From: Fadi Hanna Date: Sat, 23 Nov 2019 00:55:46 +0000 (-0800) Subject: Unifying many of the R2R and COR constants between crossgen2 and the r2rdump tools... X-Git-Tag: submit/tizen/20210909.063632~10929 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=75afc580079742b9d9fa5bbba29a79f46e7f1cc4;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Unifying many of the R2R and COR constants between crossgen2 and the r2rdump tools (#172) * Unifying many of the R2R and COR constants between crossgen2 and the r2rdump tools * Move tools/crossgen2/Common to tools/Common * Adjust paths in csproj files --- diff --git a/src/coreclr/src/tools/Common/CommandLine/CommandLineException.cs b/src/coreclr/src/tools/Common/CommandLine/CommandLineException.cs new file mode 100644 index 00000000000..e51837ca944 --- /dev/null +++ b/src/coreclr/src/tools/Common/CommandLine/CommandLineException.cs @@ -0,0 +1,16 @@ +// 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; + +namespace Internal.CommandLine +{ + internal class CommandLineException : Exception + { + public CommandLineException(string message) + : base(message) + { + } + } +} diff --git a/src/coreclr/src/tools/Common/CommandLine/CommandLineHelpers.cs b/src/coreclr/src/tools/Common/CommandLine/CommandLineHelpers.cs new file mode 100644 index 00000000000..35618e005e5 --- /dev/null +++ b/src/coreclr/src/tools/Common/CommandLine/CommandLineHelpers.cs @@ -0,0 +1,65 @@ +// 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.Collections.Generic; +using System.IO; + +namespace Internal.CommandLine +{ + // + // Helpers for command line processing + // + internal class Helpers + { + // Helper to create a collection of paths unique in their simple names. + public static void AppendExpandedPaths(Dictionary dictionary, string pattern, bool strict) + { + bool empty = true; + + string directoryName = Path.GetDirectoryName(pattern); + string searchPattern = Path.GetFileName(pattern); + + if (directoryName == "") + directoryName = "."; + + if (Directory.Exists(directoryName)) + { + foreach (string fileName in Directory.EnumerateFiles(directoryName, searchPattern)) + { + string fullFileName = Path.GetFullPath(fileName); + + string simpleName = Path.GetFileNameWithoutExtension(fileName); + + if (dictionary.ContainsKey(simpleName)) + { + if (strict) + { + throw new CommandLineException("Multiple input files matching same simple name " + + fullFileName + " " + dictionary[simpleName]); + } + } + else + { + dictionary.Add(simpleName, fullFileName); + } + + empty = false; + } + } + + if (empty) + { + if (strict) + { + throw new CommandLineException("No files matching " + pattern); + } + else + { + Console.WriteLine("Warning: No files matching " + pattern); + } + } + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/CodeGenerationFailedException.cs b/src/coreclr/src/tools/Common/Compiler/CodeGenerationFailedException.cs new file mode 100644 index 00000000000..ab4a47be400 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/CodeGenerationFailedException.cs @@ -0,0 +1,28 @@ +// 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.TypeSystem; + +namespace ILCompiler +{ + public class CodeGenerationFailedException : InternalCompilerErrorException + { + private const string MessageText = "Code generation failed for method '{0}'"; + + public MethodDesc Method { get; } + + public CodeGenerationFailedException(MethodDesc method) + : this(method, null) + { + } + + public CodeGenerationFailedException(MethodDesc method, Exception inner) + : base(String.Format(MessageText, method), inner) + { + Method = method; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/CompilationBuilder.cs b/src/coreclr/src/tools/Common/Compiler/CompilationBuilder.cs new file mode 100644 index 00000000000..7fd7ad1769f --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/CompilationBuilder.cs @@ -0,0 +1,110 @@ +// 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.Collections.Generic; + +using ILCompiler.DependencyAnalysis; +using ILCompiler.DependencyAnalysisFramework; + +using Internal.IL; + +namespace ILCompiler +{ + public abstract partial class CompilationBuilder + { + protected readonly CompilerTypeSystemContext _context; + protected readonly CompilationModuleGroup _compilationGroup; + protected readonly NameMangler _nameMangler; + + // These need to provide reasonable defaults so that the user can optionally skip + // calling the Use/Configure methods and still get something reasonable back. + protected Logger _logger = Logger.Null; + private DependencyTrackingLevel _dependencyTrackingLevel = DependencyTrackingLevel.None; + protected IEnumerable _compilationRoots = Array.Empty(); + protected OptimizationMode _optimizationMode = OptimizationMode.None; + + public CompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup compilationGroup, NameMangler nameMangler) + { + _context = context; + _compilationGroup = compilationGroup; + _nameMangler = nameMangler; + InitializePartial(); + } + + // Partial class specific initialization + partial void InitializePartial(); + + public CompilationBuilder UseLogger(Logger logger) + { + _logger = logger; + return this; + } + + public CompilationBuilder UseCompilationUnitPrefix(string prefix) + { + _nameMangler.CompilationUnitPrefix = prefix; + return this; + } + + public CompilationBuilder UseDependencyTracking(DependencyTrackingLevel trackingLevel) + { + _dependencyTrackingLevel = trackingLevel; + return this; + } + + public CompilationBuilder UseCompilationRoots(IEnumerable compilationRoots) + { + _compilationRoots = compilationRoots; + return this; + } + + public CompilationBuilder UseOptimizationMode(OptimizationMode mode) + { + _optimizationMode = mode; + return this; + } + + public abstract CompilationBuilder UseBackendOptions(IEnumerable options); + + public abstract CompilationBuilder UseILProvider(ILProvider ilProvider); + + protected abstract ILProvider GetILProvider(); + + public abstract CompilationBuilder UseJitPath(string jitPath); + + protected DependencyAnalyzerBase CreateDependencyGraph(NodeFactory factory, IComparer> comparer = null) + { + return _dependencyTrackingLevel.CreateDependencyGraph(factory, comparer); + } + + public abstract ICompilation ToCompilation(); + } + + /// + /// Represents the level of optimizations performed by the compiler. + /// + public enum OptimizationMode + { + /// + /// Do not optimize. + /// + None, + + /// + /// Minimize code space. + /// + PreferSize, + + /// + /// Generate blended code. (E.g. favor size for rarely executed code such as class constructors.) + /// + Blended, + + /// + /// Maximize execution speed. + /// + PreferSpeed, + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/CompilationModuleGroup.cs b/src/coreclr/src/tools/Common/Compiler/CompilationModuleGroup.cs new file mode 100644 index 00000000000..1feb14c46c0 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/CompilationModuleGroup.cs @@ -0,0 +1,26 @@ +// 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 Internal.TypeSystem; + +namespace ILCompiler +{ + public abstract partial class CompilationModuleGroup + { + /// + /// If true, "type" is in the set of input assemblies being compiled + /// + public abstract bool ContainsType(TypeDesc type); + /// + /// If true, "method" is in the set of input assemblies being compiled + /// + public abstract bool ContainsMethodBody(MethodDesc method, bool unboxingStub); + /// + /// Decide whether a given call may get inlined by JIT. + /// + /// Calling method the assembly code of is about to receive the callee code + /// The called method to be inlined into the caller + public virtual bool CanInline(MethodDesc callerMethod, MethodDesc calleeMethod) => true; + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/CompilerTypeSystemContext.Validation.cs b/src/coreclr/src/tools/Common/Compiler/CompilerTypeSystemContext.Validation.cs new file mode 100644 index 00000000000..50314850660 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/CompilerTypeSystemContext.Validation.cs @@ -0,0 +1,151 @@ +// 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 Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler +{ + // Validates types to the extent that is required to make sure the compilation won't fail + // in unpredictable spots. + partial class CompilerTypeSystemContext + { + /// + /// Ensures that the type can be fully loaded. The method will throw one of the type system + /// exceptions if the type is not loadable. + /// + public void EnsureLoadableType(TypeDesc type) + { + _validTypes.GetOrCreateValue(type); + } + + class ValidTypeHashTable : LockFreeReaderHashtable + { + protected override bool CompareKeyToValue(TypeDesc key, TypeDesc value) => key == value; + protected override bool CompareValueToValue(TypeDesc value1, TypeDesc value2) => value1 == value2; + protected override TypeDesc CreateValueFromKey(TypeDesc key) => EnsureLoadableTypeUncached(key); + protected override int GetKeyHashCode(TypeDesc key) => key.GetHashCode(); + protected override int GetValueHashCode(TypeDesc value) => value.GetHashCode(); + } + private readonly ValidTypeHashTable _validTypes = new ValidTypeHashTable(); + + private static TypeDesc EnsureLoadableTypeUncached(TypeDesc type) + { + if (type.IsParameterizedType) + { + // Validate parameterized types + var parameterizedType = (ParameterizedType)type; + + TypeDesc parameterType = parameterizedType.ParameterType; + + // Make sure type of the parameter is loadable. + ((CompilerTypeSystemContext)type.Context).EnsureLoadableType(parameterType); + + // Validate we're not constructing a type over a ByRef + if (parameterType.IsByRef) + { + // CLR compat note: "ldtoken int32&&" will actually fail with a message about int32&; "ldtoken int32&[]" + // will fail with a message about being unable to create an array of int32&. This is a middle ground. + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + // Validate the parameter is not an uninstantiated generic. + if (parameterType.IsGenericDefinition) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + if (parameterizedType.IsArray) + { + if (parameterType.IsFunctionPointer) + { + // Arrays of function pointers are not currently supported + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + LayoutInt elementSize = parameterType.GetElementSize(); + if (!elementSize.IsIndeterminate && elementSize.AsInt >= ushort.MaxValue) + { + // Element size over 64k can't be encoded in the GCDesc + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadValueClassTooLarge, parameterType); + } + + if (((ArrayType)parameterizedType).Rank > 32) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadRankTooLarge, type); + } + + if (parameterType.IsByRefLike) + { + // Arrays of byref-like types are not allowed + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + // It might seem reasonable to disallow array of void, but the CLR doesn't prevent that too hard. + // E.g. "newarr void" will fail, but "newarr void[]" or "ldtoken void[]" will succeed. + } + } + else if (type.IsFunctionPointer) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + else + { + // Validate classes, structs, enums, interfaces, and delegates + Debug.Assert(type.IsDefType); + + // Don't validate generic definitons + if (type.IsGenericDefinition) + { + return type; + } + + // System.__Canon or System.__UniversalCanon + if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) + { + return type; + } + + // We need to be able to load interfaces + foreach (var intf in type.RuntimeInterfaces) + { + ((CompilerTypeSystemContext)type.Context).EnsureLoadableType(intf.NormalizeInstantiation()); + } + + var defType = (DefType)type; + + // Ensure we can compute the type layout + defType.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields); + defType.ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizesAndFields); + + // Make sure instantiation length matches the expectation + if (defType.Instantiation.Length != defType.GetTypeDefinition().Instantiation.Length) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + foreach (TypeDesc typeArg in defType.Instantiation) + { + // ByRefs, pointers, function pointers, and System.Void are never valid instantiation arguments + if (typeArg.IsByRef + || typeArg.IsPointer + || typeArg.IsFunctionPointer + || typeArg.IsVoid + || typeArg.IsByRefLike) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + // TODO: validate constraints + } + + // Check the type doesn't have bogus MethodImpls or overrides and we can get the finalizer. + defType.GetFinalizer(); + } + + return type; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/CompilerTypeSystemContext.cs b/src/coreclr/src/tools/Common/Compiler/CompilerTypeSystemContext.cs new file mode 100644 index 00000000000..7463ec7cc86 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/CompilerTypeSystemContext.cs @@ -0,0 +1,353 @@ +// 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.IO; +using System.IO.MemoryMappedFiles; +using System.Diagnostics; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILCompiler +{ + public partial class CompilerTypeSystemContext : MetadataTypeSystemContext, IMetadataStringDecoderProvider + { + private readonly MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); + private readonly MetadataVirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm(); + + private MetadataStringDecoder _metadataStringDecoder; + + private class ModuleData + { + public string SimpleName; + public string FilePath; + + public EcmaModule Module; + public MemoryMappedViewAccessor MappedViewAccessor; + } + + private class ModuleHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(EcmaModule key) + { + return key.GetHashCode(); + } + protected override int GetValueHashCode(ModuleData value) + { + return value.Module.GetHashCode(); + } + protected override bool CompareKeyToValue(EcmaModule key, ModuleData value) + { + return Object.ReferenceEquals(key, value.Module); + } + protected override bool CompareValueToValue(ModuleData value1, ModuleData value2) + { + return Object.ReferenceEquals(value1.Module, value2.Module); + } + protected override ModuleData CreateValueFromKey(EcmaModule key) + { + Debug.Fail("CreateValueFromKey not supported"); + return null; + } + } + private readonly ModuleHashtable _moduleHashtable = new ModuleHashtable(); + + private class SimpleNameHashtable : LockFreeReaderHashtable + { + StringComparer _comparer = StringComparer.OrdinalIgnoreCase; + + protected override int GetKeyHashCode(string key) + { + return _comparer.GetHashCode(key); + } + protected override int GetValueHashCode(ModuleData value) + { + return _comparer.GetHashCode(value.SimpleName); + } + protected override bool CompareKeyToValue(string key, ModuleData value) + { + return _comparer.Equals(key, value.SimpleName); + } + protected override bool CompareValueToValue(ModuleData value1, ModuleData value2) + { + return _comparer.Equals(value1.SimpleName, value2.SimpleName); + } + protected override ModuleData CreateValueFromKey(string key) + { + Debug.Fail("CreateValueFromKey not supported"); + return null; + } + } + private readonly SimpleNameHashtable _simpleNameHashtable = new SimpleNameHashtable(); + + private readonly SharedGenericsMode _genericsMode; + + public IReadOnlyDictionary InputFilePaths + { + get; + set; + } + + public IReadOnlyDictionary ReferenceFilePaths + { + get; + set; + } + + public override ModuleDesc ResolveAssembly(System.Reflection.AssemblyName name, bool throwIfNotFound) + { + // TODO: catch typesystem BadImageFormatException and throw a new one that also captures the + // assembly name that caused the failure. (Along with the reason, which makes this rather annoying). + return GetModuleForSimpleName(name.Name, throwIfNotFound); + } + + public ModuleDesc GetModuleForSimpleName(string simpleName, bool throwIfNotFound = true) + { + ModuleData existing; + if (_simpleNameHashtable.TryGetValue(simpleName, out existing)) + return existing.Module; + + string filePath; + if (!InputFilePaths.TryGetValue(simpleName, out filePath)) + { + if (!ReferenceFilePaths.TryGetValue(simpleName, out filePath)) + { + // We allow the CanonTypesModule to not be an EcmaModule. + if (((IAssemblyDesc)CanonTypesModule).GetName().Name == simpleName) + return CanonTypesModule; + + // TODO: the exception is wrong for two reasons: for one, this should be assembly full name, not simple name. + // The other reason is that on CoreCLR, the exception also captures the reason. We should be passing two + // string IDs. This makes this rather annoying. + if (throwIfNotFound) + ThrowHelper.ThrowFileNotFoundException(ExceptionStringID.FileLoadErrorGeneric, simpleName); + return null; + } + } + + return AddModule(filePath, simpleName, true); + } + + public EcmaModule GetModuleFromPath(string filePath) + { + return GetOrAddModuleFromPath(filePath, true); + } + + public EcmaModule GetMetadataOnlyModuleFromPath(string filePath) + { + return GetOrAddModuleFromPath(filePath, false); + } + + private EcmaModule GetOrAddModuleFromPath(string filePath, bool useForBinding) + { + // This method is not expected to be called frequently. Linear search is acceptable. + foreach (var entry in ModuleHashtable.Enumerator.Get(_moduleHashtable)) + { + if (entry.FilePath == filePath) + return entry.Module; + } + + return AddModule(filePath, null, useForBinding); + } + + public static unsafe PEReader OpenPEFile(string filePath, out MemoryMappedViewAccessor mappedViewAccessor) + { + // System.Reflection.Metadata has heuristic that tries to save virtual address space. This heuristic does not work + // well for us since it can make IL access very slow (call to OS for each method IL query). We will map the file + // ourselves to get the desired performance characteristics reliably. + + FileStream fileStream = null; + MemoryMappedFile mappedFile = null; + MemoryMappedViewAccessor accessor = null; + try + { + // Create stream because CreateFromFile(string, ...) uses FileShare.None which is too strict + fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false); + mappedFile = MemoryMappedFile.CreateFromFile( + fileStream, null, fileStream.Length, MemoryMappedFileAccess.Read, HandleInheritability.None, true); + accessor = mappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); + + var safeBuffer = accessor.SafeMemoryMappedViewHandle; + var peReader = new PEReader((byte*)safeBuffer.DangerousGetHandle(), (int)safeBuffer.ByteLength); + + // MemoryMappedFile does not need to be kept around. MemoryMappedViewAccessor is enough. + + mappedViewAccessor = accessor; + accessor = null; + + return peReader; + } + finally + { + if (accessor != null) + accessor.Dispose(); + if (mappedFile != null) + mappedFile.Dispose(); + if (fileStream != null) + fileStream.Dispose(); + } + } + + private EcmaModule AddModule(string filePath, string expectedSimpleName, bool useForBinding) + { + MemoryMappedViewAccessor mappedViewAccessor = null; + PdbSymbolReader pdbReader = null; + try + { + PEReader peReader = OpenPEFile(filePath, out mappedViewAccessor); + pdbReader = OpenAssociatedSymbolFile(filePath, peReader); + + EcmaModule module = EcmaModule.Create(this, peReader, containingAssembly: null, pdbReader); + + MetadataReader metadataReader = module.MetadataReader; + string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); + + if (expectedSimpleName != null && !simpleName.Equals(expectedSimpleName, StringComparison.OrdinalIgnoreCase)) + throw new FileNotFoundException("Assembly name does not match filename " + filePath); + + ModuleData moduleData = new ModuleData() + { + SimpleName = simpleName, + FilePath = filePath, + Module = module, + MappedViewAccessor = mappedViewAccessor + }; + + lock (this) + { + if (useForBinding) + { + ModuleData actualModuleData = _simpleNameHashtable.AddOrGetExisting(moduleData); + if (actualModuleData != moduleData) + { + if (actualModuleData.FilePath != filePath) + throw new FileNotFoundException("Module with same simple name already exists " + filePath); + return actualModuleData.Module; + } + } + mappedViewAccessor = null; // Ownership has been transfered + pdbReader = null; // Ownership has been transferred + + _moduleHashtable.AddOrGetExisting(moduleData); + } + + return module; + } + finally + { + if (mappedViewAccessor != null) + mappedViewAccessor.Dispose(); + if (pdbReader != null) + pdbReader.Dispose(); + } + } + + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) + { + return _metadataRuntimeInterfacesAlgorithm; + } + + public override VirtualMethodAlgorithm GetVirtualMethodAlgorithmForType(TypeDesc type) + { + Debug.Assert(!type.IsArray, "Wanted to call GetClosestMetadataType?"); + + return _virtualMethodAlgorithm; + } + + protected override Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) + { + if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes) + return RuntimeDeterminedCanonicalizationAlgorithm.ConvertInstantiationToCanonForm(instantiation, kind, out changed); + + Debug.Assert(_genericsMode == SharedGenericsMode.Disabled); + changed = false; + return instantiation; + } + + protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) + { + if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes) + return RuntimeDeterminedCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind); + + Debug.Assert(_genericsMode == SharedGenericsMode.Disabled); + return typeToConvert; + } + + protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) + { + if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes) + return RuntimeDeterminedCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, ref kind); + + Debug.Assert(_genericsMode == SharedGenericsMode.Disabled); + return typeToConvert; + } + + public override bool SupportsUniversalCanon => false; + public override bool SupportsCanon => _genericsMode != SharedGenericsMode.Disabled; + + public MetadataStringDecoder GetMetadataStringDecoder() + { + if (_metadataStringDecoder == null) + _metadataStringDecoder = new CachingMetadataStringDecoder(0x10000); // TODO: Tune the size + return _metadataStringDecoder; + } + + // + // Symbols + // + + private PdbSymbolReader OpenAssociatedSymbolFile(string peFilePath, PEReader peReader) + { + // Assume that the .pdb file is next to the binary + var pdbFilename = Path.ChangeExtension(peFilePath, ".pdb"); + string searchPath = ""; + + if (!File.Exists(pdbFilename)) + { + pdbFilename = null; + + // If the file doesn't exist, try the path specified in the CodeView section of the image + foreach (DebugDirectoryEntry debugEntry in peReader.ReadDebugDirectory()) + { + if (debugEntry.Type != DebugDirectoryEntryType.CodeView) + continue; + + string candidateFileName = peReader.ReadCodeViewDebugDirectoryData(debugEntry).Path; + if (Path.IsPathRooted(candidateFileName) && File.Exists(candidateFileName)) + { + pdbFilename = candidateFileName; + searchPath = Path.GetDirectoryName(pdbFilename); + break; + } + } + + if (pdbFilename == null) + return null; + } + + // Try to open the symbol file as portable pdb first + PdbSymbolReader reader = PortablePdbSymbolReader.TryOpen(pdbFilename, GetMetadataStringDecoder()); + if (reader == null) + { + // Fallback to the diasymreader for non-portable pdbs + reader = UnmanagedPdbSymbolReader.TryOpenSymbolReaderForMetadataFile(peFilePath, searchPath); + } + + return reader; + } + } + + /// + /// Specifies the mode in which canonicalization should occur. + /// + public enum SharedGenericsMode + { + Disabled, + CanonicalReferenceTypes, + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/CoreRTNameMangler.cs b/src/coreclr/src/tools/Common/Compiler/CoreRTNameMangler.cs new file mode 100644 index 00000000000..fe5b722d723 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/CoreRTNameMangler.cs @@ -0,0 +1,641 @@ +// 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.Collections.Generic; +using System.Collections.Immutable; +using System.Security.Cryptography; +using System.Text; + +using Internal.Text; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; +using System.Diagnostics; + +namespace ILCompiler +{ + public class CoreRTNameMangler : NameMangler + { + private SHA256 _sha256; + +#if !READYTORUN + private readonly bool _mangleForCplusPlus; + + public CoreRTNameMangler(NodeMangler nodeMangler, bool mangleForCplusPlus) : base(nodeMangler) + { + _mangleForCplusPlus = mangleForCplusPlus; + } +#else + private readonly bool _mangleForCplusPlus = false; +#endif + + private string _compilationUnitPrefix; + + public override string CompilationUnitPrefix + { + set { _compilationUnitPrefix = SanitizeNameWithHash(value); } + get + { + Debug.Assert(_compilationUnitPrefix != null); + return _compilationUnitPrefix; + } + } + + // + // Turn a name into a valid C/C++ identifier + // + public override string SanitizeName(string s, bool typeName = false) + { + StringBuilder sb = null; + for (int i = 0; i < s.Length; i++) + { + char c = s[i]; + + if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) + { + if (sb != null) + sb.Append(c); + continue; + } + + if ((c >= '0') && (c <= '9')) + { + // C identifiers cannot start with a digit. Prepend underscores. + if (i == 0) + { + if (sb == null) + sb = new StringBuilder(s.Length + 2); + sb.Append("_"); + } + if (sb != null) + sb.Append(c); + continue; + } + + if (sb == null) + sb = new StringBuilder(s, 0, i, s.Length); + + // For CppCodeGen, replace "." (C# namespace separator) with "::" (C++ namespace separator) + if (typeName && c == '.' && _mangleForCplusPlus) + { + sb.Append("::"); + continue; + } + + // Everything else is replaced by underscore. + // TODO: We assume that there won't be collisions with our own or C++ built-in identifiers. + sb.Append("_"); + } + + string sanitizedName = (sb != null) ? sb.ToString() : s; + + // The character sequences denoting generic instantiations, arrays, byrefs, or pointers must be + // restricted to that use only. Replace them if they happened to be used in any identifiers in + // the compilation input. + return _mangleForCplusPlus + ? sanitizedName.Replace(EnterNameScopeSequence, "_AA_").Replace(ExitNameScopeSequence, "_VV_") + : sanitizedName; + } + + private static byte[] GetBytesFromString(string literal) + { + byte[] bytes = new byte[checked(literal.Length * 2)]; + for (int i = 0; i < literal.Length; i++) + { + int iByteBase = i * 2; + char c = literal[i]; + bytes[iByteBase] = (byte)c; + bytes[iByteBase + 1] = (byte)(c >> 8); + } + return bytes; + } + + private string SanitizeNameWithHash(string literal) + { + string mangledName = SanitizeName(literal); + + if (mangledName.Length > 30) + mangledName = mangledName.Substring(0, 30); + + if (mangledName != literal) + { + byte[] hash; + lock (this) + { + if (_sha256 == null) + { + // Use SHA256 hash here to provide a high degree of uniqueness to symbol names without requiring them to be long + // This hash function provides an exceedingly high likelihood that no two strings will be given equal symbol names + // This is not considered used for security purpose; however collisions would be highly unfortunate as they will cause compilation + // failure. + _sha256 = SHA256.Create(); + } + + hash = _sha256.ComputeHash(GetBytesFromString(literal)); + } + + mangledName += "_" + BitConverter.ToString(hash).Replace("-", ""); + } + + return mangledName; + } + + /// + /// Dictionary given a mangled name for a given + /// + private ImmutableDictionary _mangledTypeNames = ImmutableDictionary.Empty; + + /// + /// Given a set of names check if + /// is unique, if not add a numbered suffix until it becomes unique. + /// + /// Name to check for uniqueness. + /// Set of names already used. + /// A name based on that is not part of . + private string DisambiguateName(string origName, ISet set) + { + int iter = 0; + string result = origName; + while (set.Contains(result)) + { + result = string.Concat(origName, "_", (iter++).ToStringInvariant()); + } + return result; + } + + public override string GetMangledTypeName(TypeDesc type) + { + string mangledName; + if (_mangledTypeNames.TryGetValue(type, out mangledName)) + return mangledName; + + return ComputeMangledTypeName(type); + } + + private string EnterNameScopeSequence => _mangleForCplusPlus ? "_A_" : "<"; + private string ExitNameScopeSequence => _mangleForCplusPlus ? "_V_" : ">"; + private string DelimitNameScopeSequence => _mangleForCplusPlus? "_C_" : ","; + + protected string NestMangledName(string name) + { + return EnterNameScopeSequence + name + ExitNameScopeSequence; + } + + /// + /// If given is an precompute its mangled type name + /// along with all the other types from the same module as . + /// Otherwise, it is a constructed type and to the EcmaType's mangled name we add a suffix to + /// show what kind of constructed type it is (e.g. appending __Array for an array type). + /// + /// Type to mangled + /// Mangled name for . + private string ComputeMangledTypeName(TypeDesc type) + { + if (type is EcmaType) + { + EcmaType ecmaType = (EcmaType)type; + + string assemblyName = ((EcmaAssembly)ecmaType.EcmaModule).GetName().Name; + bool isSystemPrivate = assemblyName.StartsWith("System.Private."); + + // Abbreviate System.Private to S.P. This might conflict with user defined assembly names, + // but we already have a problem due to running SanitizeName without disambiguating the result + // This problem needs a better fix. + if (isSystemPrivate && !_mangleForCplusPlus) + assemblyName = "S.P." + assemblyName.Substring(15); + string prependAssemblyName = SanitizeName(assemblyName); + + var deduplicator = new HashSet(); + + // Add consistent names for all types in the module, independent on the order in which + // they are compiled + lock (this) + { + bool isSystemModule = ecmaType.Module == ecmaType.Context.SystemModule; + + if (!_mangledTypeNames.ContainsKey(type)) + { + foreach (MetadataType t in ecmaType.EcmaModule.GetAllTypes()) + { + string name = t.GetFullName(); + + // Include encapsulating type + DefType containingType = t.ContainingType; + while (containingType != null) + { + name = containingType.GetFullName() + "_" + name; + containingType = containingType.ContainingType; + } + + name = SanitizeName(name, true); + + if (_mangleForCplusPlus) + { + // Always generate a fully qualified name + name = "::" + prependAssemblyName + "::" + name; + } + else + { + name = prependAssemblyName + "_" + name; + + // If this is one of the well known types, use a shorter name + // We know this won't conflict because all the other types are + // prefixed by the assembly name. + if (isSystemModule) + { + switch (t.Category) + { + case TypeFlags.Boolean: name = "Bool"; break; + case TypeFlags.Byte: name = "UInt8"; break; + case TypeFlags.SByte: name = "Int8"; break; + case TypeFlags.UInt16: name = "UInt16"; break; + case TypeFlags.Int16: name = "Int16"; break; + case TypeFlags.UInt32: name = "UInt32"; break; + case TypeFlags.Int32: name = "Int32"; break; + case TypeFlags.UInt64: name = "UInt64"; break; + case TypeFlags.Int64: name = "Int64"; break; + case TypeFlags.Char: name = "Char"; break; + case TypeFlags.Double: name = "Double"; break; + case TypeFlags.Single: name = "Single"; break; + case TypeFlags.IntPtr: name = "IntPtr"; break; + case TypeFlags.UIntPtr: name = "UIntPtr"; break; + default: + if (t.IsObject) + name = "Object"; + else if (t.IsString) + name = "String"; + break; + } + } + } + + // Ensure that name is unique and update our tables accordingly. + name = DisambiguateName(name, deduplicator); + deduplicator.Add(name); + _mangledTypeNames = _mangledTypeNames.Add(t, name); + } + } + } + + return _mangledTypeNames[type]; + } + + string mangledName; + + switch (type.Category) + { + case TypeFlags.Array: + mangledName = "__MDArray" + + EnterNameScopeSequence + + GetMangledTypeName(((ArrayType)type).ElementType) + + DelimitNameScopeSequence + + ((ArrayType)type).Rank.ToStringInvariant() + + ExitNameScopeSequence; + break; + case TypeFlags.SzArray: + mangledName = "__Array" + NestMangledName(GetMangledTypeName(((ArrayType)type).ElementType)); + break; + case TypeFlags.ByRef: + mangledName = GetMangledTypeName(((ByRefType)type).ParameterType) + NestMangledName("ByRef"); + break; + case TypeFlags.Pointer: + mangledName = GetMangledTypeName(((PointerType)type).ParameterType) + NestMangledName("Pointer"); + break; + default: + // Case of a generic type. If `type' is a type definition we use the type name + // for mangling, otherwise we use the mangling of the type and its generic type + // parameters, e.g. A becomes A_<___B_>_ in RyuJIT compilation, or A_A___B_V_ + // in C++ compilation. + var typeDefinition = type.GetTypeDefinition(); + if (typeDefinition != type) + { + mangledName = GetMangledTypeName(typeDefinition); + + var inst = type.Instantiation; + string mangledInstantiation = ""; + for (int i = 0; i < inst.Length; i++) + { + string instArgName = GetMangledTypeName(inst[i]); + if (_mangleForCplusPlus) + instArgName = instArgName.Replace("::", "_"); + if (i > 0) + mangledInstantiation += "__"; + + mangledInstantiation += instArgName; + } + mangledName += NestMangledName(mangledInstantiation); + } + else if (type is IPrefixMangledMethod) + { + mangledName = GetPrefixMangledMethodName((IPrefixMangledMethod)type).ToString(); + } + else if (type is IPrefixMangledType) + { + mangledName = GetPrefixMangledTypeName((IPrefixMangledType)type).ToString(); + } + else + { + // This is a type definition. Since we didn't fall in the `is EcmaType` case above, + // it's likely a compiler-generated type. + mangledName = SanitizeName(((DefType)type).GetFullName(), true); + + // Always generate a fully qualified name + if (_mangleForCplusPlus) + mangledName = "::" + mangledName; + } + break; + } + + lock (this) + { + // Ensure that name is unique and update our tables accordingly. + if (!_mangledTypeNames.ContainsKey(type)) + _mangledTypeNames = _mangledTypeNames.Add(type, mangledName); + } + + return mangledName; + } + + private ImmutableDictionary _mangledMethodNames = ImmutableDictionary.Empty; + private ImmutableDictionary _unqualifiedMangledMethodNames = ImmutableDictionary.Empty; + + public override Utf8String GetMangledMethodName(MethodDesc method) + { + if (_mangleForCplusPlus) + { + return GetUnqualifiedMangledMethodName(method); + } + else + { + Utf8String utf8MangledName; + if (_mangledMethodNames.TryGetValue(method, out utf8MangledName)) + return utf8MangledName; + + Utf8StringBuilder sb = new Utf8StringBuilder(); + sb.Append(GetMangledTypeName(method.OwningType)); + sb.Append("__"); + sb.Append(GetUnqualifiedMangledMethodName(method)); + utf8MangledName = sb.ToUtf8String(); + + lock (this) + { + if (!_mangledMethodNames.ContainsKey(method)) + _mangledMethodNames = _mangledMethodNames.Add(method, utf8MangledName); + } + + return utf8MangledName; + } + } + + private Utf8String GetUnqualifiedMangledMethodName(MethodDesc method) + { + Utf8String mangledName; + if (_unqualifiedMangledMethodNames.TryGetValue(method, out mangledName)) + return mangledName; + + return ComputeUnqualifiedMangledMethodName(method); + } + + private Utf8String GetPrefixMangledTypeName(IPrefixMangledType prefixMangledType) + { + Utf8StringBuilder sb = new Utf8StringBuilder(); + sb.Append(EnterNameScopeSequence).Append(prefixMangledType.Prefix).Append(ExitNameScopeSequence); + + if (_mangleForCplusPlus) + { + string name = GetMangledTypeName(prefixMangledType.BaseType).ToString().Replace("::", "_"); + sb.Append(name); + } + else + { + sb.Append(GetMangledTypeName(prefixMangledType.BaseType)); + } + + return sb.ToUtf8String(); + } + + private Utf8String GetPrefixMangledSignatureName(IPrefixMangledSignature prefixMangledSignature) + { + Utf8StringBuilder sb = new Utf8StringBuilder(); + sb.Append(EnterNameScopeSequence).Append(prefixMangledSignature.Prefix).Append(ExitNameScopeSequence); + + var signature = prefixMangledSignature.BaseSignature; + sb.Append(signature.Flags.ToStringInvariant()); + + sb.Append(EnterNameScopeSequence); + + string sigRetTypeName = GetMangledTypeName(signature.ReturnType); + if (_mangleForCplusPlus) + sigRetTypeName = sigRetTypeName.Replace("::", "_"); + sb.Append(sigRetTypeName); + + for (int i = 0; i < signature.Length; i++) + { + sb.Append("__"); + string sigArgName = GetMangledTypeName(signature[i]); + if (_mangleForCplusPlus) + sigArgName = sigArgName.Replace("::", "_"); + sb.Append(sigArgName); + } + + sb.Append(ExitNameScopeSequence); + + return sb.ToUtf8String(); + } + + private Utf8String GetPrefixMangledMethodName(IPrefixMangledMethod prefixMangledMetod) + { + Utf8StringBuilder sb = new Utf8StringBuilder(); + sb.Append(EnterNameScopeSequence).Append(prefixMangledMetod.Prefix).Append(ExitNameScopeSequence); + + if (_mangleForCplusPlus) + { + string name = GetMangledMethodName(prefixMangledMetod.BaseMethod).ToString().Replace("::", "_"); + sb.Append(name); + } + else + { + sb.Append(GetMangledMethodName(prefixMangledMetod.BaseMethod)); + } + + return sb.ToUtf8String(); + } + + private Utf8String ComputeUnqualifiedMangledMethodName(MethodDesc method) + { + if (method is EcmaMethod) + { + var deduplicator = new HashSet(); + + // Add consistent names for all methods of the type, independent on the order in which + // they are compiled + lock (this) + { + if (!_unqualifiedMangledMethodNames.ContainsKey(method)) + { + foreach (var m in method.OwningType.GetMethods()) + { + string name = SanitizeName(m.Name); + + name = DisambiguateName(name, deduplicator); + deduplicator.Add(name); + + _unqualifiedMangledMethodNames = _unqualifiedMangledMethodNames.Add(m, name); + } + } + } + + return _unqualifiedMangledMethodNames[method]; + } + + Utf8String utf8MangledName; + + var methodDefinition = method.GetMethodDefinition(); + if (methodDefinition != method) + { + // Instantiated generic method + Utf8StringBuilder sb = new Utf8StringBuilder(); + sb.Append(GetUnqualifiedMangledMethodName(methodDefinition.GetTypicalMethodDefinition())); + + sb.Append(EnterNameScopeSequence); + + var inst = method.Instantiation; + for (int i = 0; i < inst.Length; i++) + { + string instArgName = GetMangledTypeName(inst[i]); + if (_mangleForCplusPlus) + instArgName = instArgName.Replace("::", "_"); + if (i > 0) + sb.Append("__"); + sb.Append(instArgName); + } + + sb.Append(ExitNameScopeSequence); + + utf8MangledName = sb.ToUtf8String(); + } + else + { + var typicalMethodDefinition = method.GetTypicalMethodDefinition(); + if (typicalMethodDefinition != method) + { + // Method on an instantiated type + utf8MangledName = GetUnqualifiedMangledMethodName(typicalMethodDefinition); + } + else if (method is IPrefixMangledMethod) + { + utf8MangledName = GetPrefixMangledMethodName((IPrefixMangledMethod)method); + } + else if (method is IPrefixMangledType) + { + utf8MangledName = GetPrefixMangledTypeName((IPrefixMangledType)method); + } + else if (method is IPrefixMangledSignature) + { + utf8MangledName = GetPrefixMangledSignatureName((IPrefixMangledSignature)method); + } + else + { + // Assume that Name is unique for all other methods + utf8MangledName = new Utf8String(SanitizeName(method.Name)); + } + } + + // Unless we're doing CPP mangling, there's no point in caching the unqualified + // method name. We only needed it to construct the fully qualified name. Nobody + // is going to ask for the unqualified name again. + if (_mangleForCplusPlus) + { + lock (this) + { + if (!_unqualifiedMangledMethodNames.ContainsKey(method)) + _unqualifiedMangledMethodNames = _unqualifiedMangledMethodNames.Add(method, utf8MangledName); + } + } + + return utf8MangledName; + } + + private ImmutableDictionary _mangledFieldNames = ImmutableDictionary.Empty; + + public override Utf8String GetMangledFieldName(FieldDesc field) + { + Utf8String mangledName; + if (_mangledFieldNames.TryGetValue(field, out mangledName)) + return mangledName; + + return ComputeMangledFieldName(field); + } + + private Utf8String ComputeMangledFieldName(FieldDesc field) + { + string prependTypeName = null; + if (!_mangleForCplusPlus) + prependTypeName = GetMangledTypeName(field.OwningType); + + if (field is EcmaField) + { + var deduplicator = new HashSet(); + + // Add consistent names for all fields of the type, independent on the order in which + // they are compiled + lock (this) + { + if (!_mangledFieldNames.ContainsKey(field)) + { + foreach (var f in field.OwningType.GetFields()) + { + string name = SanitizeName(f.Name); + + name = DisambiguateName(name, deduplicator); + deduplicator.Add(name); + + if (prependTypeName != null) + name = prependTypeName + "__" + name; + + _mangledFieldNames = _mangledFieldNames.Add(f, name); + } + } + } + + return _mangledFieldNames[field]; + } + + + string mangledName = SanitizeName(field.Name); + + if (prependTypeName != null) + mangledName = prependTypeName + "__" + mangledName; + + Utf8String utf8MangledName = new Utf8String(mangledName); + + lock (this) + { + if (!_mangledFieldNames.ContainsKey(field)) + _mangledFieldNames = _mangledFieldNames.Add(field, utf8MangledName); + } + + return utf8MangledName; + } + + private ImmutableDictionary _mangledStringLiterals = ImmutableDictionary.Empty; + + public override string GetMangledStringName(string literal) + { + string mangledName; + if (_mangledStringLiterals.TryGetValue(literal, out mangledName)) + return mangledName; + + mangledName = SanitizeNameWithHash(literal); + + lock (this) + { + if (!_mangledStringLiterals.ContainsKey(literal)) + _mangledStringLiterals = _mangledStringLiterals.Add(literal, mangledName); + } + + return mangledName; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs new file mode 100644 index 00000000000..4287b78b032 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs @@ -0,0 +1,122 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using System.Text; +using ILCompiler.DependencyAnalysisFramework; +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + public interface IHasStartSymbol + { + ObjectAndOffsetSymbolNode StartSymbol { get; } + } + + /// + /// Represents an array of nodes. The contents of this node will be emitted + /// by placing a starting symbol, followed by contents of nodes (optionally + /// sorted using provided comparer), followed by ending symbol. + /// + public class ArrayOfEmbeddedDataNode : EmbeddedDataContainerNode, IHasStartSymbol + where TEmbedded : EmbeddedObjectNode + { + private HashSet _nestedNodes = new HashSet(); + private List _nestedNodesList = new List(); + private IComparer _sorter; + + public ArrayOfEmbeddedDataNode(string startSymbolMangledName, string endSymbolMangledName, IComparer nodeSorter) : base(startSymbolMangledName, endSymbolMangledName) + { + _sorter = nodeSorter; + } + + public void AddEmbeddedObject(TEmbedded symbol) + { + lock (_nestedNodes) + { + if (_nestedNodes.Add(symbol)) + { + _nestedNodesList.Add(symbol); + } + symbol.ContainingNode = this; + } + } + + protected override string GetName(NodeFactory factory) => $"Region {StartSymbol.GetMangledName(factory.NameMangler)}"; + + public override ObjectNodeSection Section => ObjectNodeSection.DataSection; + public override bool IsShareable => false; + + public override bool StaticDependenciesAreComputed => true; + + protected IEnumerable NodesList => _nestedNodesList; + private TEmbedded _nextElementToEncode; + public TEmbedded NextElementToEncode => _nextElementToEncode; + + protected virtual void GetElementDataForNodes(ref ObjectDataBuilder builder, NodeFactory factory, bool relocsOnly) + { + int index = 0; + _nextElementToEncode = null; + for (int i = 0; i < _nestedNodesList.Count; i++) + { + TEmbedded node = _nestedNodesList[i]; + if ((i + 1) < _nestedNodesList.Count) + _nextElementToEncode = _nestedNodesList[i + 1]; + else + _nextElementToEncode = null; + + if (!relocsOnly) + { + node.InitializeOffsetFromBeginningOfArray(builder.CountBytes); + node.InitializeIndexFromBeginningOfArray(index++); + } + + node.EncodeData(ref builder, factory, relocsOnly); + if (node is ISymbolDefinitionNode symbolDef) + { + builder.AddSymbol(symbolDef); + } + } + } + + public override ObjectData GetData(NodeFactory factory, bool relocsOnly) + { + ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); + builder.RequireInitialPointerAlignment(); + + if (_sorter != null) + _nestedNodesList.Sort(_sorter); + + builder.AddSymbol(StartSymbol); + + GetElementDataForNodes(ref builder, factory, relocsOnly); + + EndSymbol.SetSymbolOffset(builder.CountBytes); + builder.AddSymbol(EndSymbol); + + ObjectData objData = builder.ToObjectData(); + return objData; + } + + public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) + { + return _nestedNodesList.Count == 0; + } + + protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) + { + DependencyList dependencies = new DependencyList(); + dependencies.Add(StartSymbol, "StartSymbol"); + dependencies.Add(EndSymbol, "EndSymbol"); + + return dependencies; + } + + protected internal override int Phase => (int)ObjectNodePhase.Ordered; + + public override int ClassCode => (int)ObjectNodeOrder.ArrayOfEmbeddedDataNode; + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedPointersNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedPointersNode.cs new file mode 100644 index 00000000000..ed4ce4a7281 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedPointersNode.cs @@ -0,0 +1,135 @@ +// 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.Collections.Generic; + +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + interface ISimpleEmbeddedPointerIndirectionNode + where TTarget : ISortableSymbolNode + { + TTarget Target { get; } + } + + /// + /// Represents an array of pointers to symbols. is the type + /// of node each pointer within the vector points to. + /// + public sealed class ArrayOfEmbeddedPointersNode : ArrayOfEmbeddedDataNode> + where TTarget : ISortableSymbolNode + { + private int _nextId; + private string _startSymbolMangledName; + + /// + /// Provides a callback mechanism for notification when an EmbeddedPointerIndirectionNode is marked and added to the + /// parent ArrayOfEmbeddedPointersNode's internal list + /// + public delegate void OnMarkedDelegate(EmbeddedPointerIndirectionNode embeddedObject); + + public ArrayOfEmbeddedPointersNode(string startSymbolMangledName, string endSymbolMangledName, IComparer> nodeSorter) + : base( + startSymbolMangledName, + endSymbolMangledName, + nodeSorter) + { + _startSymbolMangledName = startSymbolMangledName; + } + + public EmbeddedObjectNode NewNode(TTarget target) + { + return new SimpleEmbeddedPointerIndirectionNode(this, target); + } + + public EmbeddedObjectNode NewNodeWithSymbol(TTarget target) + { + return new EmbeddedPointerIndirectionWithSymbolNode(this, target, GetNextId()); + } + + int GetNextId() + { + return System.Threading.Interlocked.Increment(ref _nextId); + } + + protected internal override int Phase => (int)ObjectNodePhase.Ordered; + + public override int ClassCode => (int)ObjectNodeOrder.ArrayOfEmbeddedPointersNode; + + public class PointerIndirectionNodeComparer : IComparer> + { + private IComparer _innerComparer; + + public PointerIndirectionNodeComparer(IComparer innerComparer) + { + _innerComparer = innerComparer; + } + + public int Compare(EmbeddedPointerIndirectionNode x, EmbeddedPointerIndirectionNode y) + { + return _innerComparer.Compare(x.Target, y.Target); + } + } + + private class SimpleEmbeddedPointerIndirectionNode : EmbeddedPointerIndirectionNode, ISimpleEmbeddedPointerIndirectionNode + { + protected ArrayOfEmbeddedPointersNode _parentNode; + + public SimpleEmbeddedPointerIndirectionNode(ArrayOfEmbeddedPointersNode futureParent, TTarget target) + : base(target) + { + _parentNode = futureParent; + } + + protected override string GetName(NodeFactory factory) => $"Embedded pointer to {Target.GetMangledName(factory.NameMangler)}"; + + protected override void OnMarked(NodeFactory factory) + { + // We don't want the child in the parent collection unless it's necessary. + // Only when this node gets marked, the parent node becomes the actual parent. + _parentNode.AddEmbeddedObject(this); + } + + public override IEnumerable GetStaticDependencies(NodeFactory factory) + { + return new[] + { + new DependencyListEntry(Target, "reloc"), + new DependencyListEntry(_parentNode, "Pointer region") + }; + } + + public override int ClassCode => -66002498; + + public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + var otherNode = (ISimpleEmbeddedPointerIndirectionNode)other; + return comparer.Compare(Target, otherNode.Target); + } + } + + private class EmbeddedPointerIndirectionWithSymbolNode : SimpleEmbeddedPointerIndirectionNode, ISymbolDefinitionNode + { + private int _id; + + public EmbeddedPointerIndirectionWithSymbolNode(ArrayOfEmbeddedPointersNode futureParent, TTarget target, int id) + : base(futureParent, target) + { + _id = id; + } + + + int ISymbolNode.Offset => 0; + + int ISymbolDefinitionNode.Offset => OffsetFromBeginningOfArray; + + public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append(nameMangler.CompilationUnitPrefix).Append(_parentNode._startSymbolMangledName).Append("_").Append(_id.ToStringInvariant()); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs new file mode 100644 index 00000000000..e0bd6d7c5cf --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs @@ -0,0 +1,82 @@ +// 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.TypeSystem; + +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + public abstract class AssemblyStubNode : ObjectNode, ISymbolDefinitionNode + { + public AssemblyStubNode() + { + } + + /// + /// Gets a value indicating whether the stub's address is visible from managed code + /// and could be a target of a managed calli. + /// + protected virtual bool IsVisibleFromManagedCode => true; + + public override ObjectNodeSection Section => ObjectNodeSection.TextSection; + + public override bool StaticDependenciesAreComputed => true; + + public abstract void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb); + public int Offset => 0; + public override bool IsShareable => false; + + public override ObjectData GetData(NodeFactory factory, bool relocsOnly) + { + // If the address is expected to be visible from managed code, we need to align + // at the managed code boundaries to prevent the stub from being confused with + // a fat fuction pointer. Otherwise we can align tighter. + int alignment = IsVisibleFromManagedCode ? + factory.Target.MinimumFunctionAlignment : + factory.Target.MinimumCodeAlignment; + + switch (factory.Target.Architecture) + { + case TargetArchitecture.X64: + X64.X64Emitter x64Emitter = new X64.X64Emitter(factory, relocsOnly); + EmitCode(factory, ref x64Emitter, relocsOnly); + x64Emitter.Builder.RequireInitialAlignment(alignment); + x64Emitter.Builder.AddSymbol(this); + return x64Emitter.Builder.ToObjectData(); + + case TargetArchitecture.X86: + X86.X86Emitter x86Emitter = new X86.X86Emitter(factory, relocsOnly); + EmitCode(factory, ref x86Emitter, relocsOnly); + x86Emitter.Builder.RequireInitialAlignment(alignment); + x86Emitter.Builder.AddSymbol(this); + return x86Emitter.Builder.ToObjectData(); + + case TargetArchitecture.ARM: + ARM.ARMEmitter armEmitter = new ARM.ARMEmitter(factory, relocsOnly); + EmitCode(factory, ref armEmitter, relocsOnly); + armEmitter.Builder.RequireInitialAlignment(alignment); + armEmitter.Builder.AddSymbol(this); + return armEmitter.Builder.ToObjectData(); + + case TargetArchitecture.ARM64: + ARM64.ARM64Emitter arm64Emitter = new ARM64.ARM64Emitter(factory, relocsOnly); + EmitCode(factory, ref arm64Emitter, relocsOnly); + arm64Emitter.Builder.RequireInitialAlignment(alignment); + arm64Emitter.Builder.AddSymbol(this); + return arm64Emitter.Builder.ToObjectData(); + + default: + throw new NotImplementedException(); + } + } + + protected abstract void EmitCode(NodeFactory factory, ref X64.X64Emitter instructionEncoder, bool relocsOnly); + protected abstract void EmitCode(NodeFactory factory, ref X86.X86Emitter instructionEncoder, bool relocsOnly); + protected abstract void EmitCode(NodeFactory factory, ref ARM.ARMEmitter instructionEncoder, bool relocsOnly); + protected abstract void EmitCode(NodeFactory factory, ref ARM64.ARM64Emitter instructionEncoder, bool relocsOnly); + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/BlobNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/BlobNode.cs new file mode 100644 index 00000000000..083de9bded8 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/BlobNode.cs @@ -0,0 +1,53 @@ +// 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.Text; +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + public class BlobNode : ObjectNode, ISymbolDefinitionNode + { + private Utf8String _name; + private ObjectNodeSection _section; + private byte[] _data; + private int _alignment; + + public BlobNode(Utf8String name, ObjectNodeSection section, byte[] data, int alignment) + { + _name = name; + _section = section; + _data = data; + _alignment = alignment; + } + + public override ObjectNodeSection Section => _section; + public override bool StaticDependenciesAreComputed => true; + + public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append(_name); + } + public int Offset => 0; + public override bool IsShareable => true; + + public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) + { + return new ObjectData(_data, Array.Empty(), _alignment, new ISymbolDefinitionNode[] { this }); + } + + protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); + +#if !SUPPORT_JIT + public override int ClassCode => -470351029; + + public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + return _name.CompareTo(((BlobNode)other)._name); + } +#endif + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/CompilerComparer.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/CompilerComparer.cs new file mode 100644 index 00000000000..250b327077e --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/CompilerComparer.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. + +using System; +using System.Diagnostics; +using System.Collections.Generic; + +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + public class CompilerComparer : TypeSystemComparer, IComparer + { + public int Compare(ISortableNode x, ISortableNode y) + { + if (x == y) + { + return 0; + } + + int codeX = x.ClassCode; + int codeY = y.ClassCode; + if (codeX == codeY) + { + Debug.Assert(x.GetType() == y.GetType()); + + int result = x.CompareToImpl(y, this); + + // We did a reference equality check above so an "Equal" result is not expected + Debug.Assert(result != 0); + + return result; + } + else + { + Debug.Assert(x.GetType() != y.GetType()); + return codeY > codeX ? -1 : 1; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedDataContainerNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedDataContainerNode.cs new file mode 100644 index 00000000000..0cffffac19b --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedDataContainerNode.cs @@ -0,0 +1,36 @@ +// 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 Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// Represents a node that contains a set of embedded objects. The main function is + /// to serve as a base class, providing symbol name boundaries and node ordering. + /// + public abstract class EmbeddedDataContainerNode : ObjectNode + { + private ObjectAndOffsetSymbolNode _startSymbol; + private ObjectAndOffsetSymbolNode _endSymbol; + private string _startSymbolMangledName; + + public ObjectAndOffsetSymbolNode StartSymbol => _startSymbol; + public ObjectAndOffsetSymbolNode EndSymbol => _endSymbol; + + protected EmbeddedDataContainerNode(string startSymbolMangledName, string endSymbolMangledName) + { + _startSymbolMangledName = startSymbolMangledName; + _startSymbol = new ObjectAndOffsetSymbolNode(this, 0, startSymbolMangledName, true); + _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, endSymbolMangledName, true); + } + + public override int ClassCode => -1410622237; + + public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + return _startSymbolMangledName.CompareTo(((EmbeddedDataContainerNode)other)._startSymbolMangledName); + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedObjectNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedObjectNode.cs new file mode 100644 index 00000000000..0db837e0c9d --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedObjectNode.cs @@ -0,0 +1,70 @@ +// 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.Collections.Generic; + +using ILCompiler.DependencyAnalysisFramework; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler.DependencyAnalysis +{ + public abstract class EmbeddedObjectNode : SortableDependencyNode + { + private const int InvalidOffset = int.MinValue; + + private int _offset; + private int _index; + + public IHasStartSymbol ContainingNode { get; set; } + + public EmbeddedObjectNode() + { + _offset = InvalidOffset; + _index = InvalidOffset; + } + + public int OffsetFromBeginningOfArray + { + get + { + Debug.Assert(_offset != InvalidOffset); + return _offset; + } + } + + public int IndexFromBeginningOfArray + { + get + { + Debug.Assert(_index != InvalidOffset); + return _index; + } + } + + public void InitializeOffsetFromBeginningOfArray(int offset) + { + Debug.Assert(_offset == InvalidOffset || _offset == offset); + _offset = offset; + } + + public void InitializeIndexFromBeginningOfArray(int index) + { + Debug.Assert(_index == InvalidOffset || _index == index); + _index = index; + } + + public virtual bool IsShareable => false; + public virtual bool RepresentsIndirectionCell => false; + + public override bool InterestingForDynamicDependencyAnalysis => false; + public override bool HasDynamicDependencies => false; + public override bool HasConditionalStaticDependencies => false; + + public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; + + public abstract void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly); + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs new file mode 100644 index 00000000000..5488801a39f --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs @@ -0,0 +1,52 @@ +// 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.Collections.Generic; + +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// An whose sole value is a pointer to a different . + /// represents the node type this pointer points to. + /// + public abstract class EmbeddedPointerIndirectionNode : EmbeddedObjectNode, ISortableSymbolNode + where TTarget : ISortableSymbolNode + { + private TTarget _targetNode; + + /// + /// Target symbol this node points to. + /// + public TTarget Target => _targetNode; + + protected internal EmbeddedPointerIndirectionNode(TTarget target) + { + _targetNode = target; + } + + public override bool StaticDependenciesAreComputed => true; + + public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly) + { + dataBuilder.RequireInitialPointerAlignment(); + dataBuilder.EmitPointerReloc(Target); + } + + // At minimum, Target needs to be reported as a static dependency by inheritors. + public abstract override IEnumerable GetStaticDependencies(NodeFactory factory); + + int ISymbolNode.Offset => 0; + + public virtual void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append("_embedded_ptr_"); + Target.AppendMangledName(nameMangler, sb); + } + + public override int ClassCode => -2055384490; + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/IMethodBodyNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/IMethodBodyNode.cs new file mode 100644 index 00000000000..b862f59b49f --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/IMethodBodyNode.cs @@ -0,0 +1,13 @@ +// 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 ILCompiler.DependencyAnalysis +{ + /// + /// Marker interface that identifies the node representing a compiled method body. + /// + public interface IMethodBodyNode : IMethodNode + { + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/IMethodNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/IMethodNode.cs new file mode 100644 index 00000000000..393ee4adf54 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/IMethodNode.cs @@ -0,0 +1,16 @@ +// 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 Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// A dependency analysis node that represents a method. + /// + public interface IMethodNode : ISortableSymbolNode + { + MethodDesc Method { get; } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs new file mode 100644 index 00000000000..c1b293b020e --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs @@ -0,0 +1,76 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis +{ + [Flags] + public enum FrameInfoFlags + { + Handler = 0x01, + Filter = 0x02, + + HasEHInfo = 0x04, + ReversePInvoke = 0x08, + HasAssociatedData = 0x10, + } + + public struct FrameInfo + { + public readonly FrameInfoFlags Flags; + public readonly int StartOffset; + public readonly int EndOffset; + public readonly byte[] BlobData; + + public FrameInfo(FrameInfoFlags flags, int startOffset, int endOffset, byte[] blobData) + { + Flags = flags; + StartOffset = startOffset; + EndOffset = endOffset; + BlobData = blobData; + } + } + + public struct DebugEHClauseInfo + { + public uint TryOffset; + public uint TryLength; + public uint HandlerOffset; + public uint HandlerLength; + + public DebugEHClauseInfo(uint tryOffset, uint tryLength, uint handlerOffset, uint handlerLength) + { + TryOffset = tryOffset; + TryLength = tryLength; + HandlerOffset = handlerOffset; + HandlerLength = handlerLength; + } + } + + public interface INodeWithCodeInfo + { + FrameInfo[] FrameInfos + { + get; + } + + byte[] GCInfo + { + get; + } + + DebugEHClauseInfo[] DebugEHClauseInfos + { + get; + } + + ObjectNode.ObjectData EHInfo + { + get; + } + + ISymbolNode GetAssociatedDataNode(NodeFactory factory); + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/INodeWithRuntimeDeterminedDependencies.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/INodeWithRuntimeDeterminedDependencies.cs new file mode 100644 index 00000000000..9969bba84a9 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/INodeWithRuntimeDeterminedDependencies.cs @@ -0,0 +1,24 @@ +// 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.Collections.Generic; + +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + using DependencyListEntry = DependencyAnalysisFramework.DependencyNodeCore.DependencyListEntry; + + /// + /// Represents a node whose dependencies are runtime determined (they depend on the generic context) + /// and which provides means to compute concrete dependencies when given the generic context. + /// + public interface INodeWithRuntimeDeterminedDependencies + { + /// + /// Instantiates runtime determined dependencies of this node using the supplied generic context. + /// + IEnumerable InstantiateDependencies(NodeFactory factory, Instantiation typeInstantiation, Instantiation methodInstantiation); + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ISortableNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ISortableNode.cs new file mode 100644 index 00000000000..ac62439b072 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ISortableNode.cs @@ -0,0 +1,23 @@ +// 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 ILCompiler.DependencyAnalysis +{ + public interface ISortableNode + { +#if !SUPPORT_JIT + /// + /// Gets an identifier that is the same for all instances of this + /// descendant, but different from the of any other descendant. + /// + /// + /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". + /// If two manage to conflict (which is pretty unlikely), just make a new one... + /// + int ClassCode { get; } + + int CompareToImpl(ISortableNode other, CompilerComparer comparer); +#endif + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ISymbolNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ISymbolNode.cs new file mode 100644 index 00000000000..feca8b45e2f --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ISymbolNode.cs @@ -0,0 +1,97 @@ +// 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 ILCompiler.DependencyAnalysisFramework; +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// Represents a reference to a symbol. The reference can potentially be offset by a value. + /// + public interface ISymbolNode : IDependencyNode + { + /// + /// Appends the mangled name of the symbol to the string builder provided. + /// + void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb); + + /// + /// Gets the offset (delta) from the symbol this references. + /// + int Offset { get; } + + /// + /// Set the return value of this property to true to indicate that this symbol + /// is an indirection cell to data that is needed, not the actual data itself. + /// Most commonly affects the code generation which accesses symbols such + /// Types which may require an indirection to access or not. + /// + bool RepresentsIndirectionCell { get; } + } + + /// + /// Represents a symbol backed by a different symbol for object emission purposes. + /// + public interface ISymbolNodeWithLinkage : ISymbolNode + { + /// + /// Return a node that is used for linkage + /// + ISymbolNode NodeForLinkage(NodeFactory factory); + } + + public interface ISortableSymbolNode : ISymbolNode, ISortableNode + { + } + + + /// + /// Represents a definition of a symbol within an . The symbol will be defined + /// at the specified offset from the beginning of the that reports this as one of + /// the symbols it defines. + /// + public interface ISymbolDefinitionNode : ISymbolNode + { + /// + /// Gets the offset (delta) from the beginning of the where this symbol should + /// be defined. Note this is different from , which is the offset to be + /// used when referencing the symbol. + /// + /// + /// Most node types will want to implement both and + /// to return 0. The name was chosen to make this convenient. If an object node implements this interface, + /// it will pretty much always want to either implement both as returning 0, or *one of them* to return + /// a non-zero value. + /// Some examples: an EEType node defines the symbol of the EEType in the middle of the object node, + /// since EETypes are prefixed by a GCDesc structure (that is not considered the beginning of the EEType). + /// This means that will return a non-zero value. When referencing the EEType by its + /// symbol, the GCDesc was already accounted for when the symbol was defined, so we want the + /// to be zero. + /// + new int Offset { get; } + } + + public static class ISymbolNodeExtensions + { + [ThreadStatic] + static Utf8StringBuilder s_cachedUtf8StringBuilder; + + public static string GetMangledName(this ISymbolNode symbolNode, NameMangler nameMangler) + { + Utf8StringBuilder sb = s_cachedUtf8StringBuilder; + if (sb == null) + sb = new Utf8StringBuilder(); + + symbolNode.AppendMangledName(nameMangler, sb); + string ret = sb.ToString(); + + sb.Clear(); + s_cachedUtf8StringBuilder = sb; + + return ret; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectAndOffsetSymbolNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectAndOffsetSymbolNode.cs new file mode 100644 index 00000000000..fb6652ff359 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectAndOffsetSymbolNode.cs @@ -0,0 +1,61 @@ +// 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.Collections.Generic; + +using ILCompiler.DependencyAnalysisFramework; + +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + public class ObjectAndOffsetSymbolNode : DependencyNodeCore, ISymbolDefinitionNode + { + private ObjectNode _object; + private int _offset; + private Utf8String _name; + private bool _includeCompilationUnitPrefix; + + public ObjectAndOffsetSymbolNode(ObjectNode obj, int offset, Utf8String name, bool includeCompilationUnitPrefix) + { + _object = obj; + _offset = offset; + _name = name; + _includeCompilationUnitPrefix = includeCompilationUnitPrefix; + } + + protected override string GetName(NodeFactory factory) => $"Symbol {_name.ToString()} at offset {_offset.ToStringInvariant()}"; + + public override bool HasConditionalStaticDependencies => false; + public override bool HasDynamicDependencies => false; + public override bool InterestingForDynamicDependencyAnalysis => false; + public override bool StaticDependenciesAreComputed => true; + + public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + if (_includeCompilationUnitPrefix) + sb.Append(nameMangler.CompilationUnitPrefix); + sb.Append(_name); + } + + int ISymbolNode.Offset => 0; + int ISymbolDefinitionNode.Offset => _offset; + public bool RepresentsIndirectionCell => false; + + public void SetSymbolOffset(int offset) + { + _offset = offset; + } + + public ObjectNode Target => _object; + + public override IEnumerable GetStaticDependencies(NodeFactory factory) + { + return new DependencyListEntry[] { new DependencyListEntry(_object, "ObjectAndOffsetDependency") }; + } + + public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs new file mode 100644 index 00000000000..3af6f173921 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs @@ -0,0 +1,349 @@ +// 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.Collections.Generic; +using Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler.DependencyAnalysis +{ + public struct ObjectDataBuilder +#if !READYTORUN + : Internal.Runtime.ITargetBinaryWriter +#endif + { + public ObjectDataBuilder(NodeFactory factory, bool relocsOnly) : this(factory.Target, relocsOnly) + { + } + + public ObjectDataBuilder(TargetDetails target, bool relocsOnly) + { + _target = target; + _data = new ArrayBuilder(); + _relocs = new ArrayBuilder(); + Alignment = 1; + _definedSymbols = new ArrayBuilder(); +#if DEBUG + _numReservations = 0; + _checkAllSymbolDependenciesMustBeMarked = !relocsOnly; +#endif + } + + private TargetDetails _target; + private ArrayBuilder _relocs; + private ArrayBuilder _data; + public int Alignment { get; private set; } + private ArrayBuilder _definedSymbols; + +#if DEBUG + private int _numReservations; + private bool _checkAllSymbolDependenciesMustBeMarked; +#endif + + public int CountBytes + { + get + { + return _data.Count; + } + } + + public int TargetPointerSize + { + get + { + return _target.PointerSize; + } + } + + /// + /// Raise the alignment requirement of this object to . This has no effect + /// if the alignment requirement is already larger than . + /// + public void RequireInitialAlignment(int align) + { + Alignment = Math.Max(align, Alignment); + } + + /// + /// Raise the alignment requirement of this object to the target pointer size. This has no effect + /// if the alignment requirement is already larger than a pointer size. + /// + public void RequireInitialPointerAlignment() + { + RequireInitialAlignment(_target.PointerSize); + } + + public void EmitByte(byte emit) + { + _data.Add(emit); + } + + public void EmitShort(short emit) + { + EmitByte((byte)(emit & 0xFF)); + EmitByte((byte)((emit >> 8) & 0xFF)); + } + + public void EmitUShort(ushort emit) + { + EmitByte((byte)(emit & 0xFF)); + EmitByte((byte)((emit >> 8) & 0xFF)); + } + + public void EmitInt(int emit) + { + EmitByte((byte)(emit & 0xFF)); + EmitByte((byte)((emit >> 8) & 0xFF)); + EmitByte((byte)((emit >> 16) & 0xFF)); + EmitByte((byte)((emit >> 24) & 0xFF)); + } + + public void EmitUInt(uint emit) + { + EmitByte((byte)(emit & 0xFF)); + EmitByte((byte)((emit >> 8) & 0xFF)); + EmitByte((byte)((emit >> 16) & 0xFF)); + EmitByte((byte)((emit >> 24) & 0xFF)); + } + + public void EmitLong(long emit) + { + EmitByte((byte)(emit & 0xFF)); + EmitByte((byte)((emit >> 8) & 0xFF)); + EmitByte((byte)((emit >> 16) & 0xFF)); + EmitByte((byte)((emit >> 24) & 0xFF)); + EmitByte((byte)((emit >> 32) & 0xFF)); + EmitByte((byte)((emit >> 40) & 0xFF)); + EmitByte((byte)((emit >> 48) & 0xFF)); + EmitByte((byte)((emit >> 56) & 0xFF)); + } + + public void EmitNaturalInt(int emit) + { + if (_target.PointerSize == 8) + { + EmitLong(emit); + } + else + { + Debug.Assert(_target.PointerSize == 4); + EmitInt(emit); + } + } + + public void EmitHalfNaturalInt(short emit) + { + if (_target.PointerSize == 8) + { + EmitInt(emit); + } + else + { + Debug.Assert(_target.PointerSize == 4); + EmitShort(emit); + } + } + + public void EmitCompressedUInt(uint emit) + { + if (emit < 128) + { + EmitByte((byte)(emit * 2 + 0)); + } + else if (emit < 128 * 128) + { + EmitByte((byte)(emit * 4 + 1)); + EmitByte((byte)(emit >> 6)); + } + else if (emit < 128 * 128 * 128) + { + EmitByte((byte)(emit * 8 + 3)); + EmitByte((byte)(emit >> 5)); + EmitByte((byte)(emit >> 13)); + } + else if (emit < 128 * 128 * 128 * 128) + { + EmitByte((byte)(emit * 16 + 7)); + EmitByte((byte)(emit >> 4)); + EmitByte((byte)(emit >> 12)); + EmitByte((byte)(emit >> 20)); + } + else + { + EmitByte((byte)15); + EmitInt((int)emit); + } + } + + public void EmitBytes(byte[] bytes) + { + _data.Append(bytes); + } + + public void EmitBytes(byte[] bytes, int offset, int length) + { + _data.Append(bytes, offset, length); + } + + internal void EmitBytes(ArrayBuilder bytes) + { + _data.Append(bytes); + } + + public void EmitZeroPointer() + { + _data.ZeroExtend(_target.PointerSize); + } + + public void EmitZeros(int numBytes) + { + _data.ZeroExtend(numBytes); + } + + private Reservation GetReservationTicket(int size) + { +#if DEBUG + _numReservations++; +#endif + Reservation ticket = (Reservation)_data.Count; + _data.ZeroExtend(size); + return ticket; + } + + private int ReturnReservationTicket(Reservation reservation) + { +#if DEBUG + Debug.Assert(_numReservations > 0); + _numReservations--; +#endif + return (int)reservation; + } + + public Reservation ReserveByte() + { + return GetReservationTicket(1); + } + + public void EmitByte(Reservation reservation, byte emit) + { + int offset = ReturnReservationTicket(reservation); + _data[offset] = emit; + } + + public Reservation ReserveShort() + { + return GetReservationTicket(2); + } + + public void EmitShort(Reservation reservation, short emit) + { + int offset = ReturnReservationTicket(reservation); + _data[offset] = (byte)(emit & 0xFF); + _data[offset + 1] = (byte)((emit >> 8) & 0xFF); + } + + public Reservation ReserveInt() + { + return GetReservationTicket(4); + } + + public void EmitInt(Reservation reservation, int emit) + { + int offset = ReturnReservationTicket(reservation); + _data[offset] = (byte)(emit & 0xFF); + _data[offset + 1] = (byte)((emit >> 8) & 0xFF); + _data[offset + 2] = (byte)((emit >> 16) & 0xFF); + _data[offset + 3] = (byte)((emit >> 24) & 0xFF); + } + + public void EmitUInt(Reservation reservation, uint emit) + { + int offset = ReturnReservationTicket(reservation); + _data[offset] = (byte)(emit & 0xFF); + _data[offset + 1] = (byte)((emit >> 8) & 0xFF); + _data[offset + 2] = (byte)((emit >> 16) & 0xFF); + _data[offset + 3] = (byte)((emit >> 24) & 0xFF); + } + + public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0) + { +#if DEBUG + if (_checkAllSymbolDependenciesMustBeMarked) + { + var node = symbol as ILCompiler.DependencyAnalysisFramework.DependencyNodeCore; + if (node != null) + Debug.Assert(node.Marked); + } +#endif + + _relocs.Add(new Relocation(relocType, _data.Count, symbol)); + + // And add space for the reloc + switch (relocType) + { + case RelocType.IMAGE_REL_BASED_REL32: + case RelocType.IMAGE_REL_BASED_RELPTR32: + case RelocType.IMAGE_REL_BASED_ABSOLUTE: + case RelocType.IMAGE_REL_BASED_HIGHLOW: + case RelocType.IMAGE_REL_SECREL: + case RelocType.IMAGE_REL_BASED_ADDR32NB: + case RelocType.IMAGE_REL_SYMBOL_SIZE: + EmitInt(delta); + break; + case RelocType.IMAGE_REL_BASED_DIR64: + EmitLong(delta); + break; + case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: + case RelocType.IMAGE_REL_BASED_ARM64_BRANCH26: + case RelocType.IMAGE_REL_BASED_THUMB_MOV32: + case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21: + case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L: + // Do not vacate space for this kind of relocation, because + // the space is embedded in the instruction. + break; + default: + throw new NotImplementedException(); + } + } + + public void EmitPointerReloc(ISymbolNode symbol, int delta = 0) + { + EmitReloc(symbol, (_target.PointerSize == 8) ? RelocType.IMAGE_REL_BASED_DIR64 : RelocType.IMAGE_REL_BASED_HIGHLOW, delta); + } + + public ObjectNode.ObjectData ToObjectData() + { +#if DEBUG + Debug.Assert(_numReservations == 0); +#endif + + ObjectNode.ObjectData returnData = new ObjectNode.ObjectData(_data.ToArray(), + _relocs.ToArray(), + Alignment, + _definedSymbols.ToArray()); + + return returnData; + } + + public enum Reservation { } + + public void AddSymbol(ISymbolDefinitionNode node) + { + _definedSymbols.Add(node); + } + + public void PadAlignment(int align) + { + Debug.Assert((align == 2) || (align == 4) || (align == 8) || (align == 16)); + int misalignment = _data.Count & (align - 1); + if (misalignment != 0) + { + EmitZeros(align - misalignment); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs new file mode 100644 index 00000000000..21490cadc31 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs @@ -0,0 +1,88 @@ +// 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.Collections.Generic; + +using ILCompiler.DependencyAnalysisFramework; +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + public abstract partial class ObjectNode : SortableDependencyNode + { + public class ObjectData + { + public ObjectData(byte[] data, Relocation[] relocs, int alignment, ISymbolDefinitionNode[] definedSymbols) + { + Data = data; + Relocs = relocs; + Alignment = alignment; + DefinedSymbols = definedSymbols; + } + + public readonly Relocation[] Relocs; + public readonly byte[] Data; + public readonly int Alignment; + public readonly ISymbolDefinitionNode[] DefinedSymbols; + } + + public virtual bool RepresentsIndirectionCell => false; + + public abstract ObjectData GetData(NodeFactory factory, bool relocsOnly = false); + + public abstract ObjectNodeSection Section { get; } + + /// + /// Should identical symbols emitted into separate object files be Comdat folded when linked together? + /// + public abstract bool IsShareable { get; } + + /// + /// Override this function to have a node which should be skipped when emitting + /// to the object file. (For instance, if there are two nodes describing the same + /// data structure, one of those nodes should return true here.) + /// + /// + /// + public virtual bool ShouldSkipEmittingObjectNode(NodeFactory factory) + { + return false; + } + + public override bool HasConditionalStaticDependencies => false; + public override bool HasDynamicDependencies => false; + public override bool InterestingForDynamicDependencyAnalysis => false; + + public sealed override IEnumerable GetStaticDependencies(NodeFactory factory) + { + DependencyList dependencies = ComputeNonRelocationBasedDependencies(factory); + Relocation[] relocs = GetData(factory, true).Relocs; + + if (relocs != null) + { + if (dependencies == null) + dependencies = new DependencyList(); + + foreach (Relocation reloc in relocs) + { + dependencies.Add(reloc.Target, "reloc"); + } + } + + if (dependencies == null) + return Array.Empty(); + else + return dependencies; + } + + protected virtual DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) + { + return null; + } + + public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs new file mode 100644 index 00000000000..98829e5f30c --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs @@ -0,0 +1,57 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis +{ + public enum SectionType + { + ReadOnly, + Writeable, + Executable + } + + /// + /// Specifies the object file section a node will be placed in; ie "text" or "data" + /// + public class ObjectNodeSection + { + public string Name { get; } + public SectionType Type { get; } + public string ComdatName { get; } + + public ObjectNodeSection(string name, SectionType type, string comdatName) + { + Name = name; + Type = type; + ComdatName = comdatName; + } + + public ObjectNodeSection(string name, SectionType type) : this(name, type, null) + { } + + /// + /// Returns true if the section is a standard one (defined as text, data, or rdata currently) + /// + public bool IsStandardSection + { + get + { + return this == DataSection || this == ReadOnlyDataSection || this == FoldableReadOnlyDataSection || this == TextSection || this == XDataSection; + } + } + + public static readonly ObjectNodeSection XDataSection = new ObjectNodeSection("xdata", SectionType.ReadOnly); + public static readonly ObjectNodeSection DataSection = new ObjectNodeSection("data", SectionType.Writeable); + public static readonly ObjectNodeSection ReadOnlyDataSection = new ObjectNodeSection("rdata", SectionType.ReadOnly); + public static readonly ObjectNodeSection FoldableReadOnlyDataSection = new ObjectNodeSection("rdata$F", SectionType.ReadOnly); + public static readonly ObjectNodeSection TextSection = new ObjectNodeSection("text", SectionType.Executable); + public static readonly ObjectNodeSection TLSSection = new ObjectNodeSection("TLS", SectionType.Writeable); + public static readonly ObjectNodeSection ManagedCodeWindowsContentSection = new ObjectNodeSection(".managedcode$I", SectionType.Executable); + public static readonly ObjectNodeSection FoldableManagedCodeWindowsContentSection = new ObjectNodeSection(".managedcode$I", SectionType.Executable); + public static readonly ObjectNodeSection ManagedCodeUnixContentSection = new ObjectNodeSection("__managedcode", SectionType.Executable); + public static readonly ObjectNodeSection FoldableManagedCodeUnixContentSection = new ObjectNodeSection("__managedcode", SectionType.Executable); + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs new file mode 100644 index 00000000000..f102131263f --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -0,0 +1,232 @@ +// 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 ILCompiler.DependencyAnalysis +{ + public enum RelocType + { + IMAGE_REL_BASED_ABSOLUTE = 0x00, // No relocation required + IMAGE_REL_BASED_ADDR32NB = 0x02, // The 32-bit address without an image base (RVA) + IMAGE_REL_BASED_HIGHLOW = 0x03, // 32 bit address base + IMAGE_REL_BASED_THUMB_MOV32 = 0x07, // Thumb2: based MOVW/MOVT + IMAGE_REL_BASED_DIR64 = 0x0A, // 64 bit address base + IMAGE_REL_BASED_REL32 = 0x10, // 32-bit relative address from byte following reloc + IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, // Thumb2: based B, BL + IMAGE_REL_BASED_ARM64_BRANCH26 = 0x14, // Arm64: B, BL + IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc + // This is a special NGEN-specific relocation type + // for relative pointer (used to make NGen relocation + // section smaller) + IMAGE_REL_SECREL = 0x80, // 32 bit offset from base of section containing target + + IMAGE_REL_BASED_ARM64_PAGEBASE_REL21 = 0x81, // ADRP + IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A = 0x82, // ADD/ADDS (immediate) with zero shift, for page offset + IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L = 0x83, // LDR (indexed, unsigned immediate), for page offset + + // + // Relocations for R2R image production + // + IMAGE_REL_SYMBOL_SIZE = 0x1000, // The size of data in the image represented by the target symbol node + } + + public struct Relocation + { + public readonly RelocType RelocType; + public readonly int Offset; + public readonly ISymbolNode Target; + + //***************************************************************************** + // Extract the 16-bit immediate from ARM Thumb2 Instruction (format T2_N) + //***************************************************************************** + private static unsafe ushort GetThumb2Imm16(ushort* p) + { + uint Opcode0 = (uint)p[0]; + uint Opcode1 = (uint)p[1]; + uint Result = + ((Opcode0 << 12) & 0xf000) | + ((Opcode0 << 1) & 0x0800) | + ((Opcode1 >> 4) & 0x0700) | + ((Opcode1 >> 0) & 0x00ff); + return (ushort)Result; + } + + //***************************************************************************** + // Deposit the 16-bit immediate into ARM Thumb2 Instruction (format T2_N) + //***************************************************************************** + private static unsafe void PutThumb2Imm16(ushort* p, ushort imm16) + { + uint Opcode0 = (uint)p[0]; + uint Opcode1 = (uint)p[1]; + int val0 = (0xf000 >> 12); + int val1 = (0x0800 >> 1); + Opcode0 &= ~((uint)val0 | (uint)val1); + int val3 = (0x0700 << 4); + Opcode1 &= ~((uint)val3 | (0x00ff << 0)); + Opcode0 |= ((uint)imm16 & 0xf000) >> 12; + Opcode0 |= ((uint)imm16 & 0x0800) >> 1; + Opcode1 |= ((uint)imm16 & 0x0700) << 4; + Opcode1 |= ((uint)imm16 & 0x00ff) << 0; + p[0] = (ushort)Opcode0; + p[1] = (ushort)Opcode1; + } + + //***************************************************************************** + // Extract the 32-bit immediate from movw/movt sequence + //***************************************************************************** + private static unsafe int GetThumb2Mov32(ushort* p) + { + // Make sure we are decoding movw/movt sequence + ushort Opcode0 = *(p + 0); + ushort Opcode1 = *(p + 2); + Debug.Assert(((uint)Opcode0 & 0xFBF0) == 0xF240); + Debug.Assert(((uint)Opcode1 & 0xFBF0) == 0xF2C0); + + return (int)GetThumb2Imm16(p) + ((int)(GetThumb2Imm16(p + 2) << 16)); + } + + //***************************************************************************** + // Deposit the 32-bit immediate into movw/movt Thumb2 sequence + //***************************************************************************** + private static unsafe void PutThumb2Mov32(ushort* p, uint imm32) + { + // Make sure we are decoding movw/movt sequence + ushort Opcode0 = *(p + 0); + ushort Opcode1 = *(p + 2); + Debug.Assert(((uint)Opcode0 & 0xFBF0) == 0xF240); + Debug.Assert(((uint)Opcode1 & 0xFBF0) == 0xF2C0); + + ushort imm16 = (ushort)(imm32 & 0xffff); + PutThumb2Imm16(p, imm16); + imm16 = (ushort)(imm32 >> 16); + PutThumb2Imm16(p + 2, imm16); + + Debug.Assert((uint)GetThumb2Mov32(p) == imm32); + } + + //***************************************************************************** + // Extract the 24-bit rel offset from bl instruction + //***************************************************************************** + private static unsafe int GetThumb2BlRel24(ushort* p) + { + uint Opcode0 = (uint)p[0]; + uint Opcode1 = (uint)p[1]; + + uint S = Opcode0 >> 10; + uint J2 = Opcode1 >> 11; + uint J1 = Opcode1 >> 13; + + uint ret = + ((S << 24) & 0x1000000) | + (((J1 ^ S ^ 1) << 23) & 0x0800000) | + (((J2 ^ S ^ 1) << 22) & 0x0400000) | + ((Opcode0 << 12) & 0x03FF000) | + ((Opcode1 << 1) & 0x0000FFE); + + // Sign-extend and return + return (int)((ret << 7) >> 7); + } + + //***************************************************************************** + // Returns whether the offset fits into bl instruction + //***************************************************************************** + private static bool FitsInThumb2BlRel24(uint imm24) + { + return ((imm24 << 7) >> 7) == imm24; + } + + //***************************************************************************** + // Deposit the 24-bit rel offset into bl instruction + //***************************************************************************** + private static unsafe void PutThumb2BlRel24(ushort* p, uint imm24) + { + // Verify that we got a valid offset + Debug.Assert(FitsInThumb2BlRel24(imm24)); + + // Ensure that the ThumbBit is not set on the offset + // as it cannot be encoded. + Debug.Assert((imm24 & 1/*THUMB_CODE*/) == 0); + + uint Opcode0 = (uint)p[0]; + uint Opcode1 = (uint)p[1]; + Opcode0 &= 0xF800; + Opcode1 &= 0xD000; + + uint S = (imm24 & 0x1000000) >> 24; + uint J1 = ((imm24 & 0x0800000) >> 23) ^ S ^ 1; + uint J2 = ((imm24 & 0x0400000) >> 22) ^ S ^ 1; + + Opcode0 |= ((imm24 & 0x03FF000) >> 12) | (S << 10); + Opcode1 |= ((imm24 & 0x0000FFE) >> 1) | (J1 << 13) | (J2 << 11); + + p[0] = (ushort)Opcode0; + p[1] = (ushort)Opcode1; + + Debug.Assert((uint)GetThumb2BlRel24(p) == imm24); + } + + public Relocation(RelocType relocType, int offset, ISymbolNode target) + { + RelocType = relocType; + Offset = offset; + Target = target; + } + + public static unsafe void WriteValue(RelocType relocType, void* location, long value) + { + switch (relocType) + { + case RelocType.IMAGE_REL_BASED_ABSOLUTE: + case RelocType.IMAGE_REL_BASED_HIGHLOW: + case RelocType.IMAGE_REL_BASED_REL32: + case RelocType.IMAGE_REL_BASED_ADDR32NB: + case RelocType.IMAGE_REL_SYMBOL_SIZE: + *(int*)location = (int)value; + break; + case RelocType.IMAGE_REL_BASED_DIR64: + *(long*)location = value; + break; + case RelocType.IMAGE_REL_BASED_THUMB_MOV32: + PutThumb2Mov32((ushort*)location, (uint)value); + break; + case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: + PutThumb2BlRel24((ushort*)location, (uint)value); + break; + default: + Debug.Fail("Invalid RelocType: " + relocType); + break; + } + } + + public static unsafe long ReadValue(RelocType relocType, void* location) + { + switch (relocType) + { + case RelocType.IMAGE_REL_BASED_ABSOLUTE: + case RelocType.IMAGE_REL_BASED_ADDR32NB: + case RelocType.IMAGE_REL_BASED_HIGHLOW: + case RelocType.IMAGE_REL_BASED_REL32: + case RelocType.IMAGE_REL_BASED_RELPTR32: + case RelocType.IMAGE_REL_SECREL: + case RelocType.IMAGE_REL_SYMBOL_SIZE: + return *(int*)location; + case RelocType.IMAGE_REL_BASED_DIR64: + return *(long*)location; + case RelocType.IMAGE_REL_BASED_THUMB_MOV32: + return (long)GetThumb2Mov32((ushort*)location); + case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: + return (long)GetThumb2BlRel24((ushort*)location); + default: + Debug.Fail("Invalid RelocType: " + relocType); + return 0; + } + } + + public override string ToString() + { + return $"{Target} ({RelocType}, 0x{Offset:X})"; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ShadowConcreteMethodNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ShadowConcreteMethodNode.cs new file mode 100644 index 00000000000..657e1100719 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ShadowConcreteMethodNode.cs @@ -0,0 +1,109 @@ +// 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.Collections.Generic; + +using ILCompiler.DependencyAnalysisFramework; + +using Internal.Text; +using Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// Represents a concrete method on a generic type (or a generic method) that doesn't + /// have code emitted in the executable because it's physically backed by a canonical + /// method body. The purpose of this node is to track the dependencies of the concrete + /// method body, as if it was generated. The node acts as a symbol for the canonical + /// method for convenience. + /// + public class ShadowConcreteMethodNode : DependencyNodeCore, IMethodNode, ISymbolNodeWithLinkage + { + /// + /// Gets the canonical method body that defines the dependencies of this node. + /// + public IMethodNode CanonicalMethodNode { get; } + + /// + /// Gets the concrete method represented by this node. + /// + public MethodDesc Method { get; } + + // Implementation of ISymbolNode that makes this node act as a symbol for the canonical body + public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + CanonicalMethodNode.AppendMangledName(nameMangler, sb); + } + public int Offset => CanonicalMethodNode.Offset; + public bool RepresentsIndirectionCell => CanonicalMethodNode.RepresentsIndirectionCell; + + public override bool StaticDependenciesAreComputed + => CanonicalMethodNode.StaticDependenciesAreComputed; + + public ShadowConcreteMethodNode(MethodDesc method, IMethodNode canonicalMethod) + { + Debug.Assert(!method.IsSharedByGenericInstantiations); + Debug.Assert(!method.IsRuntimeDeterminedExactMethod); + Debug.Assert(canonicalMethod.Method.IsSharedByGenericInstantiations); + Debug.Assert(canonicalMethod.Method == method.GetCanonMethodTarget(CanonicalFormKind.Specific)); + Method = method; + CanonicalMethodNode = canonicalMethod; + } + + public ISymbolNode NodeForLinkage(NodeFactory factory) + { + return CanonicalMethodNode; + } + + public override IEnumerable GetStaticDependencies(NodeFactory factory) + { + DependencyList dependencies = new DependencyList(); + + // Make sure the canonical body gets generated + dependencies.Add(new DependencyListEntry(CanonicalMethodNode, "Canonical body")); + + // Instantiate the runtime determined dependencies of the canonical method body + // with the concrete instantiation of the method to get concrete dependencies. + Instantiation typeInst = Method.OwningType.Instantiation; + Instantiation methodInst = Method.Instantiation; + IEnumerable staticDependencies = CanonicalMethodNode.GetStaticDependencies(factory); + + if (staticDependencies != null) + { + foreach (DependencyListEntry canonDep in staticDependencies) + { + var runtimeDep = canonDep.Node as INodeWithRuntimeDeterminedDependencies; + if (runtimeDep != null) + { + dependencies.AddRange(runtimeDep.InstantiateDependencies(factory, typeInst, methodInst)); + } + } + } + + return dependencies; + } + + protected override string GetName(NodeFactory factory) => $"{Method.ToString()} backed by {CanonicalMethodNode.GetMangledName(factory.NameMangler)}"; + + public sealed override bool HasConditionalStaticDependencies => false; + public sealed override bool HasDynamicDependencies => false; + public sealed override bool InterestingForDynamicDependencyAnalysis => false; + + public sealed override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; + public sealed override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; + + int ISortableNode.ClassCode => -1440570971; + + int ISortableNode.CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + var compare = comparer.Compare(Method, ((ShadowConcreteMethodNode)other).Method); + if (compare != 0) + return compare; + + return comparer.Compare(CanonicalMethodNode, ((ShadowConcreteMethodNode)other).CanonicalMethodNode); + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs new file mode 100644 index 00000000000..81aa110c9d4 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs @@ -0,0 +1,192 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +using ILCompiler.DependencyAnalysisFramework; +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + public abstract class SortableDependencyNode : DependencyNodeCore, ISortableNode + { +#if !SUPPORT_JIT + /// + /// Allows grouping of instances such that all nodes in a lower phase + /// will be ordered before nodes in a later phase. + /// + protected internal virtual int Phase => (int)ObjectNodePhase.Unordered; + + /// + /// Gets an identifier that is the same for all instances of this + /// descendant, but different from the of any other descendant. + /// + /// + /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". + /// If two manage to conflict (which is pretty unlikely), just make a new one... + /// + public abstract int ClassCode { get; } + + // Note to implementers: the type of `other` is actually the same as the type of `this`. + public virtual int CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + throw new NotImplementedException("Multiple nodes of this type are not supported"); + } + + protected enum ObjectNodePhase + { + /// + /// Nodes should only be placed in this phase if they have strict output ordering requirements that + /// affect compiler correctness. Today that includes native layout tables. + /// + Ordered, + Unordered + } + + protected enum ObjectNodeOrder + { + // + // The ordering of this sequence of nodes is deliberate and currently required for + // compiler correctness. + // + + // + // ReadyToRun Nodes + // + CorHeaderNode, + ReadyToRunHeaderNode, + ImportSectionsTableNode, + ImportSectionNode, + MethodEntrypointTableNode, + + + // + // CoreRT Nodes + // + MetadataNode, + ResourceDataNode, + ResourceIndexNode, + TypeMetadataMapNode, + ClassConstructorContextMap, + DynamicInvokeTemplateDataNode, + ReflectionInvokeMapNode, + DelegateMarshallingStubMapNode, + StructMarshallingStubMapNode, + ArrayMapNode, + ReflectionFieldMapNode, + NativeLayoutInfoNode, + ExactMethodInstantiationsNode, + GenericTypesHashtableNode, + GenericMethodsHashtableNode, + GenericVirtualMethodTableNode, + InterfaceGenericVirtualMethodTableNode, + GenericMethodsTemplateMap, + GenericTypesTemplateMap, + BlockReflectionTypeMapNode, + StaticsInfoHashtableNode, + ReflectionVirtualInvokeMapNode, + ArrayOfEmbeddedPointersNode, + DefaultConstructorMapNode, + ExternalReferencesTableNode, + StackTraceEmbeddedMetadataNode, + StackTraceMethodMappingNode, + ArrayOfEmbeddedDataNode, + WindowsDebugNeedTypeIndicesStoreNode, + WindowsDebugMethodSignatureMapSectionNode, + WindowsDebugTypeSignatureMapSectionNode, + WindowsDebugManagedNativeDictionaryInfoSectionNode, + WindowsDebugTypeRecordsSectionNode, + WindowsDebugPseudoAssemblySectionNode, + } + + public class EmbeddedObjectNodeComparer : IComparer + { + private CompilerComparer _comparer; + + public EmbeddedObjectNodeComparer(CompilerComparer comparer) + { + _comparer = comparer; + } + + public int Compare(EmbeddedObjectNode x, EmbeddedObjectNode y) + { + return CompareImpl(x, y, _comparer); + } + } + + /// + /// This comparer is used to sort the marked node list. We only care about ordering ObjectNodes + /// for emission into the binary, so any EmbeddedObjectNode or DependencyNodeCore objects are + /// skipped for efficiency. + /// + public class ObjectNodeComparer : IComparer> + { + private CompilerComparer _comparer; + + public ObjectNodeComparer(CompilerComparer comparer) + { + _comparer = comparer; + } + + public int Compare(DependencyNodeCore x1, DependencyNodeCore y1) + { + ObjectNode x = x1 as ObjectNode; + ObjectNode y = y1 as ObjectNode; + + if (x == y) + { + return 0; + } + + // Sort non-object nodes after ObjectNodes + if (x == null) + return 1; + + if (y == null) + return -1; + + return CompareImpl(x, y, _comparer); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CompareImpl(SortableDependencyNode x, SortableDependencyNode y, CompilerComparer comparer) + { + int phaseX = x.Phase; + int phaseY = y.Phase; + + if (phaseX == phaseY) + { + int codeX = x.ClassCode; + int codeY = y.ClassCode; + if (codeX == codeY) + { + Debug.Assert(x.GetType() == y.GetType() || + (x.GetType().IsConstructedGenericType && y.GetType().IsConstructedGenericType + && x.GetType().GetGenericTypeDefinition() == y.GetType().GetGenericTypeDefinition())); + + int result = x.CompareToImpl(y, comparer); + + // We did a reference equality check above so an "Equal" result is not expected + Debug.Assert(result != 0 || x == y); + + return result; + } + else + { + Debug.Assert(x.GetType() != y.GetType()); + return codeY > codeX ? -1 : 1; + } + } + else + { + return phaseX - phaseY; + } + } +#endif + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs new file mode 100644 index 00000000000..535f13fce46 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs @@ -0,0 +1,213 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis.ARM +{ + public struct ARMEmitter + { + public ARMEmitter(NodeFactory factory, bool relocsOnly) + { + Builder = new ObjectDataBuilder(factory, relocsOnly); + TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem); + } + + public ObjectDataBuilder Builder; + public TargetRegisterMap TargetRegister; + + // check the value length + private static bool IsBitNumOverflow(int value, byte numBits) + { + return (value >> numBits) != 0; + } + + private static bool IsLowReg(Register reg) + { + return !IsBitNumOverflow((int)reg, 3); + } + + private static bool IsValidReg(Register reg) + { + return !IsBitNumOverflow((int)reg, 4); + } + + // mov reg, immediate + // reg range: [0..7] + // immediage range: [0..255] + public void EmitMOV(Register reg, int immediate) + { + Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); + Builder.EmitShort((short)(0x2000 + ((byte)reg << 8) + immediate)); + } + + // cmp reg, immediate + // reg range: [0..7] + // immediage range: [0..255] + public void EmitCMP(Register reg, int immediate) + { + Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); + Builder.EmitShort((short)(0x2800 + ((byte)reg << 8) + immediate)); + } + + // add reg, immediate + // reg range: [0..7] + // immediage range: [0..255] + public void EmitADD(Register reg, int immediate) + { + Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); + Builder.EmitShort((short)(0x3000 + ((byte)reg << 8) + immediate)); + } + + // sub reg, immediate + // reg range: [0..7] + // immediage range: [0..255] + public void EmitSUB(Register reg, int immediate) + { + Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); + Builder.EmitShort((short)(0x3800 + ((byte)reg << 8) + immediate)); + } + + // nop + public void EmitNOP() + { + Builder.EmitByte(0x00); + Builder.EmitByte(0xbf); + } + + // __debugbreak + public void EmitDebugBreak() + { + Builder.EmitByte(0xde); + Builder.EmitByte(0xfe); + } + + // push reg + // reg range: [0..12, LR] + public void EmitPUSH(Register reg) + { + Debug.Assert(reg >= Register.R0 && (reg <= Register.R12 || reg == TargetRegister.LR)); + Builder.EmitByte(0x4d); + Builder.EmitByte(0xf8); + Builder.EmitShort((short)(0x0d04 + ((byte)reg << 12))); + } + + // pop reg + // reg range: [0..12, LR, PC] + public void EmitPOP(Register reg) + { + Debug.Assert(IsValidReg(reg) && reg != TargetRegister.SP); + Builder.EmitByte(0x5d); + Builder.EmitByte(0xf8); + Builder.EmitShort((short)(0x0b04 + ((byte)reg << 12))); + } + + // mov reg, reg + // reg range: [0..PC] + public void EmitMOV(Register destination, Register source) + { + Debug.Assert(IsValidReg(destination) && IsValidReg(source)); + Builder.EmitShort((short)(0x4600 + (((byte)destination & 0x8) << 4) + (((byte)source & 0x8) << 3) + (((byte)source & 0x7) << 3) + ((byte)destination & 0x7))); + } + + // ldr reg, [reg] + // reg range: [0..7] + public void EmitLDR(Register destination, Register source) + { + Debug.Assert(IsLowReg(destination) && IsLowReg(source)); + Builder.EmitShort((short)(0x6800 + (((byte)source & 0x7) << 3) + ((byte)destination & 0x7))); + } + + // ldr.w reg, [reg, #offset] + // reg range: [0..PC] + // offset range: [-255..4095] + public void EmitLDR(Register destination, Register source, int offset) + { + Debug.Assert(IsValidReg(destination) && IsValidReg(source)); + Debug.Assert(offset >= -255 && offset <= 4095); + if (offset >= 0) + { + Builder.EmitShort((short)(0xf8d0 + ((byte)(source)))); + Builder.EmitShort((short)(offset + (((byte)destination) << 12))); + } + else + { + Builder.EmitShort((short)(0xf850 + ((byte)(source)))); + Builder.EmitShort((short)(-offset + (((byte)destination) << 12) + (((byte)12) << 8))); + } + } + + // movw reg, [reloc] & 0x0000FFFF + // movt reg, [reloc] & 0xFFFF0000 + // reg range: [0..12, LR] + public void EmitMOV(Register destination, ISymbolNode symbol) + { + Debug.Assert(destination >= Register.R0 && (destination <= Register.R12 || destination == TargetRegister.LR)); + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_THUMB_MOV32); + Builder.EmitShort(unchecked((short)0xf240)); + Builder.EmitShort((short)((byte)destination << 8)); + Builder.EmitShort(unchecked((short)0xf2c0)); + Builder.EmitShort((short)((byte)destination << 8)); + } + + // b.w symbol + public void EmitJMP(ISymbolNode symbol) + { + Debug.Assert(!symbol.RepresentsIndirectionCell); + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_THUMB_BRANCH24); + Builder.EmitByte(0); + Builder.EmitByte(0xF0); + Builder.EmitByte(0); + Builder.EmitByte(0xB8); + } + + // bx reg + // reg range: [0..PC] + public void EmitJMP(Register destination) + { + Debug.Assert(IsValidReg(destination)); + Builder.EmitShort((short)(0x4700 + ((byte)destination << 3))); + } + + // bx lr + public void EmitRET() + { + EmitJMP(TargetRegister.LR); + } + + // bne #offset + // offset range: [-256..254] + public void EmitBNE(int immediate) + { + Debug.Assert(immediate >= -256 && immediate <= 254); + // considering the pipeline with PC + immediate -= 4; + + Builder.EmitByte((byte)(immediate >> 1)); + Builder.EmitByte(0xD1); + } + + // beq #offset + // offset range: [-256..254] + public void EmitBEQ(int immediate) + { + Debug.Assert(immediate >= -256 && immediate <= 254); + // considering the pipeline with PC + immediate -= 4; + + Builder.EmitByte((byte)(immediate >> 1)); + Builder.EmitByte(0xD0); + } + + // bne label(+4): ret(2) + next(2) + // bx lr + // label: ... + public void EmitRETIfEqual() + { + EmitBNE(4); + EmitRET(); + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/Register.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/Register.cs new file mode 100644 index 00000000000..15213c752ed --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/Register.cs @@ -0,0 +1,37 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILCompiler.DependencyAnalysis.ARM +{ + public enum Register + { + R0 = 0, + R1 = 1, + R2 = 2, + R3 = 3, + R4 = 4, + R5 = 5, + R6 = 6, + R7 = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, + + None = 16, + RegDirect = 24, + + NoIndex = 128, + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs new file mode 100644 index 00000000000..d3940ceaaad --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs @@ -0,0 +1,39 @@ +// 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.TypeSystem; + +namespace ILCompiler.DependencyAnalysis.ARM +{ + /// + /// Maps logical registers to physical registers on a specified OS. + /// + public struct TargetRegisterMap + { + public readonly Register Arg0; + public readonly Register Arg1; + public readonly Register Arg2; + public readonly Register Arg3; + public readonly Register Result; + public readonly Register InterproceduralScratch; + public readonly Register SP; + public readonly Register LR; + public readonly Register PC; + + public TargetRegisterMap(TargetOS os) + { + Arg0 = Register.R0; + Arg1 = Register.R1; + Arg2 = Register.R2; + Arg3 = Register.R3; + Result = Register.R0; + InterproceduralScratch = Register.R12; + SP = Register.R13; + LR = Register.R14; + PC = Register.R15; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs new file mode 100644 index 00000000000..da3d8b6e946 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs @@ -0,0 +1,122 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis.ARM64 +{ + public struct ARM64Emitter + { + public ARM64Emitter(NodeFactory factory, bool relocsOnly) + { + Builder = new ObjectDataBuilder(factory, relocsOnly); + TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem); + } + + public ObjectDataBuilder Builder; + public TargetRegisterMap TargetRegister; + + // Assembly stub creation api. TBD, actually make this general purpose + public void EmitMOV(Register regDst, ref AddrMode memory) + { + throw new NotImplementedException(); + } + + public void EmitMOV(Register regDst, Register regSrc) + { + throw new NotImplementedException(); + } + + public void EmitMOV(Register regDst, int imm32) + { + throw new NotImplementedException(); + } + + public void EmitLEAQ(Register reg, ISymbolNode symbol, int delta = 0) + { + throw new NotImplementedException(); + } + + public void EmitLEA(Register reg, ref AddrMode addrMode) + { + throw new NotImplementedException(); + } + + public void EmitCMP(ref AddrMode addrMode, sbyte immediate) + { + throw new NotImplementedException(); + } + + // add reg, immediate + public void EmitADD(Register reg, byte immediate) + { + Builder.EmitInt((int)(0x91 << 24) | (immediate << 10) | ((byte)reg << 5) | (byte) reg); + } + + public void EmitJMP(ISymbolNode symbol) + { + if (symbol.RepresentsIndirectionCell) + { + // xip0 register num is 0x10 + + // ADRP xip0, [symbol (21bit ADRP thing)] + // 0x90000000 + (xip regnum) + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21); + Builder.EmitByte(0x10); + Builder.EmitByte(0x00); + Builder.EmitByte(0x00); + Builder.EmitByte(0x90); + + // LDR xip0, [xip0 + 12bit LDR page offset reloc)] + // 0xF9400000 + ((xip0 regnum) << 5) + (xip regnum) + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L); + Builder.EmitByte(0x10); + Builder.EmitByte(0x02); + Builder.EmitByte(0x40); + Builder.EmitByte(0xF9); + + // BR xip0 + // 0xD61F0000 + (xip0 regnum) << 5) + Builder.EmitByte(0x00); + Builder.EmitByte(0x02); + Builder.EmitByte(0x1F); + Builder.EmitByte(0xD6); + } + else + { + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ARM64_BRANCH26); + Builder.EmitByte(0); + Builder.EmitByte(0); + Builder.EmitByte(0); + Builder.EmitByte(0x14); + } + } + + public void EmitINT3() + { + throw new NotImplementedException(); + } + + public void EmitJmpToAddrMode(ref AddrMode addrMode) + { + throw new NotImplementedException(); + } + + public void EmitRET() + { + throw new NotImplementedException(); + } + + public void EmitRETIfEqual() + { + throw new NotImplementedException(); + } + + private bool InSignedByteRange(int i) + { + return i == (int)(sbyte)i; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/AddrMode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/AddrMode.cs new file mode 100644 index 00000000000..f8d757359d6 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/AddrMode.cs @@ -0,0 +1,35 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis.ARM64 +{ + public enum AddrModeSize + { + Int8 = 1, + Int16 = 2, + Int32 = 4, + Int64 = 8, + Int128 = 16 + } + + public struct AddrMode + { + public readonly Register BaseReg; + public readonly Register? IndexReg; + public readonly int Offset; + public readonly byte Scale; + public readonly AddrModeSize Size; + + public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size) + { + BaseReg = baseRegister; + IndexReg = indexRegister; + Offset = offset; + Scale = scale; + Size = size; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/Register.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/Register.cs new file mode 100644 index 00000000000..b69177e30af --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/Register.cs @@ -0,0 +1,52 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILCompiler.DependencyAnalysis.ARM64 +{ + public enum Register + { + X0 = 0, + X1 = 1, + X2 = 2, + X3 = 3, + X4 = 4, + X5 = 5, + X6 = 6, + X7 = 7, + X8 = 8, + X9 = 9, + X10 = 10, + X11 = 11, + X12 = 12, + X13 = 13, + X14 = 14, + X15 = 15, + X16 = 16, + X17 = 17, + X18 = 18, + X19 = 19, + X20 = 20, + X21 = 21, + X22 = 22, + X23 = 23, + X24 = 24, + X25 = 25, + X26 = 26, + X27 = 27, + X28 = 28, + X29 = 29, + X30 = 30, + + X31 = 31, + + None = 32, + NoIndex = 128, + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/TargetRegisterMap.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/TargetRegisterMap.cs new file mode 100644 index 00000000000..dff6e4a837d --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/TargetRegisterMap.cs @@ -0,0 +1,39 @@ +// 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.TypeSystem; + +namespace ILCompiler.DependencyAnalysis.ARM64 +{ + /// + /// Maps logical registers to physical registers on a specified OS. + /// + public struct TargetRegisterMap + { + public readonly Register Arg0; + public readonly Register Arg1; + public readonly Register Arg2; + public readonly Register Arg3; + public readonly Register Arg4; + public readonly Register Arg5; + public readonly Register Arg6; + public readonly Register Arg7; + public readonly Register Result; + + public TargetRegisterMap(TargetOS os) + { + Arg0 = Register.X0; + Arg1 = Register.X1; + Arg2 = Register.X2; + Arg3 = Register.X3; + Arg4 = Register.X4; + Arg5 = Register.X5; + Arg6 = Register.X6; + Arg7 = Register.X7; + Result = Register.X0; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/AddrMode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/AddrMode.cs new file mode 100644 index 00000000000..cba245601b5 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/AddrMode.cs @@ -0,0 +1,35 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis.X64 +{ + public enum AddrModeSize + { + Int8 = 1, + Int16 = 2, + Int32 = 4, + Int64 = 8, + Int128 = 16 + } + + public struct AddrMode + { + public readonly Register BaseReg; + public readonly Register? IndexReg; + public readonly int Offset; + public readonly byte Scale; + public readonly AddrModeSize Size; + + public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size) + { + BaseReg = baseRegister; + IndexReg = indexRegister; + Offset = offset; + Scale = scale; + Size = size; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/Register.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/Register.cs new file mode 100644 index 00000000000..1bc2aa00bc0 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/Register.cs @@ -0,0 +1,37 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILCompiler.DependencyAnalysis.X64 +{ + public enum Register + { + RAX = 0, + RCX = 1, + RDX = 2, + RBX = 3, + RSP = 4, + RBP = 5, + RSI = 6, + RDI = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, + + None = 16, + RegDirect = 24, + + NoIndex = 128, + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs new file mode 100644 index 00000000000..808f8ed03c5 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.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. + +using System; + +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis.X64 +{ + /// + /// Maps logical registers to physical registers on a specified OS. + /// + public struct TargetRegisterMap + { + public readonly Register Arg0; + public readonly Register Arg1; + public readonly Register Arg2; + public readonly Register Arg3; + public readonly Register Result; + + public TargetRegisterMap(TargetOS os) + { + switch (os) + { + case TargetOS.Windows: + Arg0 = Register.RCX; + Arg1 = Register.RDX; + Arg2 = Register.R8; + Arg3 = Register.R9; + Result = Register.RAX; + break; + + case TargetOS.Linux: + case TargetOS.OSX: + case TargetOS.FreeBSD: + Arg0 = Register.RDI; + Arg1 = Register.RSI; + Arg2 = Register.RDX; + Arg3 = Register.RCX; + Result = Register.RAX; + break; + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs new file mode 100644 index 00000000000..932e5ab96de --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs @@ -0,0 +1,375 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis.X64 +{ + public struct X64Emitter + { + public X64Emitter(NodeFactory factory, bool relocsOnly) + { + Builder = new ObjectDataBuilder(factory, relocsOnly); + TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem); + } + + public ObjectDataBuilder Builder; + public TargetRegisterMap TargetRegister; + + // Assembly stub creation api. TBD, actually make this general purpose + public void EmitMOV(Register regDst, ref AddrMode memory) + { + EmitIndirInstructionSize(0x8a, regDst, ref memory); + } + + public void EmitMOV(Register regDst, Register regSrc) + { + AddrMode rexAddrMode = new AddrMode(regSrc, null, 0, 0, AddrModeSize.Int64); + EmitRexPrefix(regDst, ref rexAddrMode); + Builder.EmitByte(0x8B); + Builder.EmitByte((byte)(0xC0 | (((int)regDst & 0x07) << 3) | (((int)regSrc & 0x07)))); + } + + public void EmitMOV(Register regDst, int imm32) + { + AddrMode rexAddrMode = new AddrMode(regDst, null, 0, 0, AddrModeSize.Int32); + EmitRexPrefix(regDst, ref rexAddrMode); + Builder.EmitByte((byte)(0xB8 | ((int)regDst & 0x07))); + Builder.EmitInt(imm32); + } + + public void EmitMOV(Register regDst, ISymbolNode node) + { + if (node.RepresentsIndirectionCell) + { + Builder.EmitByte(0x67); + Builder.EmitByte(0x48); + Builder.EmitByte(0x8B); + Builder.EmitByte((byte)(0x00 | ((byte)regDst << 3) | 0x05)); + Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_REL32); + } + else + { + EmitLEAQ(regDst, node, delta: 0); + } + } + + public void EmitLEAQ(Register reg, ISymbolNode symbol, int delta = 0) + { + AddrMode rexAddrMode = new AddrMode(Register.RAX, null, 0, 0, AddrModeSize.Int64); + EmitRexPrefix(reg, ref rexAddrMode); + Builder.EmitByte(0x8D); + Builder.EmitByte((byte)(0x05 | (((int)reg) & 0x07) << 3)); + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32, delta); + } + + public void EmitLEA(Register reg, ref AddrMode addrMode) + { + Debug.Assert(addrMode.Size != AddrModeSize.Int8 && + addrMode.Size != AddrModeSize.Int16); + EmitIndirInstruction(0x8D, reg, ref addrMode); + } + + public void EmitCMP(ref AddrMode addrMode, sbyte immediate) + { + if (addrMode.Size == AddrModeSize.Int16) + Builder.EmitByte(0x66); + EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), 0x7, ref addrMode); + Builder.EmitByte((byte)immediate); + } + + public void EmitADD(ref AddrMode addrMode, sbyte immediate) + { + if (addrMode.Size == AddrModeSize.Int16) + Builder.EmitByte(0x66); + EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), (byte)0, ref addrMode); + Builder.EmitByte((byte)immediate); + } + + public void EmitJMP(ISymbolNode symbol) + { + if (symbol.RepresentsIndirectionCell) + { + Builder.EmitByte(0xff); + Builder.EmitByte(0x25); + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); + } + else + { + Builder.EmitByte(0xE9); + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); + + } + } + + public void EmitJE(ISymbolNode symbol) + { + if (symbol.RepresentsIndirectionCell) + { + throw new NotImplementedException(); + } + else + { + Builder.EmitByte(0x0f); + Builder.EmitByte(0x84); + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); + } + } + + public void EmitINT3() + { + Builder.EmitByte(0xCC); + } + + public void EmitJmpToAddrMode(ref AddrMode addrMode) + { + EmitIndirInstruction(0xFF, 0x4, ref addrMode); + } + + public void EmitPUSH(sbyte imm8) + { + Builder.EmitByte(0x6A); + Builder.EmitByte(unchecked((byte)imm8)); + } + + public void EmitPUSH(ISymbolNode node) + { + if (node.RepresentsIndirectionCell) + { + // push [rip + relative node offset] + Builder.EmitByte(0xFF); + Builder.EmitByte(0x35); + Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_REL32); + } + else + { + // push rax (arbitrary value) + Builder.EmitByte(0x50); + // lea rax, [rip + relative node offset] + Builder.EmitByte(0x48); + Builder.EmitByte(0x8D); + Builder.EmitByte(0x05); + Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_REL32); + // xchg [rsp], rax; this also restores the previous value of rax + Builder.EmitByte(0x48); + Builder.EmitByte(0x87); + Builder.EmitByte(0x04); + Builder.EmitByte(0x24); + } + } + + public void EmitRET() + { + Builder.EmitByte(0xC3); + } + + public void EmitRETIfEqual() + { + // jne @+1 + Builder.EmitByte(0x75); + Builder.EmitByte(0x01); + + // ret + Builder.EmitByte(0xC3); + } + + private bool InSignedByteRange(int i) + { + return i == (int)(sbyte)i; + } + + private void EmitImmediate(int immediate, int size) + { + switch (size) + { + case 0: + break; + case 1: + Builder.EmitByte((byte)immediate); + break; + case 2: + Builder.EmitShort((short)immediate); + break; + case 4: + Builder.EmitInt(immediate); + break; + default: + throw new NotImplementedException(); + } + } + + private void EmitModRM(byte subOpcode, ref AddrMode addrMode) + { + byte modRM = (byte)((subOpcode & 0x07) << 3); + if (addrMode.BaseReg > Register.None) + { + Debug.Assert(addrMode.BaseReg >= Register.RegDirect); + + Register reg = (Register)(addrMode.BaseReg - Register.RegDirect); + Builder.EmitByte((byte)(0xC0 | modRM | ((int)reg & 0x07))); + } + else + { + byte lowOrderBitsOfBaseReg = (byte)((int)addrMode.BaseReg & 0x07); + modRM |= lowOrderBitsOfBaseReg; + int offsetSize = 0; + + if (addrMode.Offset == 0 && (lowOrderBitsOfBaseReg != (byte)Register.RBP)) + { + offsetSize = 0; + } + else if (InSignedByteRange(addrMode.Offset)) + { + offsetSize = 1; + modRM |= 0x40; + } + else + { + offsetSize = 4; + modRM |= 0x80; + } + + bool emitSibByte = false; + Register sibByteBaseRegister = addrMode.BaseReg; + + if (addrMode.BaseReg == Register.None) + { + //# ifdef _TARGET_AMD64_ + // x64 requires SIB to avoid RIP relative address + emitSibByte = true; + //#else + // emitSibByte = (addrMode.m_indexReg != MDIL_REG_NO_INDEX); + //#endif + + modRM &= 0x38; // set Mod bits to 00 and clear out base reg + offsetSize = 4; // this forces 32-bit displacement + + if (emitSibByte) + { + // EBP in SIB byte means no base + // ModRM base register forced to ESP in SIB code below + sibByteBaseRegister = Register.RBP; + } + else + { + // EBP in ModRM means no base + modRM |= (byte)(Register.RBP); + } + } + else if (lowOrderBitsOfBaseReg == (byte)Register.RSP || addrMode.IndexReg.HasValue) + { + emitSibByte = true; + } + + if (!emitSibByte) + { + Builder.EmitByte(modRM); + } + else + { + // MDIL_REG_ESP as the base is the marker that there is a SIB byte + modRM = (byte)((modRM & 0xF8) | (int)Register.RSP); + Builder.EmitByte(modRM); + + int indexRegAsInt = (int)(addrMode.IndexReg.HasValue ? addrMode.IndexReg.Value : Register.RSP); + + Builder.EmitByte((byte)((addrMode.Scale << 6) + ((indexRegAsInt & 0x07) << 3) + ((int)sibByteBaseRegister & 0x07))); + } + EmitImmediate(addrMode.Offset, offsetSize); + } + } + + private void EmitExtendedOpcode(int opcode) + { + if ((opcode >> 16) != 0) + { + if ((opcode >> 24) != 0) + { + Builder.EmitByte((byte)(opcode >> 24)); + } + Builder.EmitByte((byte)(opcode >> 16)); + } + Builder.EmitByte((byte)(opcode >> 8)); + } + + private void EmitRexPrefix(Register reg, ref AddrMode addrMode) + { + byte rexPrefix = 0; + + // Check the situations where a REX prefix is needed + + // Are we accessing a byte register that wasn't byte accessible in x86? + if (addrMode.Size == AddrModeSize.Int8 && reg >= Register.RSP) + { + rexPrefix |= 0x40; // REX - access to new 8-bit registers + } + + // Is this a 64 bit instruction? + if (addrMode.Size == AddrModeSize.Int64) + { + rexPrefix |= 0x48; // REX.W - 64-bit data operand + } + + // Is the destination register one of the new ones? + if (reg >= Register.R8) + { + rexPrefix |= 0x44; // REX.R - extension of the register field + } + + // Is the index register one of the new ones? + if (addrMode.IndexReg.HasValue && addrMode.IndexReg.Value >= Register.R8 && addrMode.IndexReg.Value <= Register.R15) + { + rexPrefix |= 0x42; // REX.X - extension of the SIB index field + } + + // Is the base register one of the new ones? + if (addrMode.BaseReg >= Register.R8 && addrMode.BaseReg <= Register.R15 + || addrMode.BaseReg >= (int)Register.R8 + Register.RegDirect && addrMode.BaseReg <= (int)Register.R15 + Register.RegDirect) + { + rexPrefix |= 0x41; // REX.WB (Wide, extended Base) + } + + // If we have anything so far, emit it. + if (rexPrefix != 0) + { + Builder.EmitByte(rexPrefix); + } + } + + private void EmitIndirInstruction(int opcode, byte subOpcode, ref AddrMode addrMode) + { + EmitRexPrefix(Register.RAX, ref addrMode); + if ((opcode >> 8) != 0) + { + EmitExtendedOpcode(opcode); + } + Builder.EmitByte((byte)opcode); + EmitModRM(subOpcode, ref addrMode); + } + + private void EmitIndirInstruction(int opcode, Register dstReg, ref AddrMode addrMode) + { + EmitRexPrefix(dstReg, ref addrMode); + if ((opcode >> 8) != 0) + { + EmitExtendedOpcode(opcode); + } + Builder.EmitByte((byte)opcode); + EmitModRM((byte)((int)dstReg & 0x07), ref addrMode); + } + + private void EmitIndirInstructionSize(int opcode, Register dstReg, ref AddrMode addrMode) + { + //# ifndef _TARGET_AMD64_ + // assert that ESP, EBP, ESI, EDI are not accessed as bytes in 32-bit mode + // Debug.Assert(!(addrMode.Size == AddrModeSize.Int8 && dstReg > Register.RBX)); + //#endif + Debug.Assert(addrMode.Size != 0); + if (addrMode.Size == AddrModeSize.Int16) + Builder.EmitByte(0x66); + EmitIndirInstruction(opcode + ((addrMode.Size != AddrModeSize.Int8) ? 1 : 0), dstReg, ref addrMode); + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs new file mode 100644 index 00000000000..75a5a7edabd --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs @@ -0,0 +1,33 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis.X86 +{ + public enum AddrModeSize + { + Int8 = 1, + Int16 = 2, + Int32 = 4 + } + + public struct AddrMode + { + public readonly Register BaseReg; + public readonly Register? IndexReg; + public readonly int Offset; + public readonly byte Scale; + public readonly AddrModeSize Size; + + public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size) + { + BaseReg = baseRegister; + IndexReg = indexRegister; + Offset = offset; + Scale = scale; + Size = size; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/Register.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/Register.cs new file mode 100644 index 00000000000..ab938c82800 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/Register.cs @@ -0,0 +1,29 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILCompiler.DependencyAnalysis.X86 +{ + public enum Register + { + EAX = 0, + ECX = 1, + EDX = 2, + EBX = 3, + ESP = 4, + EBP = 5, + ESI = 6, + EDI = 7, + + None = 8, + RegDirect = 24, + + NoIndex = 128, + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs new file mode 100644 index 00000000000..3b81e43ba02 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs @@ -0,0 +1,35 @@ +// 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.TypeSystem; + +namespace ILCompiler.DependencyAnalysis.X86 +{ + /// + /// Maps logical registers to physical registers on a specified OS. + /// + public struct TargetRegisterMap + { + public readonly Register Arg0; + public readonly Register Arg1; + public readonly Register Result; + + public TargetRegisterMap(TargetOS os) + { + switch (os) + { + case TargetOS.Windows: + Arg0 = Register.ECX; + Arg1 = Register.EDX; + Result = Register.EAX; + break; + + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs new file mode 100644 index 00000000000..a811ab4e678 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs @@ -0,0 +1,220 @@ +// 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; + +namespace ILCompiler.DependencyAnalysis.X86 +{ + public struct X86Emitter + { + public X86Emitter(NodeFactory factory, bool relocsOnly) + { + Builder = new ObjectDataBuilder(factory, relocsOnly); + TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem); + } + + public ObjectDataBuilder Builder; + public TargetRegisterMap TargetRegister; + + public void EmitADD(ref AddrMode addrMode, sbyte immediate) + { + if (addrMode.Size == AddrModeSize.Int16) + Builder.EmitByte(0x66); + EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), (byte)0, ref addrMode); + Builder.EmitByte((byte)immediate); + } + + public void EmitJMP(ISymbolNode symbol) + { + if (symbol.RepresentsIndirectionCell) + { + Builder.EmitByte(0xff); + Builder.EmitByte(0x25); + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_HIGHLOW); + } + else + { + Builder.EmitByte(0xE9); + Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); + } + } + + public void EmitXOR(Register register1, Register register2) + { + Builder.EmitByte(0x33); + Builder.EmitByte((byte)(0xC0 | ((byte)register1 << 3) | (byte)register2)); + } + + public void EmitPUSH(sbyte imm8) + { + Builder.EmitByte(0x6A); + Builder.EmitByte(unchecked((byte)imm8)); + } + + public void EmitPUSH(ISymbolNode node) + { + if (node.RepresentsIndirectionCell) + { + // push eax (arbitrary value) + Builder.EmitByte(0x50); + // mov eax, [node address] + Builder.EmitByte(0x8B); + Builder.EmitByte(0x00 | ((byte)Register.EAX << 3) | 0x5); + Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_HIGHLOW); + // xchg [esp], eax; this also restores the previous value of eax + Builder.EmitByte(0x87); + Builder.EmitByte(0x04); + Builder.EmitByte(0x24); + } + else + { + // push + Builder.EmitByte(0x68); + Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_HIGHLOW); + } + } + + public void EmitMOV(Register register, ISymbolNode node) + { + if (node.RepresentsIndirectionCell) + { + // mov register, [node address] + Builder.EmitByte(0x8B); + Builder.EmitByte((byte)(0x00 | ((byte)register << 3) | 0x5)); + } + else + { + // mov register, immediate + Builder.EmitByte((byte)(0xB8 + (byte)register)); + } + Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_HIGHLOW); + } + + public void EmitINT3() + { + Builder.EmitByte(0xCC); + } + + private bool InSignedByteRange(int i) + { + return i == (int)(sbyte)i; + } + + private void EmitImmediate(int immediate, int size) + { + switch (size) + { + case 0: + break; + case 1: + Builder.EmitByte((byte)immediate); + break; + case 2: + Builder.EmitShort((short)immediate); + break; + case 4: + Builder.EmitInt(immediate); + break; + default: + throw new NotImplementedException(); + } + } + + private void EmitModRM(byte subOpcode, ref AddrMode addrMode) + { + byte modRM = (byte)((subOpcode & 0x07) << 3); + if (addrMode.BaseReg > Register.None) + { + Debug.Assert(addrMode.BaseReg >= Register.RegDirect); + + Register reg = (Register)(addrMode.BaseReg - Register.RegDirect); + Builder.EmitByte((byte)(0xC0 | modRM | ((int)reg & 0x07))); + } + else + { + byte lowOrderBitsOfBaseReg = (byte)((int)addrMode.BaseReg & 0x07); + modRM |= lowOrderBitsOfBaseReg; + int offsetSize = 0; + + if (addrMode.Offset == 0 && (lowOrderBitsOfBaseReg != (byte)Register.EBP)) + { + offsetSize = 0; + } + else if (InSignedByteRange(addrMode.Offset)) + { + offsetSize = 1; + modRM |= 0x40; + } + else + { + offsetSize = 4; + modRM |= 0x80; + } + + bool emitSibByte = false; + Register sibByteBaseRegister = addrMode.BaseReg; + + if (addrMode.BaseReg == Register.None) + { + emitSibByte = (addrMode.IndexReg != Register.NoIndex); + modRM &= 0x38; // set Mod bits to 00 and clear out base reg + offsetSize = 4; // this forces 32-bit displacement + + if (emitSibByte) + { + // EBP in SIB byte means no base + // ModRM base register forced to ESP in SIB code below + sibByteBaseRegister = Register.EBP; + } + else + { + // EBP in ModRM means no base + modRM |= (byte)(Register.EBP); + } + } + else if (lowOrderBitsOfBaseReg == (byte)Register.ESP || addrMode.IndexReg.HasValue) + { + emitSibByte = true; + } + + if (!emitSibByte) + { + Builder.EmitByte(modRM); + } + else + { + modRM = (byte)((modRM & 0xF8) | (int)Register.ESP); + Builder.EmitByte(modRM); + int indexRegAsInt = (int)(addrMode.IndexReg.HasValue ? addrMode.IndexReg.Value : Register.ESP); + Builder.EmitByte((byte)((addrMode.Scale << 6) + ((indexRegAsInt & 0x07) << 3) + ((int)sibByteBaseRegister & 0x07))); + } + EmitImmediate(addrMode.Offset, offsetSize); + } + } + + private void EmitExtendedOpcode(int opcode) + { + if ((opcode >> 16) != 0) + { + if ((opcode >> 24) != 0) + { + Builder.EmitByte((byte)(opcode >> 24)); + } + Builder.EmitByte((byte)(opcode >> 16)); + } + Builder.EmitByte((byte)(opcode >> 8)); + } + + private void EmitIndirInstruction(int opcode, byte subOpcode, ref AddrMode addrMode) + { + if ((opcode >> 8) != 0) + { + EmitExtendedOpcode(opcode); + } + Builder.EmitByte((byte)opcode); + EmitModRM(subOpcode, ref addrMode); + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyTrackingLevel.cs b/src/coreclr/src/tools/Common/Compiler/DependencyTrackingLevel.cs new file mode 100644 index 00000000000..9322b9d3026 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyTrackingLevel.cs @@ -0,0 +1,58 @@ +// 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.Collections.Generic; + +using ILCompiler.DependencyAnalysis; +using ILCompiler.DependencyAnalysisFramework; + +namespace ILCompiler +{ + /// + /// Represents the level of dependency tracking within the dependency analysis system. + /// + public enum DependencyTrackingLevel + { + /// + /// Tracking disabled. This is the most performant and memory efficient option. + /// + None, + + /// + /// The graph keeps track of the first dependency. + /// + First, + + /// + /// The graph keeps track of all dependencies. + /// + All + } + + internal static class DependencyTrackingLevelExtensions + { + public static DependencyAnalyzerBase CreateDependencyGraph(this DependencyTrackingLevel trackingLevel, NodeFactory factory, IComparer> comparer = null) + { + // Choose which dependency graph implementation to use based on the amount of logging requested. + switch (trackingLevel) + { + case DependencyTrackingLevel.None: + if (EventSourceLogStrategy.IsEventSourceEnabled) + return new DependencyAnalyzer, NodeFactory>(factory, comparer); + else + return new DependencyAnalyzer, NodeFactory>(factory, comparer); + + case DependencyTrackingLevel.First: + return new DependencyAnalyzer, NodeFactory>(factory, comparer); + + case DependencyTrackingLevel.All: + return new DependencyAnalyzer, NodeFactory>(factory, comparer); + + default: + throw new InvalidOperationException(); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/src/tools/Common/Compiler/DevirtualizationManager.cs new file mode 100644 index 00000000000..92467d0176c --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DevirtualizationManager.cs @@ -0,0 +1,101 @@ +// 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 Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler +{ + /// + /// Manages devirtualization behaviors. Devirtualization is the process of converting + /// virtual calls to direct calls in cases where we can compute the result of a virtual + /// lookup at compile time. + /// + public class DevirtualizationManager + { + /// + /// Returns true if cannot be the base class of any other + /// type. + /// + public virtual bool IsEffectivelySealed(TypeDesc type) + { + switch (type.Category) + { + case TypeFlags.Array: + case TypeFlags.SzArray: + case TypeFlags.ByRef: + case TypeFlags.Pointer: + case TypeFlags.FunctionPointer: + return true; + + default: + Debug.Assert(type.IsDefType); + var metadataType = (MetadataType)type; + return metadataType.IsSealed || metadataType.IsModuleType; + } + } + + /// + /// Returns true if cannot be overriden by any other method. + /// + public virtual bool IsEffectivelySealed(MethodDesc method) + { + return method.IsFinal || IsEffectivelySealed(method.OwningType); + } + + /// + /// Attempts to resolve the virtual method into + /// a method on that implements the declaring method. + /// Returns null if this is not possible. + /// + /// + /// Note that if is a value type, the result of the resolution + /// might have to be treated as an unboxing thunk by the caller. + /// + public MethodDesc ResolveVirtualMethod(MethodDesc declMethod, TypeDesc implType) + { + Debug.Assert(declMethod.IsVirtual); + + // We're operating on virtual methods. This means that if implType is an array, we need + // to get the type that has all the virtual methods provided by the class library. + return ResolveVirtualMethod(declMethod, implType.GetClosestDefType()); + } + + protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType implType) + { + // Quick check: if decl matches impl, we're done. + if (declMethod.OwningType == implType) + return declMethod; + + MethodDesc impl; + + if (declMethod.OwningType.IsInterface) + { + impl = implType.ResolveInterfaceMethodTarget(declMethod); + if (impl != null) + { + impl = implType.FindVirtualFunctionTargetMethodOnObjectType(impl); + } + } + else + { + impl = implType.FindVirtualFunctionTargetMethodOnObjectType(declMethod); + if (impl != null && (impl != declMethod)) + { + MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl); + MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod); + + if (slotDefiningMethodImpl != slotDefiningMethodDecl) + { + // We cannot resolve virtual method in case the impl is a different slot from the declMethod + impl = null; + } + } + } + + return impl; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/HardwareIntrinsicHelpers.cs b/src/coreclr/src/tools/Common/Compiler/HardwareIntrinsicHelpers.cs new file mode 100644 index 00000000000..99b3400617c --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/HardwareIntrinsicHelpers.cs @@ -0,0 +1,192 @@ +// 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.TypeSystem; +using Internal.IL; +using Internal.IL.Stubs; +using System.Diagnostics; + +namespace ILCompiler +{ + public static class HardwareIntrinsicHelpers + { + /// + /// Gets a value indicating whether this is a hardware intrinsic on the platform that we're compiling for. + /// + public static bool IsHardwareIntrinsic(MethodDesc method) + { + TypeDesc owningType = method.OwningType; + + if (owningType.IsIntrinsic && owningType is MetadataType mdType) + { + TargetArchitecture targetArch = owningType.Context.Target.Architecture; + + if (targetArch == TargetArchitecture.X64 || targetArch == TargetArchitecture.X86) + { + mdType = (MetadataType)mdType.ContainingType ?? mdType; + if (mdType.Namespace == "System.Runtime.Intrinsics.X86") + return true; + } + else if (targetArch == TargetArchitecture.ARM64) + { + if (mdType.Namespace == "System.Runtime.Intrinsics.Arm.Arm64") + return true; + } + } + + return false; + } + + public static bool IsIsSupportedMethod(MethodDesc method) + { + return method.Name == "get_IsSupported"; + } + + public static MethodIL GetUnsupportedImplementationIL(MethodDesc method) + { + // The implementation of IsSupported for codegen backends that don't support hardware intrinsics + // at all is to return 0. + if (IsIsSupportedMethod(method)) + { + return new ILStubMethodIL(method, + new byte[] { + (byte)ILOpcode.ldc_i4_0, + (byte)ILOpcode.ret + }, + Array.Empty(), null); + } + + // Other methods throw PlatformNotSupportedException + MethodDesc throwPnse = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException"); + + return new ILStubMethodIL(method, + new byte[] { + (byte)ILOpcode.call, 1, 0, 0, 0, + (byte)ILOpcode.br_s, unchecked((byte)-7), + }, + Array.Empty(), + new object[] { throwPnse }); + } + + /// + /// Generates IL for the IsSupported property that reads this information from a field initialized by the runtime + /// at startup. Returns null for hardware intrinsics whose support level is known at compile time + /// (i.e. they're known to be always supported or always unsupported). + /// + public static MethodIL EmitIsSupportedIL(MethodDesc method, FieldDesc isSupportedField) + { + Debug.Assert(IsIsSupportedMethod(method)); + Debug.Assert(isSupportedField.IsStatic && isSupportedField.FieldType.IsWellKnownType(WellKnownType.Int32)); + + TargetDetails target = method.Context.Target; + MetadataType owningType = (MetadataType)method.OwningType; + + // Check for case of nested "X64" types + if (owningType.Name == "X64") + { + if (target.Architecture != TargetArchitecture.X64) + return null; + + // Un-nest the type so that we can do a name match + owningType = (MetadataType)owningType.ContainingType; + } + + int flag; + if ((target.Architecture == TargetArchitecture.X64 || target.Architecture == TargetArchitecture.X86) + && owningType.Namespace == "System.Runtime.Intrinsics.X86") + { + switch (owningType.Name) + { + case "Aes": + flag = XArchIntrinsicConstants.Aes; + break; + case "Pclmulqdq": + flag = XArchIntrinsicConstants.Pclmulqdq; + break; + case "Sse3": + flag = XArchIntrinsicConstants.Sse3; + break; + case "Ssse3": + flag = XArchIntrinsicConstants.Ssse3; + break; + case "Lzcnt": + flag = XArchIntrinsicConstants.Lzcnt; + break; + // NOTE: this switch is complemented by IsKnownSupportedIntrinsicAtCompileTime + // in the method below. + default: + return null; + } + } + else + { + return null; + } + + var emit = new ILEmitter(); + ILCodeStream codeStream = emit.NewCodeStream(); + + codeStream.Emit(ILOpcode.ldsfld, emit.NewToken(isSupportedField)); + codeStream.EmitLdc(flag); + codeStream.Emit(ILOpcode.and); + codeStream.EmitLdc(0); + codeStream.Emit(ILOpcode.cgt_un); + codeStream.Emit(ILOpcode.ret); + + return emit.Link(method); + } + + /// + /// Gets a value indicating whether the support for a given intrinsic is known at compile time. + /// + public static bool IsKnownSupportedIntrinsicAtCompileTime(MethodDesc method) + { + TargetDetails target = method.Context.Target; + + if (target.Architecture == TargetArchitecture.X64 + || target.Architecture == TargetArchitecture.X86) + { + var owningType = (MetadataType)method.OwningType; + if (owningType.Name == "X64") + { + if (target.Architecture != TargetArchitecture.X64) + return true; + owningType = (MetadataType)owningType.ContainingType; + } + + if (owningType.Namespace != "System.Runtime.Intrinsics.X86") + return true; + + // Sse and Sse2 are baseline required intrinsics. + // RyuJIT also uses Sse41/Sse42 with the general purpose Vector APIs. + // RyuJIT only respects Popcnt if Sse41/Sse42 is also enabled. + // Avx/Avx2/Bmi1/Bmi2 require VEX encoding and RyuJIT currently can't enable them + // without enabling VEX encoding everywhere. We don't support them. + // This list complements EmitIsSupportedIL above. + return owningType.Name == "Sse" || owningType.Name == "Sse2" + || owningType.Name == "Sse41" || owningType.Name == "Sse42" + || owningType.Name == "Popcnt" + || owningType.Name == "Bmi1" || owningType.Name == "Bmi2" + || owningType.Name == "Avx" || owningType.Name == "Avx2"; + } + + return false; + } + + // Keep this enumeration in sync with startup.cpp in the native runtime. + private static class XArchIntrinsicConstants + { + public const int Aes = 0x0001; + public const int Pclmulqdq = 0x0002; + public const int Sse3 = 0x0004; + public const int Ssse3 = 0x0008; + public const int Sse41 = 0x0010; + public const int Sse42 = 0x0020; + public const int Popcnt = 0x0040; + public const int Lzcnt = 0x0080; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/ICompilationRootProvider.cs b/src/coreclr/src/tools/Common/Compiler/ICompilationRootProvider.cs new file mode 100644 index 00000000000..8434ad8a8ac --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/ICompilationRootProvider.cs @@ -0,0 +1,18 @@ +// 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 ILCompiler +{ + /// + /// Provides a set of seeds from which compilation will start. + /// + public interface ICompilationRootProvider + { + /// + /// When implemented in a class, uses to add compilation + /// roots to the compilation. + /// + void AddCompilationRoots(IRootingServiceProvider rootProvider); + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/InternalCompilerErrorException.cs b/src/coreclr/src/tools/Common/Compiler/InternalCompilerErrorException.cs new file mode 100644 index 00000000000..06d0cf3e5df --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/InternalCompilerErrorException.cs @@ -0,0 +1,21 @@ +// 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; + +namespace ILCompiler +{ + public class InternalCompilerErrorException : Exception + { + public InternalCompilerErrorException(string message) + : this(message, innerException: null) + { + } + + public InternalCompilerErrorException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/Logger.cs b/src/coreclr/src/tools/Common/Compiler/Logger.cs new file mode 100644 index 00000000000..5fa09a1c420 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/Logger.cs @@ -0,0 +1,25 @@ +// 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.IO; + +namespace ILCompiler +{ + // Poor man's logger. We can do better than this. + + public class Logger + { + public static Logger Null = new Logger(TextWriter.Null, false); + + public TextWriter Writer { get; } + + public bool IsVerbose { get; } + + public Logger(TextWriter writer, bool isVerbose) + { + Writer = TextWriter.Synchronized(writer); + IsVerbose = isVerbose; + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/NameMangler.cs b/src/coreclr/src/tools/Common/Compiler/NameMangler.cs new file mode 100644 index 00000000000..3bd959748e2 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/NameMangler.cs @@ -0,0 +1,39 @@ +// 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 Internal.Text; +using Internal.TypeSystem; + +namespace ILCompiler +{ + // + // NameMangler is responsible for giving extern C/C++ names to managed types, methods and fields + // + // The key invariant is that the mangled names are independent on the compilation order. + // + public abstract class NameMangler + { +#if !READYTORUN + public NameMangler(NodeMangler nodeMangler) + { + nodeMangler.NameMangler = this; + NodeMangler = nodeMangler; + } + + public NodeMangler NodeMangler { get; private set; } +#endif + + public abstract string CompilationUnitPrefix { get; set; } + + public abstract string SanitizeName(string s, bool typeName = false); + + public abstract string GetMangledTypeName(TypeDesc type); + + public abstract Utf8String GetMangledMethodName(MethodDesc method); + + public abstract Utf8String GetMangledFieldName(FieldDesc field); + + public abstract string GetMangledStringName(string literal); + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/ReadyToRun.cs b/src/coreclr/src/tools/Common/Compiler/ReadyToRun.cs new file mode 100644 index 00000000000..034136734d1 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/ReadyToRun.cs @@ -0,0 +1,195 @@ +// 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. + +// +// Keep in sync with https://github.com/dotnet/coreclr/blob/master/src/inc/readytorun.h +// + +namespace ILCompiler +{ + // + // Intrinsics and helpers + // + + public enum ReadyToRunHelper + { + Invalid = 0x00, + + // Not a real helper - handle to current module passed to delay load helpers. + Module = 0x01, + GSCookie = 0x02, + + // + // Delay load helpers + // + + // All delay load helpers use custom calling convention: + // - scratch register - address of indirection cell. 0 = address is inferred from callsite. + // - stack - section index, module handle + DelayLoad_MethodCall = 0x08, + + DelayLoad_Helper = 0x10, + DelayLoad_Helper_Obj = 0x11, + DelayLoad_Helper_ObjObj = 0x12, + + // Exception handling helpers + Throw = 0x20, + Rethrow = 0x21, + Overflow = 0x22, + RngChkFail = 0x23, + FailFast = 0x24, + ThrowNullRef = 0x25, + ThrowDivZero = 0x26, + + // Write barriers + WriteBarrier = 0x30, + CheckedWriteBarrier = 0x31, + ByRefWriteBarrier = 0x32, + + // Array helpers + Stelem_Ref = 0x38, + Ldelema_Ref = 0x39, + + MemSet = 0x40, + MemCpy = 0x41, + + // P/Invoke support + PInvokeBegin = 0x42, + PInvokeEnd = 0x43, + + // Get string handle lazily + GetString = 0x50, + + // Used by /Tuning for Profile optimizations + LogMethodEnter = 0x51, + + // Reflection helpers + GetRuntimeTypeHandle = 0x54, + GetRuntimeMethodHandle = 0x55, + GetRuntimeFieldHandle = 0x56, + + Box = 0x58, + Box_Nullable = 0x59, + Unbox = 0x5A, + Unbox_Nullable = 0x5B, + NewMultiDimArr = 0x5C, + NewMultiDimArr_NonVarArg = 0x5D, + + // Helpers used with generic handle lookup cases + NewObject = 0x60, + NewArray = 0x61, + CheckCastAny = 0x62, + CheckInstanceAny = 0x63, + GenericGcStaticBase = 0x64, + GenericNonGcStaticBase = 0x65, + GenericGcTlsBase = 0x66, + GenericNonGcTlsBase = 0x67, + VirtualFuncPtr = 0x68, + + // Long mul/div/shift ops + LMul = 0xC0, + LMulOfv = 0xC1, + ULMulOvf = 0xC2, + LDiv = 0xC3, + LMod = 0xC4, + ULDiv = 0xC5, + ULMod = 0xC6, + LLsh = 0xC7, + LRsh = 0xC8, + LRsz = 0xC9, + Lng2Dbl = 0xCA, + ULng2Dbl = 0xCB, + + // 32-bit division helpers + Div = 0xCC, + Mod = 0xCD, + UDiv = 0xCE, + UMod = 0xCF, + + // Floating point conversions + Dbl2Int = 0xD0, + Dbl2IntOvf = 0xD1, + Dbl2Lng = 0xD2, + Dbl2LngOvf = 0xD3, + Dbl2UInt = 0xD4, + Dbl2UIntOvf = 0xD5, + Dbl2ULng = 0xD6, + Dbl2ULngOvf = 0xD7, + + // Floating point ops + DblRem = 0xE0, + FltRem = 0xE1, + DblRound = 0xE2, + FltRound = 0xE3, + + // Personality rountines + PersonalityRoutine = 0xF0, + PersonalityRoutineFilterFunclet = 0xF1, + + // Synchronized methods + MonitorEnter = 0xF8, + MonitorExit = 0xF9, + + // JIT32 x86-specific write barriers + WriteBarrier_EAX = 0x100, + WriteBarrier_EBX = 0x101, + WriteBarrier_ECX = 0x102, + WriteBarrier_ESI = 0x103, + WriteBarrier_EDI = 0x104, + WriteBarrier_EBP = 0x105, + CheckedWriteBarrier_EAX = 0x106, + CheckedWriteBarrier_EBX = 0x107, + CheckedWriteBarrier_ECX = 0x108, + CheckedWriteBarrier_ESI = 0x109, + CheckedWriteBarrier_EDI = 0x10A, + CheckedWriteBarrier_EBP = 0x10B, + + // JIT32 x86-specific exception handling + EndCatch = 0x110, + + StackProbe = 0x111, + + // ********************************************************************************************** + // + // These are not actually part of the R2R file format. We have them here because it's convenient. + // + // ********************************************************************************************** + + // Marker to be used in asserts. + FirstFakeHelper, + + ThrowArgumentOutOfRange, + ThrowArgument, + ThrowPlatformNotSupported, + ThrowNotImplemented, + + DebugBreak, + + GetRuntimeType, + + AreTypesEquivalent, + + CheckCastClass, + CheckInstanceClass, + CheckCastArray, + CheckInstanceArray, + CheckCastInterface, + CheckInstanceInterface, + + // P/Invoke support + ReversePInvokeEnter, + ReversePInvokeExit, + + MonitorEnterStatic, + MonitorExitStatic, + + // GVM lookup helper + GVMLookupForSlot, + + // TypedReference + TypeHandleToRuntimeType, + GetRefAny, + TypeHandleToRuntimeTypeHandle, + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/SingleMethodRootProvider.cs b/src/coreclr/src/tools/Common/Compiler/SingleMethodRootProvider.cs new file mode 100644 index 00000000000..c1d9f484e0b --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/SingleMethodRootProvider.cs @@ -0,0 +1,26 @@ +// 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 Internal.TypeSystem; + +namespace ILCompiler +{ + /// + /// Compilation root that is a single method. + /// + public class SingleMethodRootProvider : ICompilationRootProvider + { + private MethodDesc _method; + + public SingleMethodRootProvider(MethodDesc method) + { + _method = method; + } + + public void AddCompilationRoots(IRootingServiceProvider rootProvider) + { + rootProvider.AddCompilationRoot(_method, "Single method root"); + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/TypeExtensions.cs b/src/coreclr/src/tools/Common/Compiler/TypeExtensions.cs new file mode 100644 index 00000000000..0514b24488c --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/TypeExtensions.cs @@ -0,0 +1,506 @@ +// 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.IL; +using Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler +{ + public static class TypeExtensions + { + public static bool IsSealed(this TypeDesc type) + { + var metadataType = type as MetadataType; + if (metadataType != null) + { + return metadataType.IsSealed || metadataType.IsModuleType; + } + + Debug.Assert(type.IsArray, "IsSealed on a type with no virtual methods?"); + return true; + } + + /// + /// Gets the type that defines virtual method slots for the specified type. + /// + public static DefType GetClosestDefType(this TypeDesc type) + { + if (type.IsArray) + { + if (!type.IsArrayTypeWithoutGenericInterfaces()) + { + MetadataType arrayShadowType = type.Context.SystemModule.GetType("System", "Array`1", throwIfNotFound: false); + if (arrayShadowType != null) + { + return arrayShadowType.MakeInstantiatedType(((ArrayType)type).ElementType); + } + } + + return type.Context.GetWellKnownType(WellKnownType.Array); + } + + Debug.Assert(type is DefType); + return (DefType)type; + } + + /// + /// Gets a value indicating whether the method requires a hidden instantiation argument in addition + /// to the formal arguments defined in the method signature. + /// + public static bool RequiresInstArg(this MethodDesc method) + { + return method.IsSharedByGenericInstantiations && + (method.HasInstantiation || method.Signature.IsStatic || method.ImplementationType.IsValueType || (method.ImplementationType.IsInterface && !method.IsAbstract)); + } + + /// + /// Gets a value indicating whether the method acquires the generic context from a hidden + /// instantiation argument that points to the method's generic dictionary. + /// + public static bool RequiresInstMethodDescArg(this MethodDesc method) + { + return method.HasInstantiation && method.IsSharedByGenericInstantiations; + } + + /// + /// Gets a value indicating whether the method acquires the generic context from a hidden + /// instantiation argument that points to the generic dictionary of the method's owning type. + /// + public static bool RequiresInstMethodTableArg(this MethodDesc method) + { + return (method.Signature.IsStatic || method.ImplementationType.IsValueType || (method.ImplementationType.IsInterface && !method.IsAbstract)) && + method.IsSharedByGenericInstantiations && + !method.HasInstantiation; + } + + /// + /// Gets a value indicating whether the method acquires the generic context from the this pointer. + /// + public static bool AcquiresInstMethodTableFromThis(this MethodDesc method) + { + return method.IsSharedByGenericInstantiations && + !method.HasInstantiation && + !method.Signature.IsStatic && + !method.ImplementationType.IsValueType && + !(method.ImplementationType.IsInterface && !method.IsAbstract); + } + + /// + /// Returns true if '' is the "Address" method on multidimensional array types. + /// + public static bool IsArrayAddressMethod(this MethodDesc method) + { + var arrayMethod = method as ArrayMethod; + return arrayMethod != null && arrayMethod.Kind == ArrayMethodKind.Address; + } + + /// + /// Gets a value indicating whether this type has any generic virtual methods. + /// + public static bool HasGenericVirtualMethods(this TypeDesc type) + { + foreach (var method in type.GetAllMethods()) + { + if (method.IsVirtual && method.HasInstantiation) + return true; + } + + return false; + } + + /// + /// Wrapper helper function around the IsCanonicalDefinitionType API on the TypeSystemContext + /// + public static bool IsCanonicalDefinitionType(this TypeDesc type, CanonicalFormKind kind) + { + return type.Context.IsCanonicalDefinitionType(type, kind); + } + + /// + /// Gets the value of the field ordinal. Ordinals are computed by also including static fields, but excluding + /// literal fields and fields with RVAs. + /// + public static int GetFieldOrdinal(this FieldDesc inputField) + { + // Make sure we are asking the question for a valid instance or static field + Debug.Assert(!inputField.HasRva && !inputField.IsLiteral); + + int fieldOrdinal = 0; + foreach (FieldDesc field in inputField.OwningType.GetFields()) + { + // If this field does not contribute to layout, skip + if (field.HasRva || field.IsLiteral) + continue; + + if (field == inputField) + return fieldOrdinal; + + fieldOrdinal++; + } + + Debug.Assert(false); + return -1; + } + + /// + /// What is the maximum number of steps that need to be taken from this type to its most contained generic type. + /// i.e. + /// System.Int32 => 0 + /// List<System.Int32> => 1 + /// Dictionary<System.Int32,System.Int32> => 1 + /// Dictionary<List<System.Int32>,<System.Int32> => 2 + /// + public static int GetGenericDepth(this TypeDesc type) + { + if (type.HasInstantiation) + { + int maxGenericDepthInInstantiation = 0; + foreach (TypeDesc instantiationType in type.Instantiation) + { + maxGenericDepthInInstantiation = Math.Max(instantiationType.GetGenericDepth(), maxGenericDepthInInstantiation); + } + + return maxGenericDepthInInstantiation + 1; + } + + return 0; + } + + /// + /// Determine if a type has a generic depth greater than a given value + /// + public static bool IsGenericDepthGreaterThan(this TypeDesc type, int depth) + { + if (depth < 0) + return true; + + foreach (TypeDesc instantiationType in type.Instantiation) + { + if (instantiationType.IsGenericDepthGreaterThan(depth - 1)) + return true; + } + + return false; + } + + /// + /// Determines whether an array type does implements the generic collection interfaces. This is the case + /// for multi-dimensional arrays, and arrays of pointers. + /// + public static bool IsArrayTypeWithoutGenericInterfaces(this TypeDesc type) + { + if (!type.IsArray) + return false; + + var arrayType = (ArrayType)type; + TypeDesc elementType = arrayType.ElementType; + return type.IsMdArray || elementType.IsPointer || elementType.IsFunctionPointer; + } + + /// + /// Determines whether an object of type '' requires 8-byte alignment on + /// 32bit ARM architectures. + /// + public static bool RequiresAlign8(this TypeDesc type) + { + if (type.Context.Target.Architecture != TargetArchitecture.ARM) + { + return false; + } + + if (type.IsArray) + { + var elementType = ((ArrayType)type).ElementType; + if ((elementType.IsValueType) && ((DefType)elementType).InstanceByteAlignment.AsInt > 4) + { + return true; + } + } + else if (type.IsDefType && ((DefType)type).InstanceByteAlignment.AsInt > 4) + { + return true; + } + + return false; + } + + public static TypeDesc MergeTypesToCommonParent(TypeDesc ta, TypeDesc tb) + { + if (ta == tb) + { + return ta; + } + + // Handle the array case + if (ta.IsArray) + { + if (tb.IsArray) + { + return MergeArrayTypesToCommonParent((ArrayType)ta, (ArrayType)tb); + } + else if (tb.IsInterface) + { + // Check to see if we can merge the array to a common interface (such as Derived[] and IList) + if (ta.CanCastTo(tb)) + { + return tb; + } + } + // keep merging from here + ta = ta.Context.GetWellKnownType(WellKnownType.Array); + } + else if (tb.IsArray) + { + if (ta.IsInterface && tb.CanCastTo(ta)) + { + return ta; + } + + tb = tb.Context.GetWellKnownType(WellKnownType.Array); + } + + Debug.Assert(ta.IsDefType); + Debug.Assert(tb.IsDefType); + + if (tb.IsInterface) + { + if (ta.IsInterface) + { + // + // Both classes are interfaces. Check that if one + // interface extends the other. + // + // Does tb extend ta ? + // + if (tb.ImplementsEquivalentInterface(ta)) + { + return ta; + } + + // + // Does tb extend ta ? + // + if (ta.ImplementsEquivalentInterface(tb)) + { + return tb; + } + + // No compatible merge found - using Object + return ta.Context.GetWellKnownType(WellKnownType.Object); + } + else + { + return MergeClassWithInterface(ta, tb); + } + } + else if (ta.IsInterface) + { + return MergeClassWithInterface(tb, ta); + } + + int aDepth = 0; + int bDepth = 0; + + // find the depth in the class hierarchy for each class + for (TypeDesc searchType = ta; searchType != null; searchType = searchType.BaseType) + { + aDepth++; + } + + for (TypeDesc searchType = tb; searchType != null; searchType = searchType.BaseType) + { + bDepth++; + } + + // for whichever class is lower down in the hierarchy, walk up the superclass chain + // to the same level as the other class + while (aDepth > bDepth) + { + ta = ta.BaseType; + aDepth--; + } + + while (bDepth > aDepth) + { + tb = tb.BaseType; + bDepth--; + } + + while (ta != tb) + { + ta = ta.BaseType; + tb = tb.BaseType; + } + + // If no compatible merge is found, we end up using Object + + Debug.Assert(ta != null); + + return ta; + } + + private static TypeDesc MergeArrayTypesToCommonParent(ArrayType ta, ArrayType tb) + { + Debug.Assert(ta.IsArray && tb.IsArray && ta != tb); + + // if no match on the rank the common ancestor is System.Array + if (ta.IsSzArray != tb.IsSzArray || ta.Rank != tb.Rank) + { + return ta.Context.GetWellKnownType(WellKnownType.Array); + } + + TypeDesc taElem = ta.ElementType; + TypeDesc tbElem = tb.ElementType; + Debug.Assert(taElem != tbElem); + + TypeDesc mergeElem; + if (taElem.IsArray && tbElem.IsArray) + { + mergeElem = MergeArrayTypesToCommonParent((ArrayType)taElem, (ArrayType)tbElem); + } + else if (taElem.IsGCPointer && tbElem.IsGCPointer) + { + // Find the common ancestor of the element types. + mergeElem = MergeTypesToCommonParent(taElem, tbElem); + } + else + { + // The element types have nothing in common. + return ta.Context.GetWellKnownType(WellKnownType.Array); + } + + if (mergeElem == taElem) + { + return ta; + } + + if (mergeElem == tbElem) + { + return tb; + } + + if (taElem.IsMdArray) + { + return mergeElem.MakeArrayType(ta.Rank); + } + + return mergeElem.MakeArrayType(); + } + + private static bool ImplementsEquivalentInterface(this TypeDesc type, TypeDesc interfaceType) + { + foreach (DefType implementedInterface in type.RuntimeInterfaces) + { + if (implementedInterface == interfaceType) + { + return true; + } + } + + return false; + } + + private static TypeDesc MergeClassWithInterface(TypeDesc type, TypeDesc interfaceType) + { + // Check if the class implements the interface + if (type.ImplementsEquivalentInterface(interfaceType)) + { + return interfaceType; + } + + // Check if the class and the interface implement a common interface + foreach (var potentialCommonInterface in interfaceType.RuntimeInterfaces) + { + if (type.ImplementsEquivalentInterface(potentialCommonInterface)) + { + // Found a common interface. If there are multiple common interfaces, then + // the problem is ambiguous so we'll just take the first one--it's the best + // we can do. + return potentialCommonInterface; + } + } + + // No compatible merge found - using Object + return type.Context.GetWellKnownType(WellKnownType.Object); + } + + /// + /// Normalizes canonical instantiations (converts Foo<object, __Canon> to + /// Foo<__Canon, __Canon>). Returns identity for non-canonical types. + /// + public static TypeDesc NormalizeInstantiation(this TypeDesc thisType) + { + if (thisType.IsCanonicalSubtype(CanonicalFormKind.Any)) + return thisType.ConvertToCanonForm(CanonicalFormKind.Specific); + + return thisType; + } + + public static Instantiation GetInstantiationThatMeetsConstraints(Instantiation inst, bool allowCanon) + { + TypeDesc[] resultArray = new TypeDesc[inst.Length]; + for (int i = 0; i < inst.Length; i++) + { + TypeDesc instArg = GetTypeThatMeetsConstraints((GenericParameterDesc)inst[i], allowCanon); + if (instArg == null) + return default(Instantiation); + resultArray[i] = instArg; + } + + return new Instantiation(resultArray); + } + + private static TypeDesc GetTypeThatMeetsConstraints(GenericParameterDesc genericParam, bool allowCanon) + { + TypeSystemContext context = genericParam.Context; + + // Universal canon is the best option if it's supported + if (allowCanon && context.SupportsUniversalCanon) + return context.UniversalCanonType; + + // Not nullable type is the only thing where we can't substitute reference types + GenericConstraints constraints = genericParam.Constraints; + if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) + return null; + + // If canon is allowed, we can use that + if (allowCanon && context.SupportsCanon) + { + foreach (var c in genericParam.TypeConstraints) + { + // Could be e.g. "where T : U" + // We could try to dig into the U and solve it, but that just opens us up to + // recursion and it's just not worth it. + if (c.IsSignatureVariable) + return null; + + if (!c.IsGCPointer) + return null; + } + + return genericParam.Context.CanonType; + } + + // If canon is not allowed, we're limited in our choices. + TypeDesc constrainedType = null; + foreach (var c in genericParam.TypeConstraints) + { + // Can't do multiple constraints + if (constrainedType != null) + return null; + + // Could be e.g. "where T : IFoo" or "where T : U" + if (c.ContainsSignatureVariables()) + return null; + + constrainedType = c; + } + + return constrainedType ?? genericParam.Context.GetWellKnownType(WellKnownType.Object); + } + } +} diff --git a/src/coreclr/src/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs new file mode 100644 index 00000000000..f52f18cf842 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs @@ -0,0 +1,115 @@ +// 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 Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler +{ + /// + /// Represents an algorithm that computes field layout for intrinsic vector types (Vector64/Vector128/Vector256). + /// + public class VectorFieldLayoutAlgorithm : FieldLayoutAlgorithm + { + private readonly FieldLayoutAlgorithm _fallbackAlgorithm; + + public VectorFieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm) + { + _fallbackAlgorithm = fallbackAlgorithm; + } + + public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind) + { + Debug.Assert(IsVectorType(defType)); + + LayoutInt alignment; + + string name = defType.Name; + if (name == "Vector64`1") + { + alignment = new LayoutInt(8); + } + else if (name == "Vector128`1") + { + if (defType.Context.Target.Architecture == TargetArchitecture.ARM) + { + // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128 + alignment = new LayoutInt(8); + } + else + { + alignment = new LayoutInt(16); + } + } + else + { + Debug.Assert(name == "Vector256`1"); + + if (defType.Context.Target.Architecture == TargetArchitecture.ARM) + { + // No such type exists for the Procedure Call Standard for ARM. We will default + // to the same alignment as __m128, which is supported by the ABI. + alignment = new LayoutInt(8); + } + else if (defType.Context.Target.Architecture == TargetArchitecture.ARM64) + { + // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to + // 16-byte alignment for __m256. + alignment = new LayoutInt(16); + } + else + { + alignment = new LayoutInt(32); + } + } + + ComputedInstanceFieldLayout layoutFromMetadata = _fallbackAlgorithm.ComputeInstanceLayout(defType, layoutKind); + + return new ComputedInstanceFieldLayout + { + ByteCountUnaligned = layoutFromMetadata.ByteCountUnaligned, + ByteCountAlignment = layoutFromMetadata.ByteCountAlignment, + FieldAlignment = alignment, + FieldSize = layoutFromMetadata.FieldSize, + Offsets = layoutFromMetadata.Offsets, + }; + } + + public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind) + { + return _fallbackAlgorithm.ComputeStaticFieldLayout(defType, layoutKind); + } + + public override bool ComputeContainsGCPointers(DefType type) + { + Debug.Assert(!_fallbackAlgorithm.ComputeContainsGCPointers(type)); + return false; + } + + public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) + { + return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type); + } + + public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) + { + return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type); + } + + public static bool IsVectorType(DefType type) + { + return type.IsIntrinsic && + type.Namespace == "System.Runtime.Intrinsics" && + (type.Name == "Vector64`1" || + type.Name == "Vector128`1" || + type.Name == "Vector256`1"); + } + + public static bool IsVectorOfTType(DefType type) + { + return type.IsIntrinsic && type.Namespace == "System.Numerics" && type.Name == "Vector`1"; + } + } +} diff --git a/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormat.cs b/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormat.cs new file mode 100644 index 00000000000..3c8539adcfe --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormat.cs @@ -0,0 +1,232 @@ +// 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; + +// +// Native Format +// +// NativeFormat is a binary metadata format. It primarily designed for storing layout decisions done by static code +// generator that the dynamic code generator needs to be aware of. However, it can be also used for storing general +// managed code metadata in future. The key properties of the format are: +// +// - Extensible: It should be possible to attach new data to existing records without breaking existing consumers that +// do not understand the new data yet. +// +// - Naturally compressed: Integers are stored using variable length encoding. Offsets are stored as relative offsets. +// +// - Random access: Random access to selected information should be fast. It is achieved by using tokens as offsets. +// +// - Locality: Access to related information should be accessing data that are close to each other. +// +// The format is essentially a collection of variable size records that can reference each other. +// + +namespace Internal.NativeFormat +{ + // + // Bag is the key record type for extensibility. It is a list pairs. Data is integer that + // is interpretted according to the id. It is typically relative offset of another record. + // +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum BagElementKind : uint + { + End = 0x00, + BaseType = 0x01, + ImplementedInterfaces = 0x02, + + DictionaryLayout = 0x40, + TypeFlags = 0x41, + NonGcStaticData = 0x42, + GcStaticData = 0x43, + NonGcStaticDataSize = 0x44, + GcStaticDataSize = 0x45, + GcStaticDesc = 0x46, + ThreadStaticDataSize = 0x47, + ThreadStaticDesc = 0x48, + ThreadStaticIndex = 0x49, + ThreadStaticOffset = 0x4a, + FieldLayout = 0x4b, + VTableMethodSignatures = 0x4c, + SealedVTableEntries = 0x4d, + ClassConstructorPointer = 0x4e, + BaseTypeSize = 0x4f, + GenericVarianceInfo = 0x50, + DelegateInvokeSignature = 0x51, + GcStaticEEType = 0x52, + + // Add new custom bag elements that don't match to something you'd find in the ECMA metadata here. + } + + // + // FixupSignature signature describes indirection. It starts with integer describing the kind of data stored in the indirection, + // followed by kind-specific signature. + // +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum FixupSignatureKind : uint + { + Null = 0x00, + TypeHandle = 0x01, + InterfaceCall = 0x02, + // unused = 0x03, + MethodDictionary = 0x04, + StaticData = 0x05, + UnwrapNullableType = 0x06, + FieldLdToken = 0x07, + MethodLdToken = 0x08, + AllocateObject = 0x09, + DefaultConstructor = 0x0a, + TlsIndex = 0x0b, + TlsOffset = 0x0c, + Method = 0x0d, + IsInst = 0x0e, + CastClass = 0x0f, + AllocateArray = 0x10, + CheckArrayElementType = 0x11, + TypeSize = 0x12, + FieldOffset = 0x13, + CallingConventionConverter = 0x14, + VTableOffset = 0x15, + NonGenericConstrainedMethod = 0x16, + GenericConstrainedMethod = 0x17, + NonGenericDirectConstrainedMethod = 0x18, + PointerToOtherSlot = 0x19, + IntValue = 0x20, + + NotYetSupported = 0xee, + } + + // + // TypeSignature describes type. The low 4 bits of the integer that is starts with describe the kind. Upper 28 bits are kind + // specific data. The argument signatures immediately follow for nested types. + // +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum TypeSignatureKind : uint + { + Null = 0x0, + Lookback = 0x1, // Go back in the stream for signature continuation (data - number of bytes to go back) + Modifier = 0x2, // Type modifier (data - TypeModifierKind) + Instantiation = 0x3, // Generic instantiation (data - number of instantiation args) + Variable = 0x4, // Generic variable (data - 2 * varnum + method) + BuiltIn = 0x5, // Built-in type (data - BuildInTypeKind) + External = 0x6, // External type reference (data - external type id) + + MultiDimArray = 0xA, // Multi-dimensional array (data - dimension) + FunctionPointer = 0xB, // Function pointer (data - calling convention, arg count, args) + }; + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum TypeModifierKind : uint + { + Array = 0x1, + ByRef = 0x2, + Pointer = 0x3, + }; + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum StaticDataKind : uint + { + Gc = 0x1, + NonGc = 0x2, + }; + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum GenericContextKind : uint + { + FromThis = 0x00, + FromHiddenArg = 0x01, + FromMethodHiddenArg = 0x02, + + HasDeclaringType = 0x04, + + NeedsUSGContext = 0x08, + }; + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum CallingConventionConverterKind : uint + { + NoInstantiatingParam = 0x00, // The calling convention interpreter can assume that the calling convention of the target method has no instantiating parameter + HasInstantiatingParam = 0x01, // The calling convention interpreter can assume that the calling convention of the target method has an instantiating parameter + MaybeInstantiatingParam = 0x02, // The calling convention interpreter can assume that the calling convention of the target method may be a fat function pointer + } + + [Flags] +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum TypeFlags : uint + { + HasClassConstructor = 0x1, + HasInstantiationDeterminedSize = 0x2, + }; + + [Flags] +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum MethodFlags : uint + { + HasInstantiation = 0x1, + IsUnboxingStub = 0x2, + HasFunctionPointer = 0x4, + FunctionPointerIsUSG = 0x8, + }; + + [Flags] +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum MethodCallingConvention : uint + { + Generic = 0x1, + Static = 0x2, + }; + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + enum FieldStorage : uint + { + Instance = 0x0, + NonGCStatic = 0x1, + GCStatic = 0x2, + TLSStatic = 0x3, + } +} diff --git a/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormatWriter.Primitives.cs b/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormatWriter.Primitives.cs new file mode 100644 index 00000000000..52a917c9a9c --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormatWriter.Primitives.cs @@ -0,0 +1,198 @@ +// 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.IO; +using System.Diagnostics; + +namespace Internal.NativeFormat +{ + internal struct NativePrimitiveEncoder + { + private byte[] _buffer; + private int _size; + + public void Init() + { + _buffer = new byte[128]; + _size = 0; + } + + public int Size { get { return _size; } } + public void Clear() { _size = 0; } + public void RollbackTo(int offset) { _size = offset; } + + public void WriteByte(byte b) + { + if (_buffer.Length == _size) + Array.Resize(ref _buffer, 2 * _buffer.Length); + _buffer[_size++] = b; + } + + public void WriteUInt8(byte value) + { + WriteByte(value); + } + + public void WriteUInt16(ushort value) + { + WriteByte((byte)value); + WriteByte((byte)(value >> 8)); + } + + public void WriteUInt32(uint value) + { + WriteByte((byte)value); + WriteByte((byte)(value >> 8)); + WriteByte((byte)(value >> 16)); + WriteByte((byte)(value >> 24)); + } + + public void WriteUInt64(ulong value) + { + WriteUInt32((uint)value); + WriteUInt32((uint)(value >> 32)); + } + + public unsafe void WriteFloat(float value) + { + WriteUInt32(*((uint*)&value)); + } + + public unsafe void WriteDouble(double value) + { + WriteUInt64(*((ulong*)&value)); + } + + // + // Same encoding as what's used by CTL + // + public void WriteUnsigned(uint d) + { + if (d < 128) + { + WriteByte((byte)(d * 2 + 0)); + } + else if (d < 128 * 128) + { + WriteByte((byte)(d * 4 + 1)); + WriteByte((byte)(d >> 6)); + } + else if (d < 128 * 128 * 128) + { + WriteByte((byte)(d * 8 + 3)); + WriteByte((byte)(d >> 5)); + WriteByte((byte)(d >> 13)); + } + else if (d < 128 * 128 * 128 * 128) + { + WriteByte((byte)(d * 16 + 7)); + WriteByte((byte)(d >> 4)); + WriteByte((byte)(d >> 12)); + WriteByte((byte)(d >> 20)); + } + else + { + WriteByte((byte)15); + WriteUInt32(d); + } + } + + public static int GetUnsignedEncodingSize(uint d) + { + if (d < 128) return 1; + if (d < 128 * 128) return 2; + if (d < 128 * 128 * 128) return 3; + if (d < 128 * 128 * 128 * 128) return 4; + return 5; + } + + public void WriteSigned(int i) + { + uint d = (uint)i; + if (d + 64 < 128) + { + WriteByte((byte)(d * 2 + 0)); + } + else if (d + 64 * 128 < 128 * 128) + { + WriteByte((byte)(d * 4 + 1)); + WriteByte((byte)(d >> 6)); + } + else if (d + 64 * 128 * 128 < 128 * 128 * 128) + { + WriteByte((byte)(d * 8 + 3)); + WriteByte((byte)(d >> 5)); + WriteByte((byte)(d >> 13)); + } + else if (d + 64 * 128 * 128 * 128 < 128 * 128 * 128 * 128) + { + WriteByte((byte)(d * 16 + 7)); + WriteByte((byte)(d >> 4)); + WriteByte((byte)(d >> 12)); + WriteByte((byte)(d >> 20)); + } + else + { + WriteByte((byte)15); + WriteUInt32(d); + } + } + + public void WriteUnsignedLong(ulong i) + { + if ((uint)i == i) + { + WriteUnsigned((uint)i); + return; + } + + WriteByte((byte)31); + WriteUInt64(i); + } + + public void WriteSignedLong(long i) + { + if ((int)i == i) + { + WriteSigned((int)i); + return; + } + + WriteByte((byte)31); + WriteUInt64((ulong)i); + } + + public void PatchByteAt(int offset, byte value) + { + Debug.Assert(offset < _size); + _buffer[offset] = value; + } + + public void Save(Stream stream) + { + stream.Write(_buffer, 0, _size); + } + + public unsafe bool Save(byte* stream, int streamLength) + { + if (streamLength < _size) + { + Debug.Assert(false); + return false; + } + for (int i = 0; i < _size; i++) + stream[i] = _buffer[i]; + return true; + } + + public byte[] GetBytes() + { + byte[] retBuffer = new byte[_size]; + for (int i = 0; i < _size; i++) + retBuffer[i] = _buffer[i]; + return retBuffer; + } + } +} diff --git a/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormatWriter.cs b/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormatWriter.cs new file mode 100644 index 00000000000..c170e3707f8 --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/NativeFormat/NativeFormatWriter.cs @@ -0,0 +1,2147 @@ +// 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.IO; +using System.Diagnostics; +using System.Collections.Generic; +using System.Text; + +// Managed mirror of NativeFormatWriter.h/.cpp +namespace Internal.NativeFormat +{ +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + abstract class Vertex + { + internal int _offset = NotPlaced; + internal int _iteration = -1; // Iteration that the offset is valid for + + internal const int NotPlaced = -1; + internal const int Placed = -2; + internal const int Unified = -3; + + public Vertex() + { + } + + internal abstract void Save(NativeWriter writer); + + public int VertexOffset + { + get + { + Debug.Assert(_offset >= 0); + return _offset; + } + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class Section + { + internal List _items = new List(); + internal Dictionary _placedMap = new Dictionary(); + + public Section() + { + } + + public Vertex Place(Vertex vertex) + { + if (vertex._offset == Vertex.Unified) + { + Vertex placedVertex; + if (_placedMap.TryGetValue(vertex, out placedVertex)) + return placedVertex; + + placedVertex = new PlacedVertex(vertex); + _placedMap.Add(vertex, placedVertex); + vertex = placedVertex; + } + + Debug.Assert(vertex._offset == Vertex.NotPlaced); + vertex._offset = Vertex.Placed; + _items.Add(vertex); + + return vertex; + } + + public Vertex Pop() + { + Vertex vertex = _items[_items.Count - 1]; + _items.RemoveAt(_items.Count - 1); + Debug.Assert(vertex._offset == Vertex.Placed); + vertex._offset = Vertex.NotPlaced; + return vertex; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class NativeWriter + { + List
_sections = new List
(); + + enum SavePhase + { + Initial, + Shrinking, + Growing + } + + + int _iteration = 0; + SavePhase _phase; // Current save phase + int _offsetAdjustment; // Cumulative offset adjustment compared to previous iteration + int _paddingSize; // How much padding was used + + Dictionary _unifier = new Dictionary(); + + NativePrimitiveEncoder _encoder = new NativePrimitiveEncoder(); + +#if NATIVEFORMAT_COMPRESSION + struct Tentative + { + internal Vertex Vertex; + internal int PreviousOffset; + } + + // State used by compression + List _tentativelyWritten = new List(); // Tentatively written Vertices. + int _compressionDepth = 0; +#endif + + public NativeWriter() + { + _encoder.Init(); + } + + public Section NewSection() + { + Section section = new Section(); + _sections.Add(section); + return section; + } + + public void WriteByte(byte b) { _encoder.WriteByte(b); } + public void WriteUInt8(byte value) { _encoder.WriteUInt8(value); } + public void WriteUInt16(ushort value) { _encoder.WriteUInt16(value); } + public void WriteUInt32(uint value) { _encoder.WriteUInt32(value); } + public void WriteUInt64(ulong value) { _encoder.WriteUInt64(value); } + public void WriteUnsigned(uint d) { _encoder.WriteUnsigned(d); } + public void WriteSigned(int i) { _encoder.WriteSigned(i); } + public void WriteUnsignedLong(ulong i) { _encoder.WriteUnsignedLong(i); } + public void WriteSignedLong(long i) { _encoder.WriteSignedLong(i); } + public void WriteFloat(float value) { _encoder.WriteFloat(value); } + public void WriteDouble(double value) { _encoder.WriteDouble(value); } + + public void WritePad(int size) + { + while (size > 0) + { + _encoder.WriteByte(0); + size--; + } + } + + public bool IsGrowing() + { + return _phase == SavePhase.Growing; + } + + public void UpdateOffsetAdjustment(int offsetDelta) + { + switch (_phase) + { + case SavePhase.Shrinking: + _offsetAdjustment = Math.Min(_offsetAdjustment, offsetDelta); + break; + case SavePhase.Growing: + _offsetAdjustment = Math.Max(_offsetAdjustment, offsetDelta); + break; + default: + break; + } + } + + public void RollbackTo(int offset) + { + _encoder.RollbackTo(offset); + } + + public void RollbackTo(int offset, int offsetAdjustment) + { + _offsetAdjustment = offsetAdjustment; + RollbackTo(offset); + } + + public void PatchByteAt(int offset, byte value) + { + _encoder.PatchByteAt(offset, value); + } + + // Swallow exceptions if invalid encoding is detected. + // This is the price we have to pay for using UTF8. Thing like High Surrogate Start Char - '\ud800' + // can be expressed in UTF-16 (which is the format used to store ECMA metadata), but don't have + // a representation in UTF-8. + private static Encoding _stringEncoding = new UTF8Encoding(false, false); + + public void WriteString(string s) + { + // The actual bytes are only necessary for the final version during the growing plase + if (IsGrowing()) + { + byte[] bytes = _stringEncoding.GetBytes(s); + + _encoder.WriteUnsigned((uint)bytes.Length); + for (int i = 0; i < bytes.Length; i++) + _encoder.WriteByte(bytes[i]); + } + else + { + int byteCount = _stringEncoding.GetByteCount(s); + _encoder.WriteUnsigned((uint)byteCount); + WritePad(byteCount); + } + } + + public void WriteRelativeOffset(Vertex val) + { + if (val._iteration == -1) + { + // If the offsets are not determined yet, use the maximum possible encoding + _encoder.WriteSigned(0x7FFFFFFF); + return; + } + + int offset = val._offset; + + // If the offset was not update in this iteration yet, adjust it by delta we have accumulated in this iteration so far. + // This adjustment allows the offsets to converge faster. + if (val._iteration < _iteration) + offset += _offsetAdjustment; + + _encoder.WriteSigned(offset - GetCurrentOffset()); + } + + public int GetExpectedOffset(Vertex val) + { + Debug.Assert(val._offset != Vertex.NotPlaced); + + if (val._iteration == -1) + { + // If the offsets are not determined yet, use the maximum possible encoding + return 0x7FFFFFFF; + } + + int offset = val._offset; + + // If the offset was not update in this iteration yet, adjust it by delta we have accumulated in this iteration so far. + // This adjustment allows the offsets to converge faster. + if (val._iteration < _iteration) + offset += _offsetAdjustment; + + return offset; + } + + public int GetCurrentOffset(Vertex val) + { + if (val._iteration != _iteration) + return -1; + + return val._offset; + } + + public int GetCurrentOffset() + { + return _encoder.Size; + } + + public int GetNumberOfIterations() + { + return _iteration; + } + + public int GetPaddingSize() + { + return _paddingSize; + } + + public void Save(Stream stream) + { + _encoder.Clear(); + + _phase = SavePhase.Initial; + foreach (var section in _sections) foreach (var vertex in section._items) + { + vertex._offset = GetCurrentOffset(); + vertex._iteration = _iteration; + vertex.Save(this); + +#if NATIVEFORMAT_COMPRESSION + // Ensure that the compressor state is fully flushed + Debug.Assert(_TentativelyWritten.Count == 0); + Debug.Assert(_compressionDepth == 0); +#endif + } + + // Aggressive phase that only allows offsets to shrink. + _phase = SavePhase.Shrinking; + for (; ; ) + { + _iteration++; + _encoder.Clear(); + + _offsetAdjustment = 0; + + foreach (var section in _sections) foreach (var vertex in section._items) + { + int currentOffset = GetCurrentOffset(); + + // Only allow the offsets to shrink. + _offsetAdjustment = Math.Min(_offsetAdjustment, currentOffset - vertex._offset); + + vertex._offset += _offsetAdjustment; + + if (vertex._offset < currentOffset) + { + // It is possible for the encoding of relative offsets to grow during some iterations. + // Ignore this growth because of it should disappear during next iteration. + RollbackTo(vertex._offset); + } + Debug.Assert(vertex._offset == GetCurrentOffset()); + + vertex._iteration = _iteration; + + vertex.Save(this); + +#if NATIVEFORMAT_COMPRESSION + // Ensure that the compressor state is fully flushed + Debug.Assert(_tentativelyWritten.Count == 0); + Debug.Assert(_compressionDepth == 0); +#endif + } + + // We are not able to shrink anymore. We cannot just return here. It is possible that we have rolledback + // above because of we shrinked too much. + if (_offsetAdjustment == 0) + break; + + // Limit number of shrinking interations. This limit is meant to be hit in corner cases only. + if (_iteration > 10) + break; + } + + // Conservative phase that only allows the offsets to grow. It is guaranteed to converge. + _phase = SavePhase.Growing; + for (; ; ) + { + _iteration++; + _encoder.Clear(); + + _offsetAdjustment = 0; + _paddingSize = 0; + + foreach (var section in _sections) foreach (var vertex in section._items) + { + int currentOffset = GetCurrentOffset(); + + // Only allow the offsets to grow. + _offsetAdjustment = Math.Max(_offsetAdjustment, currentOffset - vertex._offset); + + vertex._offset += _offsetAdjustment; + + if (vertex._offset > currentOffset) + { + // Padding + int padding = vertex._offset - currentOffset; + _paddingSize += padding; + WritePad(padding); + } + Debug.Assert(vertex._offset == GetCurrentOffset()); + + vertex._iteration = _iteration; + + vertex.Save(this); + +#if NATIVEFORMAT_COMPRESSION + // Ensure that the compressor state is fully flushed + Debug.Assert(_tentativelyWritten.Count == 0); + Debug.Assert(_compressionDepth == 0); +#endif + } + + if (_offsetAdjustment == 0) + { + _encoder.Save(stream); + return; + } + } + } + +#if NATIVEFORMAT_COMPRESSION + // TODO: +#else + internal struct TypeSignatureCompressor + { + internal TypeSignatureCompressor(NativeWriter pWriter) { } + internal void Pack(Vertex vertex) { } + } +#endif + + T Unify(T vertex) where T : Vertex + { + Vertex existing; + if (_unifier.TryGetValue(vertex, out existing)) + return (T)existing; + + Debug.Assert(vertex._offset == Vertex.NotPlaced); + vertex._offset = Vertex.Unified; + _unifier.Add(vertex, vertex); + + return vertex; + } + + public Vertex GetUnsignedConstant(uint value) + { + UnsignedConstant vertex = new UnsignedConstant(value); + return Unify(vertex); + } + + public Vertex GetTuple(Vertex item1, Vertex item2) + { + Tuple vertex = new Tuple(item1, item2); + return Unify(vertex); + } + + public Vertex GetTuple(Vertex item1, Vertex item2, Vertex item3) + { + Tuple vertex = new Tuple(item1, item2, item3); + return Unify(vertex); + } + + public Vertex GetMethodNameAndSigSignature(string name, Vertex signature) + { + MethodNameAndSigSignature sig = new MethodNameAndSigSignature( + GetStringConstant(name), + GetRelativeOffsetSignature(signature)); + return Unify(sig); + } + + public Vertex GetStringConstant(string value) + { + StringConstant vertex = new StringConstant(value); + return Unify(vertex); + } + + public Vertex GetRelativeOffsetSignature(Vertex item) + { + RelativeOffsetSignature sig = new RelativeOffsetSignature(item); + return Unify(sig); + } + + public Vertex GetOffsetSignature(Vertex item) + { + OffsetSignature sig = new OffsetSignature(item); + return Unify(sig); + } + + public Vertex GetExternalTypeSignature(uint externalTypeId) + { + ExternalTypeSignature sig = new ExternalTypeSignature(externalTypeId); + return Unify(sig); + } + + public Vertex GetMethodSignature(uint flags, uint fptrReferenceId, Vertex containingType, Vertex methodNameAndSig, Vertex[] args) + { + MethodSignature sig = new MethodSignature(flags, fptrReferenceId, containingType, methodNameAndSig, args); + return Unify(sig); + } + + public Vertex GetFieldSignature(Vertex containingType, string name) + { + FieldSignature sig = new FieldSignature(containingType, name); + return Unify(sig); + } + + public Vertex GetFixupSignature(FixupSignatureKind kind, Vertex signature) + { + FixupSignature sig = new FixupSignature(kind, signature); + return Unify(sig); + } + + public Vertex GetStaticDataSignature(Vertex type, StaticDataKind staticDataKind) + { + StaticDataSignature sig = new StaticDataSignature(type, staticDataKind); + return Unify(sig); + } + + public Vertex GetMethodSlotSignature(Vertex type, uint slot) + { + MethodSlotSignature sig = new MethodSlotSignature(type, slot); + return Unify(sig); + } + + public Vertex GetMethodSigSignature(uint callingConvention, uint genericArgCount, Vertex returnType, Vertex[] parameters) + { + MethodSigSignature sig = new MethodSigSignature(callingConvention, genericArgCount, returnType, parameters); + return Unify(sig); + } + + public Vertex GetModifierTypeSignature(TypeModifierKind modifier, Vertex param) + { + ModifierTypeSignature sig = new ModifierTypeSignature(modifier, param); + return Unify(sig); + } + + public Vertex GetVariableTypeSignature(uint index, bool method) + { + VariableTypeSignature sig = new VariableTypeSignature(index, method); + return Unify(sig); + } + + public Vertex GetInstantiationTypeSignature(Vertex typeDef, Vertex[] arguments) + { + InstantiationTypeSignature sig = new InstantiationTypeSignature(typeDef, arguments); + return Unify(sig); + } + + public Vertex GetMDArrayTypeSignature(Vertex elementType, uint rank, uint[] bounds, uint[] lowerBounds) + { + MDArrayTypeSignature sig = new MDArrayTypeSignature(elementType, rank, bounds, lowerBounds); + return Unify(sig); + } + + public Vertex GetCallingConventionConverterSignature(uint flags, Vertex signature) + { + CallingConventionConverterSignature sig = new CallingConventionConverterSignature(flags, GetRelativeOffsetSignature(signature)); + return Unify(sig); + } + } + + class PlacedVertex : Vertex + { + Vertex _unified; + + public PlacedVertex(Vertex unified) + { + _unified = unified; + } + + internal override void Save(NativeWriter writer) + { + _unified.Save(writer); + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class UnsignedConstant : Vertex + { + uint _value; + + public UnsignedConstant(uint value) + { + _value = value; + } + + internal override void Save(NativeWriter writer) + { + writer.WriteUnsigned(_value); + } + + public override int GetHashCode() + { + return 6659 + ((int)_value) * 19; + } + public override bool Equals(object other) + { + if (!(other is UnsignedConstant)) + return false; + + UnsignedConstant p = (UnsignedConstant)other; + if (_value != p._value) return false; + return true; + } + } + + class Tuple : Vertex + { + private Vertex _item1; + private Vertex _item2; + private Vertex _item3; + + public Tuple(Vertex item1, Vertex item2, Vertex item3 = null) + { + _item1 = item1; + _item2 = item2; + _item3 = item3; + } + + internal override void Save(NativeWriter writer) + { + _item1.Save(writer); + _item2.Save(writer); + if (_item3 != null) + _item3.Save(writer); + } + + public override int GetHashCode() + { + int hash = _item1.GetHashCode() * 93481 + _item2.GetHashCode() + 3492; + if (_item3 != null) + hash += (hash << 7) + _item3.GetHashCode() * 34987 + 213; + return hash; + } + + public override bool Equals(object obj) + { + Tuple other = obj as Tuple; + if (other == null) + return false; + + return Object.Equals(_item1, other._item1) && + Object.Equals(_item2, other._item2) && + Object.Equals(_item3, other._item3); + } + } + + // + // Bag of pairs. Good for extensible information (e.g. type info) + // + // Data can be either relative offset of another vertex, or arbitrary integer. + // +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class VertexBag : Vertex + { + enum EntryType { Vertex, Unsigned, Signed } + + struct Entry + { + internal BagElementKind _id; + internal EntryType _type; + internal object _value; + + internal Entry(BagElementKind id, Vertex value) + { + _id = id; + _type = EntryType.Vertex; + _value = value; + } + + internal Entry(BagElementKind id, uint value) + { + _id = id; + _type = EntryType.Unsigned; + _value = value; + } + + internal Entry(BagElementKind id, int value) + { + _id = id; + _type = EntryType.Signed; + _value = value; + } + } + + private List _elements; + + public VertexBag() + { + _elements = new List(); + } + + public void Append(BagElementKind id, Vertex value) + { + _elements.Add(new Entry(id, value)); + } + + public void AppendUnsigned(BagElementKind id, uint value) + { + _elements.Add(new Entry(id, value)); + } + + public void AppendSigned(BagElementKind id, int value) + { + _elements.Add(new Entry(id, value)); + } + + internal override void Save(NativeWriter writer) + { + foreach (var elem in _elements) + { + writer.WriteUnsigned((uint)elem._id); + + switch (elem._type) + { + case EntryType.Vertex: + writer.WriteRelativeOffset((Vertex)elem._value); + break; + + case EntryType.Unsigned: + writer.WriteUnsigned((uint)elem._value); + break; + + case EntryType.Signed: + writer.WriteSigned((int)elem._value); + break; + + } + } + writer.WriteUnsigned((uint)BagElementKind.End); + } + + public int ElementsCount => _elements.Count; + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class VertexSequence : Vertex + { + private List _elements; + + public VertexSequence() + { + _elements = new List(); + } + + public void Append(Vertex vertex) + { + _elements.Add(vertex); + } + + internal override void Save(NativeWriter writer) + { + writer.WriteUnsigned((uint)_elements.Count); + foreach (var elem in _elements) + elem.Save(writer); + } + + public override bool Equals(object obj) + { + var other = obj as VertexSequence; + if (other == null || other._elements.Count != _elements.Count) + return false; + + for (int i = 0; i < _elements.Count; i++) + if (!Object.Equals(_elements[i], other._elements[i])) + return false; + + return true; + } + + public override int GetHashCode() + { + int hashCode = 13; + foreach (var element in _elements) + { + int value = (element != null ? element.GetHashCode() : 0) * 0x5498341 + 0x832424; + hashCode = hashCode * 31 + value; + } + + return hashCode; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class MethodNameAndSigSignature : Vertex + { + private Vertex _methodName; + private Vertex _signature; + + public MethodNameAndSigSignature(Vertex methodName, Vertex signature) + { + _methodName = methodName; + _signature = signature; + } + + internal override void Save(NativeWriter writer) + { + _methodName.Save(writer); + _signature.Save(writer); + } + + public override int GetHashCode() + { + return 509 * 197 + _methodName.GetHashCode() + 647 * _signature.GetHashCode(); + } + + public override bool Equals(object obj) + { + MethodNameAndSigSignature other = obj as MethodNameAndSigSignature; + if (other == null) + return false; + + return Object.Equals(_methodName, other._methodName) && Object.Equals(_signature, other._signature); + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class StringConstant : Vertex + { + private string _value; + + public StringConstant(string value) + { + _value = value; + } + + internal override void Save(NativeWriter writer) + { + writer.WriteString(_value); + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + public override bool Equals(object obj) + { + StringConstant other = obj as StringConstant; + if (other == null) + return false; + + return _value == other._value; + } + } + + // + // Performs indirection to an existing native layout signature by writing out the + // relative offset. + // +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class RelativeOffsetSignature : Vertex + { + private Vertex _item; + + public RelativeOffsetSignature(Vertex item) + { + _item = item; + } + + internal override void Save(NativeWriter writer) + { + writer.WriteRelativeOffset(_item); + } + + public override int GetHashCode() + { + return _item.GetHashCode() >> 3; + } + + public override bool Equals(object obj) + { + RelativeOffsetSignature other = obj as RelativeOffsetSignature; + if (other == null) + return false; + + return Object.Equals(_item, other._item); + } + } + + // + // Performs indirection to an existing native layout signature using offset from the + // beginning of the native format. This allows cross-native layout references. You must + // ensure that the native layout writer of the pointee is saved before that of the pointer + // so the offsets are locked down. + // +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class OffsetSignature : Vertex + { + private Vertex _item; + + public OffsetSignature(Vertex item) + { + _item = item; + } + + internal override void Save(NativeWriter writer) + { + writer.WriteUnsigned((uint)_item.VertexOffset); + } + + public override int GetHashCode() + { + return _item.GetHashCode(); + } + + public override bool Equals(object obj) + { + OffsetSignature other = obj as OffsetSignature; + if (other == null) + return false; + + return Object.Equals(_item, other._item); + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class ExternalTypeSignature : Vertex + { + private uint _externalTypeId; + + public ExternalTypeSignature(uint externalTypeId) + { + _externalTypeId = externalTypeId; + } + + internal override void Save(NativeWriter writer) + { + NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); + + writer.WriteUnsigned((uint)TypeSignatureKind.External | (_externalTypeId << 4)); + + compressor.Pack(this); + } + + public override int GetHashCode() + { + return 32439 + 11 * (int)_externalTypeId; + } + + public override bool Equals(object obj) + { + ExternalTypeSignature other = obj as ExternalTypeSignature; + if (other == null) + return false; + + return _externalTypeId == other._externalTypeId; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class MethodSignature : Vertex + { + private uint _flags; + private uint _fptrReferenceId; + private Vertex _containingType; + private Vertex _methodNameAndSig; + private Vertex[] _args; + + public MethodSignature(uint flags, uint fptrReferenceId, Vertex containingType, Vertex methodNameAndSig, Vertex[] args) + { + _flags = flags; + _fptrReferenceId = fptrReferenceId; + _containingType = containingType; + _methodNameAndSig = methodNameAndSig; + _args = args; + + if ((flags & (uint)MethodFlags.HasInstantiation) != 0) + Debug.Assert(args != null && args.Length > 0); + if ((flags & (uint)MethodFlags.HasFunctionPointer) == 0) + Debug.Assert(fptrReferenceId == 0); + } + + internal override void Save(NativeWriter writer) + { + writer.WriteUnsigned(_flags); + if ((_flags & (uint)MethodFlags.HasFunctionPointer) != 0) + writer.WriteUnsigned(_fptrReferenceId); + _containingType.Save(writer); + _methodNameAndSig.Save(writer); + if ((_flags & (uint)MethodFlags.HasInstantiation) != 0) + { + writer.WriteUnsigned((uint)_args.Length); + for (uint iArg = 0; _args != null && iArg < _args.Length; iArg++) + _args[iArg].Save(writer); + } + } + + public override int GetHashCode() + { + int hash = _args != null ? _args.Length : 0; + hash += (hash << 5) + (int)_flags * 23; + hash += (hash << 5) + (int)_fptrReferenceId * 119; + hash += (hash << 5) + _containingType.GetHashCode(); + for (uint iArg = 0; _args != null && iArg < _args.Length; iArg++) + hash += (hash << 5) + _args[iArg].GetHashCode(); + hash += (hash << 5) + _methodNameAndSig.GetHashCode(); + return hash; + } + + public override bool Equals(object obj) + { + MethodSignature other = obj as MethodSignature; + if (other == null) + return false; + + if (!( + _flags == other._flags && + _fptrReferenceId == other._fptrReferenceId && + Object.Equals(_containingType, other._containingType) && + Object.Equals(_methodNameAndSig, other._methodNameAndSig))) + { + return false; + } + + if (_args != null) + { + if (other._args == null) return false; + if (other._args.Length != _args.Length) return false; + for (uint iArg = 0; _args != null && iArg < _args.Length; iArg++) + if (!Object.Equals(_args[iArg], other._args[iArg])) + return false; + } + else if (other._args != null) + return false; + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class FieldSignature : Vertex + { + private Vertex _containingType; + private string _name; + + public FieldSignature(Vertex containingType, string name) + { + _containingType = containingType; + _name = name; + } + + internal override void Save(NativeWriter writer) + { + _containingType.Save(writer); + writer.WriteString(_name); + } + + public override int GetHashCode() + { + int hash = 113 + 97 * _containingType.GetHashCode(); + foreach (char c in _name) + hash += (hash << 5) + c * 19; + + return hash; + } + + public override bool Equals(object obj) + { + var other = obj as FieldSignature; + if (other == null) + return false; + + if (!Object.Equals(other._containingType, _containingType)) + return false; + + if (!Object.Equals(other._name, _name)) + return false; + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class FixupSignature : Vertex + { + private FixupSignatureKind _kind; + private Vertex _signature; + + public FixupSignature(FixupSignatureKind kind, Vertex signature) + { + _kind = kind; + _signature = signature; + } + + internal override void Save(NativeWriter writer) + { + writer.WriteUnsigned((uint)_kind); + if (_signature != null) + _signature.Save(writer); + } + + public override int GetHashCode() + { + return 53345 + 97 * (int)_kind + ((_signature != null) ? _signature.GetHashCode() : 0); + } + + public override bool Equals(object obj) + { + var other = obj as FixupSignature; + if (other == null) + return false; + + if (other._kind != _kind) + return false; + + if (!Object.Equals(other._signature, _signature)) + return false; + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class StaticDataSignature : Vertex + { + private Vertex _type; + private StaticDataKind _staticDataKind; + + public StaticDataSignature(Vertex type, StaticDataKind staticDataKind) + { + _type = type; + _staticDataKind = staticDataKind; + } + + internal override void Save(NativeWriter writer) + { + _type.Save(writer); + writer.WriteUnsigned((uint)_staticDataKind); + } + + public override int GetHashCode() + { + return 456789 + 101 * (int)_staticDataKind + _type.GetHashCode(); + } + + public override bool Equals(object obj) + { + var other = obj as StaticDataSignature; + if (other == null) + return false; + + if (!Object.Equals(other._type, _type)) + return false; + + if (other._staticDataKind != _staticDataKind) + return false; + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class MethodSlotSignature : Vertex + { + private Vertex _type; + private uint _slot; + + public MethodSlotSignature(Vertex type, uint slot) + { + _type = type; + _slot = slot; + } + + internal override void Save(NativeWriter writer) + { + _type.Save(writer); + writer.WriteUnsigned(_slot); + } + + public override int GetHashCode() + { + return 124121 + 47 * (int)_slot + _type.GetHashCode(); + } + + public override bool Equals(object obj) + { + var other = obj as MethodSlotSignature; + if (other == null) + return false; + + if (!Object.Equals(other._type, _type)) + return false; + + if (other._slot != _slot) + return false; + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class MethodSigSignature : Vertex + { + private uint _callingConvention; + private uint _genericArgCount; + private Vertex _returnType; + private Vertex[] _parameters; + + public MethodSigSignature(uint callingConvention, uint genericArgCount, Vertex returnType, Vertex[] parameters) + { + _callingConvention = callingConvention; + _returnType = returnType; + _genericArgCount = genericArgCount; + _parameters = parameters; + } + + internal override void Save(NativeWriter writer) + { + writer.WriteUnsigned(_callingConvention); + + // Signatures omit the generic type parameter count for non-generic methods + if (_genericArgCount > 0) + writer.WriteUnsigned(_genericArgCount); + + writer.WriteUnsigned((uint)_parameters.Length); + + _returnType.Save(writer); + + foreach (var p in _parameters) + p.Save(writer); + } + + public override int GetHashCode() + { + int hash = 317 + 709 * (int)_callingConvention + 953 * (int)_genericArgCount + 31 * _returnType.GetHashCode(); + foreach (var p in _parameters) + hash += (hash << 5) + p.GetHashCode(); + return hash; + } + + public override bool Equals(object obj) + { + MethodSigSignature other = obj as MethodSigSignature; + if (other == null) + return false; + + if (!( + _callingConvention == other._callingConvention && + _genericArgCount == other._genericArgCount && + _parameters.Length == other._parameters.Length && + Object.Equals(_returnType, other._returnType))) + { + return false; + } + + for (int i = 0; i < _parameters.Length; i++) + if (!Object.Equals(_parameters[i], other._parameters[i])) + return false; + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class ModifierTypeSignature : Vertex + { + private TypeModifierKind _modifier; + private Vertex _param; + + public ModifierTypeSignature(TypeModifierKind modifier, Vertex param) + { + _modifier = modifier; + _param = param; + } + + internal override void Save(NativeWriter writer) + { + NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); + + writer.WriteUnsigned((uint)TypeSignatureKind.Modifier | ((uint)_modifier << 4)); + _param.Save(writer); + + compressor.Pack(this); + } + + public override int GetHashCode() + { + return 432981 + 37 * (int)_modifier + _param.GetHashCode(); + } + + public override bool Equals(object obj) + { + ModifierTypeSignature other = obj as ModifierTypeSignature; + if (other == null) + return false; + + return _modifier == other._modifier && Object.Equals(_param, other._param); + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class VariableTypeSignature : Vertex + { + private uint _variableId; + + public VariableTypeSignature(uint index, bool method) + { + _variableId = (index << 1) | (method ? (uint)1 : 0); + } + + internal override void Save(NativeWriter writer) + { + NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); + + writer.WriteUnsigned((uint)TypeSignatureKind.Variable | (_variableId << 4)); + + compressor.Pack(this); + } + + public override int GetHashCode() + { + return 6093 + 7 * (int)_variableId; + } + + public override bool Equals(object obj) + { + VariableTypeSignature other = obj as VariableTypeSignature; + if (other == null) + return false; + + return _variableId == other._variableId; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class InstantiationTypeSignature : Vertex + { + private Vertex _typeDef; + private Vertex[] _args; + + public InstantiationTypeSignature(Vertex typeDef, Vertex[] args) + { + _typeDef = typeDef; + _args = args; + } + + internal override void Save(NativeWriter writer) + { + NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); + + writer.WriteUnsigned((uint)TypeSignatureKind.Instantiation | ((uint)_args.Length << 4)); + _typeDef.Save(writer); + for (int iArg = 0; iArg < _args.Length; iArg++) + _args[iArg].Save(writer); + + compressor.Pack(this); + } + + public override int GetHashCode() + { + int hash = _args.Length; + + hash += (hash << 5) + _typeDef.GetHashCode(); + for (int iArg = 0; iArg < _args.Length; iArg++) + hash += (hash << 5) + _args[iArg].GetHashCode(); + return hash; + } + + public override bool Equals(object obj) + { + InstantiationTypeSignature other = obj as InstantiationTypeSignature; + if (other == null) + return false; + + if (_args.Length != other._args.Length || !Object.Equals(_typeDef, other._typeDef)) + return false; + + for (uint iArg = 0; iArg < _args.Length; iArg++) + if (!Object.Equals(_args[iArg], other._args[iArg])) + return false; + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class MDArrayTypeSignature : Vertex + { + private Vertex _arrayElementType; + private uint _rank; + private uint[] _bounds; + private uint[] _lowerBounds; + + public MDArrayTypeSignature(Vertex arrayElementType, uint rank, uint[] bounds, uint[] lowerBounds) + { + Debug.Assert(bounds != null && lowerBounds != null); + + _arrayElementType = arrayElementType; + _rank = rank; + _bounds = bounds; + _lowerBounds = lowerBounds; + } + + internal override void Save(NativeWriter writer) + { + NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); + + writer.WriteUnsigned((uint)TypeSignatureKind.MultiDimArray | ((uint)_rank << 4)); + _arrayElementType.Save(writer); + + writer.WriteUnsigned((uint)_bounds.Length); + foreach (uint b in _bounds) + writer.WriteUnsigned(b); + + writer.WriteUnsigned((uint)_lowerBounds.Length); + foreach (uint b in _lowerBounds) + writer.WriteUnsigned(b); + + compressor.Pack(this); + } + + public override int GetHashCode() + { + int hash = 79 + 971 * (int)_rank + 83 * _arrayElementType.GetHashCode(); + + foreach (uint b in _bounds) + hash += (hash << 5) + (int)b * 19; + + foreach (uint b in _lowerBounds) + hash += (hash << 5) + (int)b * 19; + + return hash; + } + + public override bool Equals(object obj) + { + MDArrayTypeSignature other = obj as MDArrayTypeSignature; + if (other == null) + return false; + + if (!Object.Equals(_arrayElementType, other._arrayElementType) || + _rank != other._rank || + _bounds.Length != other._bounds.Length || + _lowerBounds.Length != other._lowerBounds.Length) + { + return false; + } + for (int i = 0; i < _bounds.Length; i++) + { + if (_bounds[i] != other._bounds[i]) + return false; + } + for (int i = 0; i < _lowerBounds.Length; i++) + { + if (_lowerBounds[i] != other._lowerBounds[i]) + return false; + } + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class CallingConventionConverterSignature : Vertex + { + private uint _flags; + private Vertex _signature; + + public CallingConventionConverterSignature(uint flags, Vertex signature) + { + _flags = flags; + _signature = signature; + } + + internal override void Save(NativeWriter writer) + { + writer.WriteUnsigned(_flags); + _signature.Save(writer); + } + + public override int GetHashCode() + { + return 509 * 197 + ((int)_flags) * 23 + 647 * _signature.GetHashCode(); + } + + public override bool Equals(object obj) + { + CallingConventionConverterSignature other = obj as CallingConventionConverterSignature; + if (other == null) + return false; + + if (_flags != other._flags) + return false; + + if (!_signature.Equals(other._signature)) + return false; + + return true; + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class BlobVertex : Vertex + { + private byte[] _data; + + public BlobVertex(byte[] data) + { + _data = data; + } + + public int GetSize() + { + return _data.Length; + } + + internal override void Save(NativeWriter writer) + { + foreach (byte b in _data) + { + writer.WriteByte(b); + } + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class EntryPointVertex : Vertex + { + private uint _methodIndex; + + private BlobVertex _fixups; + + public EntryPointVertex(uint methodIndex, BlobVertex fixups) + { + _methodIndex = methodIndex; + _fixups = fixups; + } + + internal override void Save(NativeWriter writer) + { + if (_fixups != null) + { + int existingOffset = _fixups._offset; + if (existingOffset != -1) + { + writer.WriteUnsigned((_methodIndex << 2) | 3); + writer.WriteUnsigned((uint)(writer.GetCurrentOffset() - existingOffset)); + } + else + { + writer.WriteUnsigned((_methodIndex << 2) | 1); + _fixups.Save(writer); + } + } + else + { + writer.WriteUnsigned(_methodIndex << 1); + } + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class EntryPointWithBlobVertex : EntryPointVertex + { + private BlobVertex _blob; + + public EntryPointWithBlobVertex(uint methodIndex, BlobVertex fixups, BlobVertex blob) + : base(methodIndex, fixups) + { + _blob = blob; + } + + internal override void Save(NativeWriter writer) + { + _blob.Save(writer); + base.Save(writer); + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class DebugInfoVertex : Vertex + { + private BlobVertex _debugInfo; + + public DebugInfoVertex(BlobVertex debugInfo) + { + _debugInfo = debugInfo; + } + + internal override void Save(NativeWriter writer) + { + int existingOffset = writer.GetCurrentOffset(_debugInfo); + if (existingOffset != -1) + { + Debug.Assert(writer.GetCurrentOffset() > existingOffset); + writer.WriteUnsigned((uint)(writer.GetCurrentOffset() - existingOffset)); + } + else + { + writer.WriteUnsigned(0); + _debugInfo._iteration = writer.GetNumberOfIterations(); + _debugInfo._offset = writer.GetCurrentOffset(); + _debugInfo.Save(writer); + } + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class VertexArray : Vertex + { + private const int BlockSize = 16; + + private Section _section; + + private List _entries; + + private List _blocks; + + /// + /// Current size of index entry: 0 - uint8, 1 - uint16, 2 - uint32 + /// + private uint _entryIndexSize; + + class VertexLeaf : Vertex + { + private Vertex _vertex; + private int _leafIndex; + + public VertexLeaf(Vertex vertex, int leafIndex) + { + _vertex = vertex; + _leafIndex = leafIndex; + } + + internal override void Save(NativeWriter writer) + { + writer.WriteUnsigned((uint)_leafIndex << 2); + + if (_vertex != null) + { + _vertex.Save(writer); + } + } + } + + class VertexTree : Vertex + { + private Vertex _first; + private Vertex _second; + + public VertexTree() + { + _first = null; + _second = null; + } + + public VertexTree(Vertex first, Vertex second) + { + _first = first; + _second = second; + } + + public void Update(Vertex first, Vertex second) + { + _first = first; + _second = second; + } + + internal override void Save(NativeWriter writer) + { + uint value = (_first != null ? 1u : 0u); + + if (_second != null) + { + value |= 2; + + int delta = writer.GetExpectedOffset(_second) - writer.GetCurrentOffset(); + Debug.Assert(delta >= 0); + value |= ((uint)delta << 2); + } + + writer.WriteUnsigned(value); + + if (_first != null) + _first.Save(writer); + } + } + + public VertexArray(Section section) + { + _section = section; + _entries = new List(); + _blocks = new List(); + _entryIndexSize = 0; + } + + private Vertex ExpandBlock(int index, int depth, bool place, out bool isLeaf) + { + if (depth == 1) + { + Vertex first = (index < _entries.Count ? _entries[index] : null); + Vertex second = (index + 1 < _entries.Count ? _entries[index + 1] : null); + + if (first == null && second == null) + { + isLeaf = true; + return null; + } + + if (first == null || second == null) + { + VertexLeaf leaf = new VertexLeaf( + first == null ? second : first, + (first == null ? index + 1 : index) & (BlockSize - 1)); + + if (place) + { + _section.Place(leaf); + } + + isLeaf = true; + return leaf; + } + + VertexTree tree = new VertexTree(first, second); + if (place) + _section.Place(tree); + + _section.Place(second); + + isLeaf = false; + return tree; + } + else + { + VertexTree tree = new VertexTree(); + if (place) + _section.Place(tree); + + bool firstIsLeaf; + Vertex first = ExpandBlock(index, depth - 1, false, out firstIsLeaf); + + bool secondIsLeaf; + Vertex second = ExpandBlock(index + (1 << (depth - 1)), depth - 1, true, out secondIsLeaf); + + if (first == null && second == null) + { + if (place) + { + Vertex pop = _section.Pop(); + Debug.Assert(pop == tree); + } + isLeaf = true; + return null; + } + + if (first == null && secondIsLeaf) + { + Vertex pop = _section.Pop(); + Debug.Assert(pop == second); + if (place) + { + pop = _section.Pop(); + Debug.Assert(pop == tree); + _section.Place(second); + } + + isLeaf = true; + return second; + } + + if (second == null && firstIsLeaf) + { + if (place) + { + Vertex pop = _section.Pop(); + Debug.Assert(pop == tree); + _section.Place(first); + } + + isLeaf = true; + return first; + } + + tree.Update(first, second); + isLeaf = false; + return tree; + } + } + + public void Set(int index, Vertex element) + { + while (index >= _entries.Count) + _entries.Add(null); + + _entries[index] = element; + } + + public void ExpandLayout() + { + VertexLeaf nullBlock = null; + for (int i = 0; i < _entries.Count; i += BlockSize) + { + bool isLeaf; + Vertex block = ExpandBlock(i, 4, true, out isLeaf); + + if (block == null) + { + if (nullBlock == null) + { + nullBlock = new VertexLeaf(vertex: null, leafIndex: BlockSize); + _section.Place(nullBlock); + } + block = nullBlock; + } + + _blocks.Add(block); + } + + // Start with maximum size entries + _entryIndexSize = 2; + } + + internal override void Save(NativeWriter writer) + { + // Lowest two bits are entry index size, the rest is number of elements + writer.WriteUnsigned(((uint)_entries.Count << 2) | _entryIndexSize); + + int blocksOffset = writer.GetCurrentOffset(); + int maxOffset = 0; + + foreach (Vertex block in _blocks) + { + int offset = writer.GetExpectedOffset(block) - blocksOffset; + Debug.Assert(offset >= 0); + + maxOffset = Math.Max(offset, maxOffset); + + if (_entryIndexSize == 0) + { + writer.WriteByte((byte)offset); + } + else + if (_entryIndexSize == 1) + { + writer.WriteUInt16((ushort)offset); + } + else + { + writer.WriteUInt32((uint)offset); + } + } + + uint newEntryIndexSize = 0; + if (maxOffset > 0xFF) + { + newEntryIndexSize++; + if (maxOffset > 0xFFFF) + newEntryIndexSize++; + } + + if (writer.IsGrowing()) + { + if (newEntryIndexSize > _entryIndexSize) + { + // Ensure that the table will be redone with new entry index size + writer.UpdateOffsetAdjustment(1); + + _entryIndexSize = newEntryIndexSize; + } + } + else + { + if (newEntryIndexSize < _entryIndexSize) + { + // Ensure that the table will be redone with new entry index size + writer.UpdateOffsetAdjustment(-1); + + _entryIndexSize = newEntryIndexSize; + } + } + } + } + +#if NATIVEFORMAT_PUBLICWRITER + public +#else + internal +#endif + class VertexHashtable : Vertex + { + struct Entry + { + public Entry(uint hashcode, Vertex vertex) + { + Offset = 0; + Hashcode = hashcode; + Vertex = vertex; + } + + public int Offset; + + public uint Hashcode; + public Vertex Vertex; + + public static int Comparison(Entry a, Entry b) + { + return (int)(a.Hashcode /*& mask*/) - (int)(b.Hashcode /*& mask*/); + } + } + + private List _Entries; + + // How many entries to target per bucket. Higher fill factor means smaller size, but worse runtime perf. + private int _nFillFactor; + + // Number of buckets choosen for the table. Must be power of two. 0 means that the table is still open for mutation. + private uint _nBuckets; + + // Current size of index entry + private int _entryIndexSize; // 0 - uint8, 1 - uint16, 2 - uint32 + + public const int DefaultFillFactor = 13; + + public VertexHashtable(int fillFactor = DefaultFillFactor) + { + _Entries = new List(); + _nFillFactor = fillFactor; + _nBuckets = 0; + _entryIndexSize = 0; + } + + public void Append(uint hashcode, Vertex element) + { + // The table needs to be open for mutation + Debug.Assert(_nBuckets == 0); + + _Entries.Add(new Entry(hashcode, element)); + } + + // Returns 1 + log2(x) rounded up, 0 iff x == 0 + static int HighestBit(uint x) + { + int ret = 0; + while (x != 0) + { + x >>= 1; + ret++; + } + return ret; + } + + // Helper method to back patch entry index in the bucket table + static void PatchEntryIndex(NativeWriter writer, int patchOffset, int entryIndexSize, int entryIndex) + { + if (entryIndexSize == 0) + { + writer.PatchByteAt(patchOffset, (byte)entryIndex); + } + else if (entryIndexSize == 1) + { + writer.PatchByteAt(patchOffset, (byte)entryIndex); + writer.PatchByteAt(patchOffset + 1, (byte)(entryIndex >> 8)); + } + else + { + writer.PatchByteAt(patchOffset, (byte)entryIndex); + writer.PatchByteAt(patchOffset + 1, (byte)(entryIndex >> 8)); + writer.PatchByteAt(patchOffset + 2, (byte)(entryIndex >> 16)); + writer.PatchByteAt(patchOffset + 3, (byte)(entryIndex >> 24)); + } + } + + void ComputeLayout() + { + uint bucketsEstimate = (uint)(_Entries.Count / _nFillFactor); + + // Round number of buckets up to the power of two + _nBuckets = (uint)(1 << HighestBit(bucketsEstimate)); + + // Lowest byte of the hashcode is used for lookup within the bucket. Keep it sorted too so that + // we can use the ordering to terminate the lookup prematurely. + uint mask = ((_nBuckets - 1) << 8) | 0xFF; + + // sort it by hashcode + _Entries.Sort( + (a, b) => + { + return (int)(a.Hashcode & mask) - (int)(b.Hashcode & mask); + } + ); + + // Start with maximum size entries + _entryIndexSize = 2; + } + + internal override void Save(NativeWriter writer) + { + // Compute the layout of the table if we have not done it yet + if (_nBuckets == 0) + ComputeLayout(); + + int nEntries = _Entries.Count; + int startOffset = writer.GetCurrentOffset(); + uint bucketMask = (_nBuckets - 1); + + // Lowest two bits are entry index size, the rest is log2 number of buckets + int numberOfBucketsShift = HighestBit(_nBuckets) - 1; + writer.WriteByte((byte)((numberOfBucketsShift << 2) | _entryIndexSize)); + + int bucketsOffset = writer.GetCurrentOffset(); + + writer.WritePad((int)((_nBuckets + 1) << _entryIndexSize)); + + // For faster lookup at runtime, we store the first entry index even though it is redundant (the + // value can be inferred from number of buckets) + PatchEntryIndex(writer, bucketsOffset, _entryIndexSize, writer.GetCurrentOffset() - bucketsOffset); + + int iEntry = 0; + + for (int iBucket = 0; iBucket < _nBuckets; iBucket++) + { + while (iEntry < nEntries) + { + if (((_Entries[iEntry].Hashcode >> 8) & bucketMask) != iBucket) + break; + + Entry curEntry = _Entries[iEntry]; + + int currentOffset = writer.GetCurrentOffset(); + writer.UpdateOffsetAdjustment(currentOffset - curEntry.Offset); + curEntry.Offset = currentOffset; + _Entries[iEntry] = curEntry; + + writer.WriteByte((byte)curEntry.Hashcode); + writer.WriteRelativeOffset(curEntry.Vertex); + + iEntry++; + } + + int patchOffset = bucketsOffset + ((iBucket + 1) << _entryIndexSize); + + PatchEntryIndex(writer, patchOffset, _entryIndexSize, writer.GetCurrentOffset() - bucketsOffset); + } + Debug.Assert(iEntry == nEntries); + + int maxIndexEntry = (writer.GetCurrentOffset() - bucketsOffset); + int newEntryIndexSize = 0; + if (maxIndexEntry > 0xFF) + { + newEntryIndexSize++; + if (maxIndexEntry > 0xFFFF) + newEntryIndexSize++; + } + + if (writer.IsGrowing()) + { + if (newEntryIndexSize > _entryIndexSize) + { + // Ensure that the table will be redone with new entry index size + writer.UpdateOffsetAdjustment(1); + + _entryIndexSize = newEntryIndexSize; + } + } + else + { + if (newEntryIndexSize < _entryIndexSize) + { + // Ensure that the table will be redone with new entry index size + writer.UpdateOffsetAdjustment(-1); + + _entryIndexSize = newEntryIndexSize; + } + } + } + + public override bool Equals(object obj) + { + throw new NotImplementedException(); + } + + public override int GetHashCode() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/coreclr/src/tools/Common/Internal/Runtime/CorConstants.cs b/src/coreclr/src/tools/Common/Internal/Runtime/CorConstants.cs new file mode 100644 index 00000000000..02477abb171 --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/Runtime/CorConstants.cs @@ -0,0 +1,128 @@ +// 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; + +namespace Internal.CorConstants +{ + /// + /// based on src/inc/corcompile.h CorCompileImportType + /// + public enum CorCompileImportType + { + CORCOMPILE_IMPORT_TYPE_UNKNOWN = 0, + CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD = 1, + CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH = 2, + CORCOMPILE_IMPORT_TYPE_STRING_HANDLE = 3, + CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE = 4, + CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE = 5, + CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD = 6, + }; + + /// + /// based on src/inc/corcompile.h CorCompileImportFlags + /// + public enum CorCompileImportFlags + { + CORCOMPILE_IMPORT_FLAGS_UNKNOWN = 0x0000, + CORCOMPILE_IMPORT_FLAGS_EAGER = 0x0001, // Section at module load time. + CORCOMPILE_IMPORT_FLAGS_CODE = 0x0002, // Section contains code. + CORCOMPILE_IMPORT_FLAGS_PCODE = 0x0004, // Section contains pointers to code. + }; + + public enum CorElementType : byte + { + Invalid = 0, + ELEMENT_TYPE_VOID = 1, + ELEMENT_TYPE_BOOLEAN = 2, + ELEMENT_TYPE_CHAR = 3, + ELEMENT_TYPE_I1 = 4, + ELEMENT_TYPE_U1 = 5, + ELEMENT_TYPE_I2 = 6, + ELEMENT_TYPE_U2 = 7, + ELEMENT_TYPE_I4 = 8, + ELEMENT_TYPE_U4 = 9, + ELEMENT_TYPE_I8 = 10, + ELEMENT_TYPE_U8 = 11, + ELEMENT_TYPE_R4 = 12, + ELEMENT_TYPE_R8 = 13, + ELEMENT_TYPE_STRING = 14, + ELEMENT_TYPE_PTR = 15, + ELEMENT_TYPE_BYREF = 16, + ELEMENT_TYPE_VALUETYPE = 17, + ELEMENT_TYPE_CLASS = 18, + ELEMENT_TYPE_VAR = 19, + ELEMENT_TYPE_ARRAY = 20, + ELEMENT_TYPE_GENERICINST = 21, + ELEMENT_TYPE_TYPEDBYREF = 22, + ELEMENT_TYPE_I = 24, + ELEMENT_TYPE_U = 25, + ELEMENT_TYPE_FNPTR = 27, + ELEMENT_TYPE_OBJECT = 28, + ELEMENT_TYPE_SZARRAY = 29, + ELEMENT_TYPE_MVAR = 30, + ELEMENT_TYPE_CMOD_REQD = 31, + ELEMENT_TYPE_CMOD_OPT = 32, + + // ZapSig encoding for ELEMENT_TYPE_VAR and ELEMENT_TYPE_MVAR. It is always followed + // by the RID of a GenericParam token, encoded as a compressed integer. + ELEMENT_TYPE_VAR_ZAPSIG = 0x3b, + + // ZapSig encoding for an array MethodTable to allow it to remain such after decoding + // (rather than being transformed into the TypeHandle representing that array) + // + // The element is always followed by ELEMENT_TYPE_SZARRAY or ELEMENT_TYPE_ARRAY + ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG = 0x3c, + + // ZapSig encoding for native value types in IL stubs. IL stub signatures may contain + // ELEMENT_TYPE_INTERNAL followed by ParamTypeDesc with ELEMENT_TYPE_VALUETYPE element + // type. It acts like a modifier to the underlying structure making it look like its + // unmanaged view (size determined by unmanaged layout, blittable, no GC pointers). + // + // ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG is used when encoding such types to NGEN images. + // The signature looks like this: ET_NATIVE_VALUETYPE_ZAPSIG ET_VALUETYPE . + // See code:ZapSig.GetSignatureForTypeHandle and code:SigPointer.GetTypeHandleThrowing + // where the encoding/decoding takes place. + ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG = 0x3d, + + ELEMENT_TYPE_CANON_ZAPSIG = 0x3e, // zapsig encoding for [mscorlib]System.__Canon + ELEMENT_TYPE_MODULE_ZAPSIG = 0x3f, // zapsig encoding for external module id# + + ELEMENT_TYPE_HANDLE = 64, + ELEMENT_TYPE_SENTINEL = 65, + ELEMENT_TYPE_PINNED = 69, + } + + public enum CorTokenType + { + mdtModule = 0x00000000, + mdtTypeRef = 0x01000000, + mdtTypeDef = 0x02000000, + mdtFieldDef = 0x04000000, + mdtMethodDef = 0x06000000, + mdtParamDef = 0x08000000, + mdtInterfaceImpl = 0x09000000, + mdtMemberRef = 0x0a000000, + mdtCustomAttribute = 0x0c000000, + mdtPermission = 0x0e000000, + mdtSignature = 0x11000000, + mdtEvent = 0x14000000, + mdtProperty = 0x17000000, + mdtMethodImpl = 0x19000000, + mdtModuleRef = 0x1a000000, + mdtTypeSpec = 0x1b000000, + mdtAssembly = 0x20000000, + mdtAssemblyRef = 0x23000000, + mdtFile = 0x26000000, + mdtExportedType = 0x27000000, + mdtManifestResource = 0x28000000, + mdtGenericParam = 0x2a000000, + mdtMethodSpec = 0x2b000000, + mdtGenericParamConstraint = 0x2c000000, + + mdtString = 0x70000000, + mdtName = 0x71000000, + mdtBaseType = 0x72000000, + } +} diff --git a/src/coreclr/src/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/src/tools/Common/Internal/Runtime/ModuleHeaders.cs new file mode 100644 index 00000000000..c18b0d0566d --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -0,0 +1,94 @@ +// 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; + +namespace Internal.Runtime +{ + // + // Please keep the data structures in this file in sync with the native version at + // src/Native/Runtime/inc/ModuleHeaders.h + // + + internal struct ReadyToRunHeaderConstants + { + public const uint Signature = 0x00525452; // 'RTR' + + public const ushort CurrentMajorVersion = 4; + public const ushort CurrentMinorVersion = 0; + } + +#pragma warning disable 0169 + internal struct ReadyToRunHeader + { + private uint Signature; // ReadyToRunHeaderConstants.Signature + private ushort MajorVersion; + private ushort MinorVersion; + + private uint Flags; + + private ushort NumberOfSections; + private byte EntrySize; + private byte EntryType; + + // Array of sections follows. + }; +#pragma warning restore 0169 + + // + // ReadyToRunSectionType IDs are used by the runtime to look up specific global data sections + // from each module linked into the final binary. New sections should be added at the bottom + // of the enum and deprecated sections should not be removed to preserve ID stability. + // + // This list should be kept in sync with the runtime version at + // https://github.com/dotnet/coreclr/blob/master/src/inc/readytorun.h + // + public enum ReadyToRunSectionType + { + // + // CoreCLR ReadyToRun sections + // + CompilerIdentifier = 100, + ImportSections = 101, + RuntimeFunctions = 102, + MethodDefEntryPoints = 103, + ExceptionInfo = 104, + DebugInfo = 105, + DelayLoadMethodCallThunks = 106, + // 107 is deprecated - it was used by an older format of AvailableTypes + AvailableTypes = 108, + InstanceMethodEntryPoints = 109, + InliningInfo = 110, // Added in v2.1 + ProfileDataInfo = 111, // Added in v2.2 + ManifestMetadata = 112, // Added in v2.3 + AttributePresence = 113, // Added in V3.1 + + // + // CoreRT ReadyToRun sections + // + StringTable = 200, // Unused + GCStaticRegion = 201, + ThreadStaticRegion = 202, + InterfaceDispatchTable = 203, + TypeManagerIndirection = 204, + EagerCctor = 205, + FrozenObjectRegion = 206, + GCStaticDesc = 207, + ThreadStaticOffsetRegion = 208, + ThreadStaticGCDescRegion = 209, + ThreadStaticIndex = 210, + LoopHijackFlag = 211, + ImportAddressTables = 212, + + // Sections 300 - 399 are reserved for RhFindBlob backwards compatibility + ReadonlyBlobRegionStart = 300, + ReadonlyBlobRegionEnd = 399, + } + + [Flags] + internal enum ModuleInfoFlags : int + { + HasEndPointer = 0x1, + } +} diff --git a/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunConstants.cs b/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunConstants.cs new file mode 100644 index 00000000000..2f6ae4b03eb --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunConstants.cs @@ -0,0 +1,316 @@ +// 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; + +namespace Internal.ReadyToRunConstants +{ + [Flags] + public enum ReadyToRunFlag + { + READYTORUN_FLAG_PlatformNeutralSource = 0x00000001, // Set if the original IL assembly was platform-neutral + READYTORUN_FLAG_SkipTypeValidation = 0x00000002, // Set of methods with native code was determined using profile data + READYTORUN_FLAG_Partial = 0x00000004, + READYTORUN_FLAG_NonSharedPInvokeStubs = 0x00000008 // PInvoke stubs compiled into image are non-shareable (no secret parameter) + } + + /// + /// Constants for method and field encoding + /// + [Flags] + public enum ReadyToRunMethodSigFlags : byte + { + READYTORUN_METHOD_SIG_None = 0x00, + READYTORUN_METHOD_SIG_UnboxingStub = 0x01, + READYTORUN_METHOD_SIG_InstantiatingStub = 0x02, + READYTORUN_METHOD_SIG_MethodInstantiation = 0x04, + READYTORUN_METHOD_SIG_SlotInsteadOfToken = 0x08, + READYTORUN_METHOD_SIG_MemberRefToken = 0x10, + READYTORUN_METHOD_SIG_Constrained = 0x20, + READYTORUN_METHOD_SIG_OwnerType = 0x40, + } + + [Flags] + public enum ReadyToRunFieldSigFlags : byte + { + READYTORUN_FIELD_SIG_IndexInsteadOfToken = 0x08, + READYTORUN_FIELD_SIG_MemberRefToken = 0x10, + READYTORUN_FIELD_SIG_OwnerType = 0x40, + } + + [Flags] + public enum ReadyToRunTypeLayoutFlags : byte + { + READYTORUN_LAYOUT_HFA = 0x01, + READYTORUN_LAYOUT_Alignment = 0x02, + READYTORUN_LAYOUT_Alignment_Native = 0x04, + READYTORUN_LAYOUT_GCLayout = 0x08, + READYTORUN_LAYOUT_GCLayout_Empty = 0x10, + } + + public enum DictionaryEntryKind + { + EmptySlot = 0, + TypeHandleSlot = 1, + MethodDescSlot = 2, + MethodEntrySlot = 3, + ConstrainedMethodEntrySlot = 4, + DispatchStubAddrSlot = 5, + FieldDescSlot = 6, + DeclaringTypeHandleSlot = 7, + } + + public enum ReadyToRunFixupKind + { + Invalid = 0x00, + + ThisObjDictionaryLookup = 0x07, + TypeDictionaryLookup = 0x08, + MethodDictionaryLookup = 0x09, + + TypeHandle = 0x10, + MethodHandle = 0x11, + FieldHandle = 0x12, + + MethodEntry = 0x13, // For calling a method entry point + MethodEntry_DefToken = 0x14, // Smaller version of MethodEntry - method is def token + MethodEntry_RefToken = 0x15, // Smaller version of MethodEntry - method is ref token + + VirtualEntry = 0x16, // For invoking a virtual method + VirtualEntry_DefToken = 0x17, // Smaller version of VirtualEntry - method is def token + VirtualEntry_RefToken = 0x18, // Smaller version of VirtualEntry - method is ref token + VirtualEntry_Slot = 0x19, // Smaller version of VirtualEntry - type & slot + + Helper = 0x1A, // Helper + StringHandle = 0x1B, // String handle + + NewObject = 0x1C, // Dynamically created new helper + NewArray = 0x1D, + + IsInstanceOf = 0x1E, // Dynamically created casting helper + ChkCast = 0x1F, + + FieldAddress = 0x20, // For accessing a cross-module static fields + CctorTrigger = 0x21, // Static constructor trigger + + StaticBaseNonGC = 0x22, // Dynamically created static base helpers + StaticBaseGC = 0x23, + ThreadStaticBaseNonGC = 0x24, + ThreadStaticBaseGC = 0x25, + + FieldBaseOffset = 0x26, // Field base offset + FieldOffset = 0x27, // Field offset + + TypeDictionary = 0x28, + MethodDictionary = 0x29, + + Check_TypeLayout = 0x2A, // size, alignment, HFA, reference map + Check_FieldOffset = 0x2B, + + DelegateCtor = 0x2C, // optimized delegate ctor + DeclaringTypeHandle = 0x2D, + + IndirectPInvokeTarget = 0x2E, // Target (indirect) of an inlined pinvoke + PInvokeTarget = 0x2F, // Target of an inlined pinvoke + + ModuleOverride = 0x80, + // followed by sig-encoded UInt with assemblyref index into either the assemblyref + // table of the MSIL metadata of the master context module for the signature or + // into the extra assemblyref table in the manifest metadata R2R header table + // (used in cases inlining brings in references to assemblies not seen in the MSIL). + } + + // + // Intrinsics and helpers + // Keep in sync with https://github.com/dotnet/coreclr/blob/master/src/inc/readytorun.h + // + + [Flags] + public enum ReadyToRunHelper + { + Invalid = 0x00, + + // Not a real helper - handle to current module passed to delay load helpers. + Module = 0x01, + GSCookie = 0x02, + + // + // Delay load helpers + // + + // All delay load helpers use custom calling convention: + // - scratch register - address of indirection cell. 0 = address is inferred from callsite. + // - stack - section index, module handle + DelayLoad_MethodCall = 0x08, + + DelayLoad_Helper = 0x10, + DelayLoad_Helper_Obj = 0x11, + DelayLoad_Helper_ObjObj = 0x12, + + // Exception handling helpers + Throw = 0x20, + Rethrow = 0x21, + Overflow = 0x22, + RngChkFail = 0x23, + FailFast = 0x24, + ThrowNullRef = 0x25, + ThrowDivZero = 0x26, + + // Write barriers + WriteBarrier = 0x30, + CheckedWriteBarrier = 0x31, + ByRefWriteBarrier = 0x32, + + // Array helpers + Stelem_Ref = 0x38, + Ldelema_Ref = 0x39, + + MemSet = 0x40, + MemCpy = 0x41, + + // P/Invoke support + PInvokeBegin = 0x42, + PInvokeEnd = 0x43, + GCPoll = 0x44, + + // Get string handle lazily + GetString = 0x50, + + // Used by /Tuning for Profile optimizations + LogMethodEnter = 0x51, + + // Reflection helpers + GetRuntimeTypeHandle = 0x54, + GetRuntimeMethodHandle = 0x55, + GetRuntimeFieldHandle = 0x56, + + Box = 0x58, + Box_Nullable = 0x59, + Unbox = 0x5A, + Unbox_Nullable = 0x5B, + NewMultiDimArr = 0x5C, + NewMultiDimArr_NonVarArg = 0x5D, + + // Helpers used with generic handle lookup cases + NewObject = 0x60, + NewArray = 0x61, + CheckCastAny = 0x62, + CheckInstanceAny = 0x63, + GenericGcStaticBase = 0x64, + GenericNonGcStaticBase = 0x65, + GenericGcTlsBase = 0x66, + GenericNonGcTlsBase = 0x67, + VirtualFuncPtr = 0x68, + + // Long mul/div/shift ops + LMul = 0xC0, + LMulOfv = 0xC1, + ULMulOvf = 0xC2, + LDiv = 0xC3, + LMod = 0xC4, + ULDiv = 0xC5, + ULMod = 0xC6, + LLsh = 0xC7, + LRsh = 0xC8, + LRsz = 0xC9, + Lng2Dbl = 0xCA, + ULng2Dbl = 0xCB, + + // 32-bit division helpers + Div = 0xCC, + Mod = 0xCD, + UDiv = 0xCE, + UMod = 0xCF, + + // Floating point conversions + Dbl2Int = 0xD0, + Dbl2IntOvf = 0xD1, + Dbl2Lng = 0xD2, + Dbl2LngOvf = 0xD3, + Dbl2UInt = 0xD4, + Dbl2UIntOvf = 0xD5, + Dbl2ULng = 0xD6, + Dbl2ULngOvf = 0xD7, + + // Floating point ops + DblRem = 0xE0, + FltRem = 0xE1, + DblRound = 0xE2, + FltRound = 0xE3, + + // Personality rountines + PersonalityRoutine = 0xF0, + PersonalityRoutineFilterFunclet = 0xF1, + + // Synchronized methods + MonitorEnter = 0xF8, + MonitorExit = 0xF9, + + // JIT32 x86-specific write barriers + WriteBarrier_EAX = 0x100, + WriteBarrier_EBX = 0x101, + WriteBarrier_ECX = 0x102, + WriteBarrier_ESI = 0x103, + WriteBarrier_EDI = 0x104, + WriteBarrier_EBP = 0x105, + CheckedWriteBarrier_EAX = 0x106, + CheckedWriteBarrier_EBX = 0x107, + CheckedWriteBarrier_ECX = 0x108, + CheckedWriteBarrier_ESI = 0x109, + CheckedWriteBarrier_EDI = 0x10A, + CheckedWriteBarrier_EBP = 0x10B, + + // JIT32 x86-specific exception handling + EndCatch = 0x110, + + StackProbe = 0x111, + + // ********************************************************************************************** + // + // These are not actually part of the R2R file format. We have them here because it's convenient. + // + // ********************************************************************************************** + + // Marker to be used in asserts. + FirstFakeHelper, + + ThrowArgumentOutOfRange, + ThrowArgument, + ThrowPlatformNotSupported, + ThrowNotImplemented, + + DebugBreak, + + GetRuntimeType, + + AreTypesEquivalent, + + CheckCastClass, + CheckInstanceClass, + CheckCastArray, + CheckInstanceArray, + CheckCastInterface, + CheckInstanceInterface, + + // P/Invoke support + ReversePInvokeEnter, + ReversePInvokeExit, + + MonitorEnterStatic, + MonitorExitStatic, + + // GVM lookup helper + GVMLookupForSlot, + + // TypedReference + TypeHandleToRuntimeType, + GetRefAny, + TypeHandleToRuntimeTypeHandle, + } + + public static class ReadyToRunRuntimeConstants + { + public const int READYTORUN_PInvokeTransitionFrameSizeInPointerUnits = 11; + } +} diff --git a/src/coreclr/src/tools/Common/Internal/Text/Utf8String.cs b/src/coreclr/src/tools/Common/Internal/Text/Utf8String.cs new file mode 100644 index 00000000000..47e70135076 --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/Text/Utf8String.cs @@ -0,0 +1,151 @@ +// 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.Runtime.CompilerServices; +using System.Text; + +namespace Internal.Text +{ + public struct Utf8String : IEquatable, IComparable + { + private byte[] _value; + + public Utf8String(byte[] underlyingArray) + { + _value = underlyingArray; + } + + public Utf8String(string s) + { + _value = Encoding.UTF8.GetBytes(s); + } + + // TODO: This should return ReadOnlySpan instead once available + public byte[] UnderlyingArray => _value; + public int Length => _value.Length; + + // For now, define implicit conversions between string and Utf8String to aid the transition + // These conversions will be removed eventually + public static implicit operator Utf8String(string s) + { + return new Utf8String(s); + } + + public override string ToString() + { + return Encoding.UTF8.GetString(_value); + } + + public override bool Equals(object obj) + { + return (obj is Utf8String) && Equals((Utf8String)obj); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int _rotl(int value, int shift) + { + // This is expected to be optimized into a single rotl instruction + return (int)(((uint)value << shift) | ((uint)value >> (32 - shift))); + } + + public unsafe override int GetHashCode() + { + int length = _value.Length; + int hash = length; + fixed (byte* ap = _value) + { + byte* a = ap; + + while (length >= 4) + { + hash = (hash + _rotl(hash, 5)) ^ *(int*)a; + a += 4; length -= 4; + } + if (length >= 2) + { + hash = (hash + _rotl(hash, 5)) ^ *(short*)a; + a += 2; length -= 2; + } + if (length > 0) + { + hash = (hash + _rotl(hash, 5)) ^ *a; + } + hash += _rotl(hash, 7); + hash += _rotl(hash, 15); + return hash; + } + } + + public bool Equals(Utf8String other) + { + int length = _value.Length; + if (length != other.Length) + return false; + + if (_value == other._value) + return true; + + unsafe + { + fixed (byte* ap = _value) fixed (byte* bp = other._value) + { + byte* a = ap; + byte* b = bp; + + while (length >= 4) + { + if (*(int*)a != *(int*)b) return false; + a += 4; b += 4; length -= 4; + } + if (length >= 2) + { + if (*(short*)a != *(short*)b) return false; + a += 2; b += 2; length -= 2; + } + if (length > 0) + { + if (*a != *b) return false; + } + return true; + } + } + } + + private static int Compare(Utf8String strA, Utf8String strB) + { + int length = Math.Min(strA.Length, strB.Length); + + unsafe + { + fixed (byte* ap = strA._value) + fixed (byte* bp = strB._value) + { + byte* a = ap; + byte* b = bp; + + while (length > 0) + { + if (*a != *b) + return *a - *b; + a += 1; + b += 1; + length -= 1; + } + + // At this point, we have compared all the characters in at least one string. + // The longer string will be larger. + // We could optimize and compare lengths before iterating strings, but we want + // Foo and Foo1 to be sorted adjacent to eachother. + return strA.Length - strB.Length; + } + } + } + + public int CompareTo(Utf8String other) + { + return Compare(this, other); + } + } +} diff --git a/src/coreclr/src/tools/Common/Internal/Text/Utf8StringBuilder.cs b/src/coreclr/src/tools/Common/Internal/Text/Utf8StringBuilder.cs new file mode 100644 index 00000000000..0cdd95abcd4 --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/Text/Utf8StringBuilder.cs @@ -0,0 +1,152 @@ +// 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.Text; +using System.Diagnostics; + +namespace Internal.Text +{ + public class Utf8StringBuilder + { + private byte[] _buffer = Array.Empty(); + private int _length = 0; + + public Utf8StringBuilder() + { + } + + // TODO: This should return ReadOnlySpan instead once available + public byte[] UnderlyingArray => _buffer; + public int Length => _length; + + public Utf8StringBuilder Clear() + { + _length = 0; + return this; + } + + public Utf8StringBuilder Truncate(int newLength) + { + Debug.Assert(newLength <= _length); + _length = newLength; + return this; + } + + public Utf8StringBuilder Append(Utf8String value) + { + return Append(value.UnderlyingArray); + } + + public Utf8StringBuilder Append(byte[] value) + { + Ensure(value.Length); + Buffer.BlockCopy(value, 0, _buffer, _length, value.Length); + _length += value.Length; + return this; + } + + public Utf8StringBuilder Append(char value) + { + Ensure(1); + if (value > 0x7F) + return Append(Encoding.UTF8.GetBytes(new char[] { value })); + _buffer[_length++] = (byte)value; + return this; + } + + public Utf8StringBuilder Append(string value) + { + Ensure(value.Length); + + byte[] buffer = _buffer; + for (int i = 0; i < value.Length; i++) + { + char c = value[i]; + if (c > 0x7F) + return Append(Encoding.UTF8.GetBytes(value)); + buffer[_length+i] = (byte)c; + } + _length += value.Length; + + return this; + } + + public override string ToString() + { + return Encoding.UTF8.GetString(_buffer, 0, _length); + } + + public string ToString(int start) + { + return Encoding.UTF8.GetString(_buffer, start, _length - start); + } + + public Utf8String ToUtf8String() + { + var ret = new byte[_length]; + Buffer.BlockCopy(_buffer, 0, ret, 0, _length); + return new Utf8String(ret); + } + + private void Ensure(int extraSpace) + { + if ((uint)(_length + extraSpace) > (uint)_buffer.Length) + Grow(extraSpace); + } + + private void Grow(int extraSpace) + { + int newSize = Math.Max(2 * _buffer.Length, _length + extraSpace); + byte[] newBuffer = new byte[newSize]; + Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _length); + _buffer = newBuffer; + } + + // Find the boundary of the last character prior to a position + // If pos points to the last byte of a char, then return pos; Otherwise, + // return the position of the last byte of the preceding char. + public int LastCharBoundary(int pos) + { + Debug.Assert(pos < _length); + + if (_buffer[pos] < 128 /*10000000*/) + { + // This is a single byte character + return pos; + } + + int origPos = pos; + + // Skip following bytes of a multi-byte character until the first byte is seen + while (_buffer[pos] < 192 /*11000000*/) + { + pos--; + } + + if (pos == origPos - 3) + { + // We just skipped a four-byte character + Debug.Assert(_buffer[pos] >= 240 /*11110000*/); + return origPos; + } + + if (pos == origPos - 2 && _buffer[pos] < 240 && _buffer[pos] >= 224 /*11100000*/) + { + // We just skipped a three-byte character + return origPos; + } + + if (pos == origPos - 1 && _buffer[pos] < 224) + { + // We just skipped a two-byte character + Debug.Assert(_buffer[pos] >= 192 /*11000000*/); + return origPos; + } + + // We were in the middle of a multi-byte character + return pos - 1; + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs new file mode 100644 index 00000000000..1aa42f323d6 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs @@ -0,0 +1,3382 @@ + +// 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. + +// DO NOT EDIT THIS FILE! It IS AUTOGENERATED +using System; +using System.Runtime.InteropServices; + +namespace Internal.JitInterface +{ + unsafe partial class CorInfoImpl + { + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getMethodAttribs(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __setMethodAttribs(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getMethodSig(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __getMethodInfo(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoInline __canInline(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint pRestrictions); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __reportInliningDecision(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __canTailCall(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, [MarshalAs(UnmanagedType.I1)]bool fIsTailPrefix); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __reportTailCallDecision(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, [MarshalAs(UnmanagedType.I1)]bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getEHinfo(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getMethodClass(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_MODULE_STRUCT_* __getMethodModule(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getMethodVTableOffset(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, [MarshalAs(UnmanagedType.U1)] ref bool isRelative); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_METHOD_STRUCT_* __resolveVirtualMethod(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* virtualMethod, CORINFO_CLASS_STRUCT_* implementingClass, CORINFO_CONTEXT_STRUCT* ownerType); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_METHOD_STRUCT_* __getUnboxedEntry(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte* requiresInstMethodTableArg); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getDefaultEqualityComparerClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* elemType); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __expandRawHandleIntrinsic(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoIntrinsics __getIntrinsicID(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, byte* pMustExpand); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __isIntrinsicType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* classHnd); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoUnmanagedCallConv __getUnmanagedCallConv(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __pInvokeMarshalingRequired(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __satisfiesMethodConstraints(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [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(default(CallingConvention))] + delegate CorInfoInstantiationVerification __isInstantiationOfVerifiedGeneric(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __initConstraintsForVerification(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularClassConstraints, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularMethodConstraint); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoCanSkipVerificationResult __canSkipMethodVerification(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHandle); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __methodMustBeLoadedBeforeCodeIsRun(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_METHOD_STRUCT_* __mapMethodDeclToMethodImpl(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getGSCookie(IntPtr _this, IntPtr* ppException, IntPtr* pCookieVal, IntPtr** ppCookieVal); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __resolveToken(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __tryResolveToken(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __findSig(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __findCallSiteSig(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getTokenTypeAsHandle(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoCanSkipVerificationResult __canSkipVerification(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isValidToken(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint metaTOK); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isValidStringRef(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint metaTOK); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __shouldEnforceCallvirtRestriction(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* scope); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoType __asCorInfoType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __getClassName(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __getClassNameFromMetadata(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte** namespaceName); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getTypeInstantiationArgument(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, uint index); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate int __appendClassName(IntPtr _this, IntPtr* ppException, short** ppBuf, ref int pnBufLen, CORINFO_CLASS_STRUCT_* cls, [MarshalAs(UnmanagedType.Bool)]bool fNamespace, [MarshalAs(UnmanagedType.Bool)]bool fFullInst, [MarshalAs(UnmanagedType.Bool)]bool fAssembly); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isValueClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoInlineTypeCheck __canInlineTypeCheck(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CorInfoInlineTypeCheckSource source); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __canInlineTypeCheckWithObjectVTable(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getClassAttribs(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isStructRequiringStackAllocRetBuf(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_MODULE_STRUCT_* __getClassModule(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_ASSEMBLY_STRUCT_* __getModuleAssembly(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* mod); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __getAssemblyName(IntPtr _this, IntPtr* ppException, CORINFO_ASSEMBLY_STRUCT_* assem); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __LongLifetimeMalloc(IntPtr _this, IntPtr* ppException, UIntPtr sz); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __LongLifetimeFree(IntPtr _this, IntPtr* ppException, void* obj); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __getClassModuleIdForStatics(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getClassSize(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getHeapClassSize(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __canAllocateOnStack(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getClassAlignmentRequirement(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, [MarshalAs(UnmanagedType.Bool)]bool fDoubleAlignHint); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getClassGClayout(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getClassNumInstanceFields(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_FIELD_STRUCT_* __getFieldInClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, int num); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __checkMethodModifier(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, [MarshalAs(UnmanagedType.Bool)]bool fOptional); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoHelpFunc __getNewHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, byte* pHasSideEffects); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoHelpFunc __getNewArrHelper(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* arrayCls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoHelpFunc __getCastingHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool fThrowing); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoHelpFunc __getSharedCCtorHelper(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoHelpFunc __getSecurityPrologHelper(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getTypeForBox(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoHelpFunc __getBoxHelper(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoHelpFunc __getUnBoxHelper(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __getReadyToRunHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getReadyToRunDelegateCtorHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pTargetMethod, CORINFO_CLASS_STRUCT_* delegateType, ref CORINFO_LOOKUP pLookup); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __getHelperName(IntPtr _this, IntPtr* ppException, CorInfoHelpFunc helpFunc); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoInitClassResult __initClass(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context, [MarshalAs(UnmanagedType.Bool)]bool speculative); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __classMustBeLoadedBeforeCodeIsRun(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getBuiltinClass(IntPtr _this, IntPtr* ppException, CorInfoClassId classId); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoType __getTypeForPrimitiveValueClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoType __getTypeForPrimitiveNumericClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __canCast(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __areTypesEquivalent(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate TypeCompareState __compareTypesForCast(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate TypeCompareState __compareTypesForEquality(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __mergeClasses(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isMoreSpecificType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getParentType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoType __getChildType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __satisfiesClassConstraints(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isSDArray(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getArrayRank(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getArrayInitializationData(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, uint size); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoIsAccessAllowedResult __canAccessClass(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __getFieldName(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* ftn, byte** moduleName); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getFieldClass(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoType __getFieldType(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getFieldOffset(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __isWriteBarrierHelperRequired(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getFieldInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __isFieldStatic(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getBoundaries(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implictBoundaries); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __setBoundaries(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getVars(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, [MarshalAs(UnmanagedType.U1)] ref bool extendOthers); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __setVars(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __allocateArray(IntPtr _this, IntPtr* ppException, uint cBytes); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __freeArray(IntPtr _this, IntPtr* ppException, void* array); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_ARG_LIST_STRUCT_* __getArgNext(IntPtr _this, IntPtr* ppException, CORINFO_ARG_LIST_STRUCT_* args); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoTypeWithMod __getArgType(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getArgClass(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoType __getHFAType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* hClass); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate HRESULT __GetErrorHRESULT(IntPtr _this, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __GetErrorMessage(IntPtr _this, IntPtr* ppException, short* buffer, uint bufferLength); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate int __FilterException(IntPtr _this, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __HandleException(IntPtr _this, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __ThrowExceptionForJitResult(IntPtr _this, IntPtr* ppException, HRESULT result); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __ThrowExceptionForHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_HELPER_DESC throwHelper); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __runWithErrorTrap(IntPtr _this, IntPtr* ppException, void* function, void* parameter); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getEEInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_EE_INFO pEEInfoOut); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.LPWStr)]delegate string __getJitTimeLogFilename(IntPtr _this, IntPtr* ppException); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate mdToken __getMethodDefFromMethod(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hMethod); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __getMethodName(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte** moduleName); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __getMethodNameFromMetadata(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassName); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getMethodHash(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate byte* __findNameOfToken(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* moduleHandle, mdToken token, byte* szFQName, UIntPtr FQNameCapacity); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __getSystemVAmd64PassStructInRegisterDescriptor(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getThreadTLSIndex(IntPtr _this, IntPtr* ppException, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getInlinedCallFrameVptr(IntPtr _this, IntPtr* ppException, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate int* __getAddrOfCaptureThreadGlobal(IntPtr _this, IntPtr* ppException, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getHelperFtn(IntPtr _this, IntPtr* ppException, CorInfoHelpFunc ftnNum, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getFunctionEntryPoint(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getFunctionFixedEntryPoint(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getMethodSync(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CorInfoHelpFunc __getLazyStringLiteralHelper(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* handle); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_MODULE_STRUCT_* __embedModuleHandle(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __embedClassHandle(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_METHOD_STRUCT_* __embedMethodHandle(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_FIELD_STRUCT_* __embedFieldHandle(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __embedGenericHandle(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.Bool)]bool fEmbedParent, ref CORINFO_GENERICHANDLE_RESULT pResult); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getLocationOfThisType(IntPtr _this, IntPtr* ppException, out CORINFO_LOOKUP_KIND _return, CORINFO_METHOD_STRUCT_* context); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getPInvokeUnmanagedTarget(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getAddressOfPInvokeFixup(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getAddressOfPInvokeTarget(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __GetCookieForPInvokeCalliSig(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __canGetCookieForPInvokeCalliSig(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_JUST_MY_CODE_HANDLE_* __getJustMyCodeHandle(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __GetProfilingHandle(IntPtr _this, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)] ref bool pbHookFunction, ref void* pProfilerHandle, [MarshalAs(UnmanagedType.Bool)] ref bool pbIndirectedHandles); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getCallInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __canAccessFamily(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hCaller, CORINFO_CLASS_STRUCT_* hInstanceType); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isRIDClassDomainID(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getClassDomainID(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getFieldAddress(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, void** ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_CLASS_STRUCT_* __getStaticFieldCurrentClass(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate IntPtr __getVarArgsHandle(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* pSig, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __canGetVarArgsHandle(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* pSig); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate InfoAccessType __constructStringLiteral(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate InfoAccessType __emptyStringLiteral(IntPtr _this, IntPtr* ppException, ref void* ppValue); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getFieldThreadLocalStoreID(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __setOverride(IntPtr _this, IntPtr* ppException, IntPtr pOverride, CORINFO_METHOD_STRUCT_* currentMethod); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __addActiveDependency(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* moduleFrom, CORINFO_MODULE_STRUCT_* moduleTo); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate CORINFO_METHOD_STRUCT_* __GetDelegateCtor(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __MethodCompileComplete(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getTailCallCopyArgsThunk(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.I1)]delegate bool __convertPInvokeCalliToCall(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool mustConvert); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __getMemoryManager(IntPtr _this, IntPtr* ppException); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __allocMem(IntPtr _this, IntPtr* ppException, uint hotCodeSize, uint coldCodeSize, uint roDataSize, uint xcptnsCount, CorJitAllocMemFlag flag, ref void* hotCodeBlock, ref void* coldCodeBlock, ref void* roDataBlock); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __reserveUnwindInfo(IntPtr _this, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)]bool isFunclet, [MarshalAs(UnmanagedType.Bool)]bool isColdCode, uint unwindSize); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __allocUnwindInfo(IntPtr _this, IntPtr* ppException, byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void* __allocGCInfo(IntPtr _this, IntPtr* ppException, UIntPtr size); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __yieldExecution(IntPtr _this, IntPtr* ppException); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __setEHcount(IntPtr _this, IntPtr* ppException, uint cEH); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __setEHinfo(IntPtr _this, IntPtr* ppException, uint EHnumber, ref CORINFO_EH_CLAUSE clause); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + [return: MarshalAs(UnmanagedType.Bool)]delegate bool __logMsg(IntPtr _this, IntPtr* ppException, uint level, byte* fmt, IntPtr args); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate int __doAssert(IntPtr _this, IntPtr* ppException, byte* szFile, int iLine, byte* szExpr); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __reportFatalError(IntPtr _this, IntPtr* ppException, CorJitResult result); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate HRESULT __allocMethodBlockCounts(IntPtr _this, IntPtr* ppException, uint count, ref BlockCounts* pBlockCounts); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate HRESULT __getMethodBlockCounts(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHnd, ref uint pCount, ref BlockCounts* pBlockCounts, ref uint pNumRuns); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __recordCallSite(IntPtr _this, IntPtr* ppException, uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __recordRelocation(IntPtr _this, IntPtr* ppException, void* location, void* target, ushort fRelocType, ushort slotNum, int addlDelta); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate ushort __getRelocTypeHint(IntPtr _this, IntPtr* ppException, void* target); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __getModuleNativeEntryPointRange(IntPtr _this, IntPtr* ppException, ref void* pStart, ref void* pEnd); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getExpectedTargetArchitecture(IntPtr _this, IntPtr* ppException); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate uint __getJitFlags(IntPtr _this, IntPtr* ppException, ref CORJIT_FLAGS flags, uint sizeInBytes); + + static uint _getMethodAttribs(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodAttribs(ftn); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static void _setMethodAttribs(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) + { + var _this = GetThis(thisHandle); + try + { + _this.setMethodAttribs(ftn, attribs); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _getMethodSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) + { + var _this = GetThis(thisHandle); + try + { + _this.getMethodSig(ftn, sig, memberParent); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _getMethodInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodInfo(ftn, info); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static CorInfoInline _canInline(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint pRestrictions) + { + var _this = GetThis(thisHandle); + try + { + return _this.canInline(callerHnd, calleeHnd, ref pRestrictions); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoInline); + } + } + + static void _reportInliningDecision(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) + { + var _this = GetThis(thisHandle); + try + { + _this.reportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _canTailCall(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, [MarshalAs(UnmanagedType.I1)]bool fIsTailPrefix) + { + var _this = GetThis(thisHandle); + try + { + return _this.canTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static void _reportTailCallDecision(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, [MarshalAs(UnmanagedType.I1)]bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason) + { + var _this = GetThis(thisHandle); + try + { + _this.reportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _getEHinfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + var _this = GetThis(thisHandle); + try + { + _this.getEHinfo(ftn, EHnumber, ref clause); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static CORINFO_CLASS_STRUCT_* _getMethodClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodClass(method); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static CORINFO_MODULE_STRUCT_* _getMethodModule(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodModule(method); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_MODULE_STRUCT_*); + } + } + + static void _getMethodVTableOffset(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, [MarshalAs(UnmanagedType.U1)] ref bool isRelative) + { + var _this = GetThis(thisHandle); + try + { + _this.getMethodVTableOffset(method, ref offsetOfIndirection, ref offsetAfterIndirection, ref isRelative); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static CORINFO_METHOD_STRUCT_* _resolveVirtualMethod(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* virtualMethod, CORINFO_CLASS_STRUCT_* implementingClass, CORINFO_CONTEXT_STRUCT* ownerType) + { + var _this = GetThis(thisHandle); + try + { + return _this.resolveVirtualMethod(virtualMethod, implementingClass, ownerType); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_METHOD_STRUCT_*); + } + } + + static CORINFO_METHOD_STRUCT_* _getUnboxedEntry(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte* requiresInstMethodTableArg) + { + var _this = GetThis(thisHandle); + try + { + return _this.getUnboxedEntry(ftn, requiresInstMethodTableArg); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_METHOD_STRUCT_*); + } + } + + static CORINFO_CLASS_STRUCT_* _getDefaultEqualityComparerClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* elemType) + { + var _this = GetThis(thisHandle); + try + { + return _this.getDefaultEqualityComparerClass(elemType); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + 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, byte* pMustExpand) + { + var _this = GetThis(thisHandle); + try + { + return _this.getIntrinsicID(method, pMustExpand); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoIntrinsics); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _isIntrinsicType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* classHnd) + { + var _this = GetThis(thisHandle); + try + { + return _this.isIntrinsicType(classHnd); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static CorInfoUnmanagedCallConv _getUnmanagedCallConv(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) + { + var _this = GetThis(thisHandle); + try + { + return _this.getUnmanagedCallConv(method); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoUnmanagedCallConv); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _pInvokeMarshalingRequired(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) + { + var _this = GetThis(thisHandle); + try + { + return _this.pInvokeMarshalingRequired(method, callSiteSig); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _satisfiesMethodConstraints(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) + { + var _this = GetThis(thisHandle); + try + { + return _this.satisfiesMethodConstraints(parent, method); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _isCompatibleDelegate(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* objCls, CORINFO_CLASS_STRUCT_* methodParentCls, CORINFO_METHOD_STRUCT_* method, CORINFO_CLASS_STRUCT_* delegateCls, [MarshalAs(UnmanagedType.Bool)] ref bool pfIsOpenDelegate) + { + var _this = GetThis(thisHandle); + try + { + return _this.isCompatibleDelegate(objCls, methodParentCls, method, delegateCls, ref pfIsOpenDelegate); + } + 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); + try + { + return _this.isInstantiationOfVerifiedGeneric(method); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoInstantiationVerification); + } + } + + static void _initConstraintsForVerification(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularClassConstraints, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularMethodConstraint) + { + var _this = GetThis(thisHandle); + try + { + _this.initConstraintsForVerification(method, ref pfHasCircularClassConstraints, ref pfHasCircularMethodConstraint); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static CorInfoCanSkipVerificationResult _canSkipMethodVerification(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHandle) + { + var _this = GetThis(thisHandle); + try + { + return _this.canSkipMethodVerification(ftnHandle); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoCanSkipVerificationResult); + } + } + + static void _methodMustBeLoadedBeforeCodeIsRun(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) + { + var _this = GetThis(thisHandle); + try + { + _this.methodMustBeLoadedBeforeCodeIsRun(method); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static CORINFO_METHOD_STRUCT_* _mapMethodDeclToMethodImpl(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) + { + var _this = GetThis(thisHandle); + try + { + return _this.mapMethodDeclToMethodImpl(method); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_METHOD_STRUCT_*); + } + } + + static void _getGSCookie(IntPtr thisHandle, IntPtr* ppException, IntPtr* pCookieVal, IntPtr** ppCookieVal) + { + var _this = GetThis(thisHandle); + try + { + _this.getGSCookie(pCookieVal, ppCookieVal); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _resolveToken(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + var _this = GetThis(thisHandle); + try + { + _this.resolveToken(ref pResolvedToken); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _tryResolveToken(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + var _this = GetThis(thisHandle); + try + { + _this.tryResolveToken(ref pResolvedToken); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _findSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + var _this = GetThis(thisHandle); + try + { + _this.findSig(module, sigTOK, context, sig); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _findCallSiteSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + var _this = GetThis(thisHandle); + try + { + _this.findCallSiteSig(module, methTOK, context, sig); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static CORINFO_CLASS_STRUCT_* _getTokenTypeAsHandle(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + var _this = GetThis(thisHandle); + try + { + return _this.getTokenTypeAsHandle(ref pResolvedToken); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static CorInfoCanSkipVerificationResult _canSkipVerification(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module) + { + var _this = GetThis(thisHandle); + try + { + return _this.canSkipVerification(module); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoCanSkipVerificationResult); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _isValidToken(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint metaTOK) + { + var _this = GetThis(thisHandle); + try + { + return _this.isValidToken(module, metaTOK); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _isValidStringRef(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint metaTOK) + { + var _this = GetThis(thisHandle); + try + { + return _this.isValidStringRef(module, metaTOK); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _shouldEnforceCallvirtRestriction(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* scope) + { + var _this = GetThis(thisHandle); + try + { + return _this.shouldEnforceCallvirtRestriction(scope); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static CorInfoType _asCorInfoType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.asCorInfoType(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoType); + } + } + + static byte* _getClassName(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassName(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + static byte* _getClassNameFromMetadata(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassNameFromMetadata(cls, namespaceName); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + static CORINFO_CLASS_STRUCT_* _getTypeInstantiationArgument(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, uint index) + { + var _this = GetThis(thisHandle); + try + { + return _this.getTypeInstantiationArgument(cls, index); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static int _appendClassName(IntPtr thisHandle, IntPtr* ppException, short** ppBuf, ref int pnBufLen, CORINFO_CLASS_STRUCT_* cls, [MarshalAs(UnmanagedType.Bool)]bool fNamespace, [MarshalAs(UnmanagedType.Bool)]bool fFullInst, [MarshalAs(UnmanagedType.Bool)]bool fAssembly) + { + var _this = GetThis(thisHandle); + try + { + return _this.appendClassName(ppBuf, ref pnBufLen, cls, fNamespace, fFullInst, fAssembly); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(int); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _isValueClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.isValueClass(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static CorInfoInlineTypeCheck _canInlineTypeCheck(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CorInfoInlineTypeCheckSource source) + { + var _this = GetThis(thisHandle); + try + { + return _this.canInlineTypeCheck(cls, source); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoInlineTypeCheck); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _canInlineTypeCheckWithObjectVTable(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.canInlineTypeCheckWithObjectVTable(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static uint _getClassAttribs(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassAttribs(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _isStructRequiringStackAllocRetBuf(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.isStructRequiringStackAllocRetBuf(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static CORINFO_MODULE_STRUCT_* _getClassModule(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassModule(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_MODULE_STRUCT_*); + } + } + + static CORINFO_ASSEMBLY_STRUCT_* _getModuleAssembly(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* mod) + { + var _this = GetThis(thisHandle); + try + { + return _this.getModuleAssembly(mod); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_ASSEMBLY_STRUCT_*); + } + } + + static byte* _getAssemblyName(IntPtr thisHandle, IntPtr* ppException, CORINFO_ASSEMBLY_STRUCT_* assem) + { + var _this = GetThis(thisHandle); + try + { + return _this.getAssemblyName(assem); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + static void* _LongLifetimeMalloc(IntPtr thisHandle, IntPtr* ppException, UIntPtr sz) + { + var _this = GetThis(thisHandle); + try + { + return _this.LongLifetimeMalloc(sz); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static void _LongLifetimeFree(IntPtr thisHandle, IntPtr* ppException, void* obj) + { + var _this = GetThis(thisHandle); + try + { + _this.LongLifetimeFree(obj); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static byte* _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassModuleIdForStatics(cls, pModule, ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + static uint _getClassSize(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassSize(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static uint _getHeapClassSize(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getHeapClassSize(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _canAllocateOnStack(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.canAllocateOnStack(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static uint _getClassAlignmentRequirement(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, [MarshalAs(UnmanagedType.Bool)]bool fDoubleAlignHint) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassAlignmentRequirement(cls, fDoubleAlignHint); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static uint _getClassGClayout(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassGClayout(cls, gcPtrs); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static uint _getClassNumInstanceFields(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassNumInstanceFields(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static CORINFO_FIELD_STRUCT_* _getFieldInClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, int num) + { + var _this = GetThis(thisHandle); + try + { + return _this.getFieldInClass(clsHnd, num); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_FIELD_STRUCT_*); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _checkMethodModifier(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, [MarshalAs(UnmanagedType.Bool)]bool fOptional) + { + var _this = GetThis(thisHandle); + try + { + return _this.checkMethodModifier(hMethod, modifier, fOptional); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static CorInfoHelpFunc _getNewHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, byte* pHasSideEffects) + { + var _this = GetThis(thisHandle); + try + { + return _this.getNewHelper(ref pResolvedToken, callerHandle, pHasSideEffects); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoHelpFunc); + } + } + + static CorInfoHelpFunc _getNewArrHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* arrayCls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getNewArrHelper(arrayCls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoHelpFunc); + } + } + + static CorInfoHelpFunc _getCastingHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool fThrowing) + { + var _this = GetThis(thisHandle); + try + { + return _this.getCastingHelper(ref pResolvedToken, fThrowing); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoHelpFunc); + } + } + + static CorInfoHelpFunc _getSharedCCtorHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd) + { + var _this = GetThis(thisHandle); + try + { + return _this.getSharedCCtorHelper(clsHnd); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoHelpFunc); + } + } + + static CorInfoHelpFunc _getSecurityPrologHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn) + { + var _this = GetThis(thisHandle); + try + { + return _this.getSecurityPrologHelper(ftn); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoHelpFunc); + } + } + + static CORINFO_CLASS_STRUCT_* _getTypeForBox(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getTypeForBox(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static CorInfoHelpFunc _getBoxHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getBoxHelper(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoHelpFunc); + } + } + + static CorInfoHelpFunc _getUnBoxHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getUnBoxHelper(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoHelpFunc); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _getReadyToRunHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup) + { + var _this = GetThis(thisHandle); + try + { + return _this.getReadyToRunHelper(ref pResolvedToken, ref pGenericLookupKind, id, ref pLookup); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static void _getReadyToRunDelegateCtorHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pTargetMethod, CORINFO_CLASS_STRUCT_* delegateType, ref CORINFO_LOOKUP pLookup) + { + var _this = GetThis(thisHandle); + try + { + _this.getReadyToRunDelegateCtorHelper(ref pTargetMethod, delegateType, ref pLookup); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static byte* _getHelperName(IntPtr thisHandle, IntPtr* ppException, CorInfoHelpFunc helpFunc) + { + var _this = GetThis(thisHandle); + try + { + return _this.getHelperName(helpFunc); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + static CorInfoInitClassResult _initClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context, [MarshalAs(UnmanagedType.Bool)]bool speculative) + { + var _this = GetThis(thisHandle); + try + { + return _this.initClass(field, method, context, speculative); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoInitClassResult); + } + } + + static void _classMustBeLoadedBeforeCodeIsRun(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + _this.classMustBeLoadedBeforeCodeIsRun(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static CORINFO_CLASS_STRUCT_* _getBuiltinClass(IntPtr thisHandle, IntPtr* ppException, CorInfoClassId classId) + { + var _this = GetThis(thisHandle); + try + { + return _this.getBuiltinClass(classId); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static CorInfoType _getTypeForPrimitiveValueClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getTypeForPrimitiveValueClass(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoType); + } + } + + static CorInfoType _getTypeForPrimitiveNumericClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getTypeForPrimitiveNumericClass(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoType); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _canCast(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) + { + var _this = GetThis(thisHandle); + try + { + return _this.canCast(child, parent); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _areTypesEquivalent(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + var _this = GetThis(thisHandle); + try + { + return _this.areTypesEquivalent(cls1, cls2); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static TypeCompareState _compareTypesForCast(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) + { + var _this = GetThis(thisHandle); + try + { + return _this.compareTypesForCast(fromClass, toClass); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(TypeCompareState); + } + } + + static TypeCompareState _compareTypesForEquality(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + var _this = GetThis(thisHandle); + try + { + return _this.compareTypesForEquality(cls1, cls2); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(TypeCompareState); + } + } + + static CORINFO_CLASS_STRUCT_* _mergeClasses(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + var _this = GetThis(thisHandle); + try + { + return _this.mergeClasses(cls1, cls2); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _isMoreSpecificType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + var _this = GetThis(thisHandle); + try + { + return _this.isMoreSpecificType(cls1, cls2); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static CORINFO_CLASS_STRUCT_* _getParentType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getParentType(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static CorInfoType _getChildType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) + { + var _this = GetThis(thisHandle); + try + { + return _this.getChildType(clsHnd, clsRet); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoType); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _satisfiesClassConstraints(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.satisfiesClassConstraints(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _isSDArray(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.isSDArray(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static uint _getArrayRank(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getArrayRank(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static void* _getArrayInitializationData(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, uint size) + { + var _this = GetThis(thisHandle); + try + { + return _this.getArrayInitializationData(field, size); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static CorInfoIsAccessAllowedResult _canAccessClass(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) + { + var _this = GetThis(thisHandle); + try + { + return _this.canAccessClass(ref pResolvedToken, callerHandle, ref pAccessHelper); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoIsAccessAllowedResult); + } + } + + static byte* _getFieldName(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* ftn, byte** moduleName) + { + var _this = GetThis(thisHandle); + try + { + return _this.getFieldName(ftn, moduleName); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + static CORINFO_CLASS_STRUCT_* _getFieldClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field) + { + var _this = GetThis(thisHandle); + try + { + return _this.getFieldClass(field); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static CorInfoType _getFieldType(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent) + { + var _this = GetThis(thisHandle); + try + { + return _this.getFieldType(field, structType, memberParent); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoType); + } + } + + static uint _getFieldOffset(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field) + { + var _this = GetThis(thisHandle); + try + { + return _this.getFieldOffset(field); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _isWriteBarrierHelperRequired(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field) + { + var _this = GetThis(thisHandle); + try + { + return _this.isWriteBarrierHelperRequired(field); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static void _getFieldInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + { + var _this = GetThis(thisHandle); + try + { + _this.getFieldInfo(ref pResolvedToken, callerHandle, flags, pResult); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _isFieldStatic(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd) + { + var _this = GetThis(thisHandle); + try + { + return _this.isFieldStatic(fldHnd); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static void _getBoundaries(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implictBoundaries) + { + var _this = GetThis(thisHandle); + try + { + _this.getBoundaries(ftn, ref cILOffsets, ref pILOffsets, implictBoundaries); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _setBoundaries(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) + { + var _this = GetThis(thisHandle); + try + { + _this.setBoundaries(ftn, cMap, pMap); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _getVars(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, [MarshalAs(UnmanagedType.U1)] ref bool extendOthers) + { + var _this = GetThis(thisHandle); + try + { + _this.getVars(ftn, ref cVars, vars, ref extendOthers); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _setVars(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) + { + var _this = GetThis(thisHandle); + try + { + _this.setVars(ftn, cVars, vars); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void* _allocateArray(IntPtr thisHandle, IntPtr* ppException, uint cBytes) + { + var _this = GetThis(thisHandle); + try + { + return _this.allocateArray(cBytes); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static void _freeArray(IntPtr thisHandle, IntPtr* ppException, void* array) + { + var _this = GetThis(thisHandle); + try + { + _this.freeArray(array); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static CORINFO_ARG_LIST_STRUCT_* _getArgNext(IntPtr thisHandle, IntPtr* ppException, CORINFO_ARG_LIST_STRUCT_* args) + { + var _this = GetThis(thisHandle); + try + { + return _this.getArgNext(args); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_ARG_LIST_STRUCT_*); + } + } + + static CorInfoTypeWithMod _getArgType(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet) + { + var _this = GetThis(thisHandle); + try + { + return _this.getArgType(sig, args, vcTypeRet); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoTypeWithMod); + } + } + + static CORINFO_CLASS_STRUCT_* _getArgClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) + { + var _this = GetThis(thisHandle); + try + { + return _this.getArgClass(sig, args); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static CorInfoType _getHFAType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* hClass) + { + var _this = GetThis(thisHandle); + try + { + return _this.getHFAType(hClass); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoType); + } + } + + static HRESULT _GetErrorHRESULT(IntPtr thisHandle, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers) + { + var _this = GetThis(thisHandle); + try + { + return _this.GetErrorHRESULT(pExceptionPointers); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(HRESULT); + } + } + + static uint _GetErrorMessage(IntPtr thisHandle, IntPtr* ppException, short* buffer, uint bufferLength) + { + var _this = GetThis(thisHandle); + try + { + return _this.GetErrorMessage(buffer, bufferLength); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static int _FilterException(IntPtr thisHandle, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers) + { + var _this = GetThis(thisHandle); + try + { + return _this.FilterException(pExceptionPointers); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(int); + } + } + + static void _HandleException(IntPtr thisHandle, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers) + { + var _this = GetThis(thisHandle); + try + { + _this.HandleException(pExceptionPointers); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _ThrowExceptionForJitResult(IntPtr thisHandle, IntPtr* ppException, HRESULT result) + { + var _this = GetThis(thisHandle); + try + { + _this.ThrowExceptionForJitResult(result); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _ThrowExceptionForHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_HELPER_DESC throwHelper) + { + var _this = GetThis(thisHandle); + try + { + _this.ThrowExceptionForHelper(ref throwHelper); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _runWithErrorTrap(IntPtr thisHandle, IntPtr* ppException, void* function, void* parameter) + { + var _this = GetThis(thisHandle); + try + { + return _this.runWithErrorTrap(function, parameter); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static void _getEEInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_EE_INFO pEEInfoOut) + { + var _this = GetThis(thisHandle); + try + { + _this.getEEInfo(ref pEEInfoOut); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + [return: MarshalAs(UnmanagedType.LPWStr)]static string _getJitTimeLogFilename(IntPtr thisHandle, IntPtr* ppException) + { + var _this = GetThis(thisHandle); + try + { + return _this.getJitTimeLogFilename(); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(string); + } + } + + static mdToken _getMethodDefFromMethod(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hMethod) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodDefFromMethod(hMethod); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(mdToken); + } + } + + static byte* _getMethodName(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte** moduleName) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodName(ftn, moduleName); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + static byte* _getMethodNameFromMetadata(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassName) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassName); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + static uint _getMethodHash(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodHash(ftn); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static byte* _findNameOfToken(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* moduleHandle, mdToken token, byte* szFQName, UIntPtr FQNameCapacity) + { + var _this = GetThis(thisHandle); + try + { + return _this.findNameOfToken(moduleHandle, token, szFQName, FQNameCapacity); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(byte*); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _getSystemVAmd64PassStructInRegisterDescriptor(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) + { + var _this = GetThis(thisHandle); + try + { + return _this.getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static uint _getThreadTLSIndex(IntPtr thisHandle, IntPtr* ppException, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getThreadTLSIndex(ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static void* _getInlinedCallFrameVptr(IntPtr thisHandle, IntPtr* ppException, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getInlinedCallFrameVptr(ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static int* _getAddrOfCaptureThreadGlobal(IntPtr thisHandle, IntPtr* ppException, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getAddrOfCaptureThreadGlobal(ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(int*); + } + } + + static void* _getHelperFtn(IntPtr thisHandle, IntPtr* ppException, CorInfoHelpFunc ftnNum, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getHelperFtn(ftnNum, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static void _getFunctionEntryPoint(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) + { + var _this = GetThis(thisHandle); + try + { + _this.getFunctionEntryPoint(ftn, ref pResult, accessFlags); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _getFunctionFixedEntryPoint(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult) + { + var _this = GetThis(thisHandle); + try + { + _this.getFunctionFixedEntryPoint(ftn, ref pResult); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void* _getMethodSync(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodSync(ftn, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static CorInfoHelpFunc _getLazyStringLiteralHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* handle) + { + var _this = GetThis(thisHandle); + try + { + return _this.getLazyStringLiteralHelper(handle); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CorInfoHelpFunc); + } + } + + static CORINFO_MODULE_STRUCT_* _embedModuleHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.embedModuleHandle(handle, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_MODULE_STRUCT_*); + } + } + + static CORINFO_CLASS_STRUCT_* _embedClassHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.embedClassHandle(handle, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static CORINFO_METHOD_STRUCT_* _embedMethodHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.embedMethodHandle(handle, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_METHOD_STRUCT_*); + } + } + + static CORINFO_FIELD_STRUCT_* _embedFieldHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.embedFieldHandle(handle, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_FIELD_STRUCT_*); + } + } + + static void _embedGenericHandle(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.Bool)]bool fEmbedParent, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + var _this = GetThis(thisHandle); + try + { + _this.embedGenericHandle(ref pResolvedToken, fEmbedParent, ref pResult); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _getLocationOfThisType(IntPtr thisHandle, IntPtr* ppException, out CORINFO_LOOKUP_KIND _return, CORINFO_METHOD_STRUCT_* context) + { + var _this = GetThis(thisHandle); + try + { + _this.getLocationOfThisType(out _return, context); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + _return = default(CORINFO_LOOKUP_KIND); + } + } + + static void* _getPInvokeUnmanagedTarget(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getPInvokeUnmanagedTarget(method, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static void* _getAddressOfPInvokeFixup(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getAddressOfPInvokeFixup(method, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static void _getAddressOfPInvokeTarget(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) + { + var _this = GetThis(thisHandle); + try + { + _this.getAddressOfPInvokeTarget(method, ref pLookup); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void* _GetCookieForPInvokeCalliSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.GetCookieForPInvokeCalliSig(szMetaSig, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _canGetCookieForPInvokeCalliSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig) + { + var _this = GetThis(thisHandle); + try + { + return _this.canGetCookieForPInvokeCalliSig(szMetaSig); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static CORINFO_JUST_MY_CODE_HANDLE_* _getJustMyCodeHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getJustMyCodeHandle(method, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_JUST_MY_CODE_HANDLE_*); + } + } + + static void _GetProfilingHandle(IntPtr thisHandle, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)] ref bool pbHookFunction, ref void* pProfilerHandle, [MarshalAs(UnmanagedType.Bool)] ref bool pbIndirectedHandles) + { + var _this = GetThis(thisHandle); + try + { + _this.GetProfilingHandle(ref pbHookFunction, ref pProfilerHandle, ref pbIndirectedHandles); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _getCallInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) + { + var _this = GetThis(thisHandle); + try + { + _this.getCallInfo(ref pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _canAccessFamily(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hCaller, CORINFO_CLASS_STRUCT_* hInstanceType) + { + var _this = GetThis(thisHandle); + try + { + return _this.canAccessFamily(hCaller, hInstanceType); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _isRIDClassDomainID(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.isRIDClassDomainID(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassDomainID(cls, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static void* _getFieldAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, void** ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getFieldAddress(field, ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static CORINFO_CLASS_STRUCT_* _getStaticFieldCurrentClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + var _this = GetThis(thisHandle); + try + { + return _this.getStaticFieldCurrentClass(field, pIsSpeculative); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_CLASS_STRUCT_*); + } + } + + static IntPtr _getVarArgsHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* pSig, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getVarArgsHandle(pSig, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(IntPtr); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _canGetVarArgsHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* pSig) + { + var _this = GetThis(thisHandle); + try + { + return _this.canGetVarArgsHandle(pSig); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static InfoAccessType _constructStringLiteral(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue) + { + var _this = GetThis(thisHandle); + try + { + return _this.constructStringLiteral(module, metaTok, ref ppValue); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(InfoAccessType); + } + } + + static InfoAccessType _emptyStringLiteral(IntPtr thisHandle, IntPtr* ppException, ref void* ppValue) + { + var _this = GetThis(thisHandle); + try + { + return _this.emptyStringLiteral(ref ppValue); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(InfoAccessType); + } + } + + static uint _getFieldThreadLocalStoreID(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getFieldThreadLocalStoreID(field, ref ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static void _setOverride(IntPtr thisHandle, IntPtr* ppException, IntPtr pOverride, CORINFO_METHOD_STRUCT_* currentMethod) + { + var _this = GetThis(thisHandle); + try + { + _this.setOverride(pOverride, currentMethod); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _addActiveDependency(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* moduleFrom, CORINFO_MODULE_STRUCT_* moduleTo) + { + var _this = GetThis(thisHandle); + try + { + _this.addActiveDependency(moduleFrom, moduleTo); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static CORINFO_METHOD_STRUCT_* _GetDelegateCtor(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) + { + var _this = GetThis(thisHandle); + try + { + return _this.GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, ref pCtorData); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(CORINFO_METHOD_STRUCT_*); + } + } + + static void _MethodCompileComplete(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd) + { + var _this = GetThis(thisHandle); + try + { + _this.MethodCompileComplete(methHnd); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void* _getTailCallCopyArgsThunk(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) + { + var _this = GetThis(thisHandle); + try + { + return _this.getTailCallCopyArgsThunk(pSig, flags); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + [return: MarshalAs(UnmanagedType.I1)]static bool _convertPInvokeCalliToCall(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool mustConvert) + { + var _this = GetThis(thisHandle); + try + { + return _this.convertPInvokeCalliToCall(ref pResolvedToken, mustConvert); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static void* _getMemoryManager(IntPtr thisHandle, IntPtr* ppException) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMemoryManager(); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static void _allocMem(IntPtr thisHandle, IntPtr* ppException, uint hotCodeSize, uint coldCodeSize, uint roDataSize, uint xcptnsCount, CorJitAllocMemFlag flag, ref void* hotCodeBlock, ref void* coldCodeBlock, ref void* roDataBlock) + { + var _this = GetThis(thisHandle); + try + { + _this.allocMem(hotCodeSize, coldCodeSize, roDataSize, xcptnsCount, flag, ref hotCodeBlock, ref coldCodeBlock, ref roDataBlock); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _reserveUnwindInfo(IntPtr thisHandle, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)]bool isFunclet, [MarshalAs(UnmanagedType.Bool)]bool isColdCode, uint unwindSize) + { + var _this = GetThis(thisHandle); + try + { + _this.reserveUnwindInfo(isFunclet, isColdCode, unwindSize); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _allocUnwindInfo(IntPtr thisHandle, IntPtr* ppException, byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) + { + var _this = GetThis(thisHandle); + try + { + _this.allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void* _allocGCInfo(IntPtr thisHandle, IntPtr* ppException, UIntPtr size) + { + var _this = GetThis(thisHandle); + try + { + return _this.allocGCInfo(size); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(void*); + } + } + + static void _yieldExecution(IntPtr thisHandle, IntPtr* ppException) + { + var _this = GetThis(thisHandle); + try + { + _this.yieldExecution(); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _setEHcount(IntPtr thisHandle, IntPtr* ppException, uint cEH) + { + var _this = GetThis(thisHandle); + try + { + _this.setEHcount(cEH); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _setEHinfo(IntPtr thisHandle, IntPtr* ppException, uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + var _this = GetThis(thisHandle); + try + { + _this.setEHinfo(EHnumber, ref clause); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + [return: MarshalAs(UnmanagedType.Bool)]static bool _logMsg(IntPtr thisHandle, IntPtr* ppException, uint level, byte* fmt, IntPtr args) + { + var _this = GetThis(thisHandle); + try + { + return _this.logMsg(level, fmt, args); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(bool); + } + } + + static int _doAssert(IntPtr thisHandle, IntPtr* ppException, byte* szFile, int iLine, byte* szExpr) + { + var _this = GetThis(thisHandle); + try + { + return _this.doAssert(szFile, iLine, szExpr); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(int); + } + } + + static void _reportFatalError(IntPtr thisHandle, IntPtr* ppException, CorJitResult result) + { + var _this = GetThis(thisHandle); + try + { + _this.reportFatalError(result); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static HRESULT _allocMethodBlockCounts(IntPtr thisHandle, IntPtr* ppException, uint count, ref BlockCounts* pBlockCounts) + { + var _this = GetThis(thisHandle); + try + { + return _this.allocMethodBlockCounts(count, ref pBlockCounts); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(HRESULT); + } + } + + static HRESULT _getMethodBlockCounts(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHnd, ref uint pCount, ref BlockCounts* pBlockCounts, ref uint pNumRuns) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodBlockCounts(ftnHnd, ref pCount, ref pBlockCounts, ref pNumRuns); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(HRESULT); + } + } + + static void _recordCallSite(IntPtr thisHandle, IntPtr* ppException, uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) + { + var _this = GetThis(thisHandle); + try + { + _this.recordCallSite(instrOffset, callSig, methodHandle); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static void _recordRelocation(IntPtr thisHandle, IntPtr* ppException, void* location, void* target, ushort fRelocType, ushort slotNum, int addlDelta) + { + var _this = GetThis(thisHandle); + try + { + _this.recordRelocation(location, target, fRelocType, slotNum, addlDelta); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static ushort _getRelocTypeHint(IntPtr thisHandle, IntPtr* ppException, void* target) + { + var _this = GetThis(thisHandle); + try + { + return _this.getRelocTypeHint(target); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(ushort); + } + } + + static void _getModuleNativeEntryPointRange(IntPtr thisHandle, IntPtr* ppException, ref void* pStart, ref void* pEnd) + { + var _this = GetThis(thisHandle); + try + { + _this.getModuleNativeEntryPointRange(ref pStart, ref pEnd); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static uint _getExpectedTargetArchitecture(IntPtr thisHandle, IntPtr* ppException) + { + var _this = GetThis(thisHandle); + try + { + return _this.getExpectedTargetArchitecture(); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, ref CORJIT_FLAGS flags, uint sizeInBytes) + { + var _this = GetThis(thisHandle); + try + { + return _this.getJitFlags(ref flags, sizeInBytes); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(uint); + } + } + + + static IntPtr GetUnmanagedCallbacks(out Object keepAlive) + { + IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 179); + Object[] delegates = new Object[179]; + + var d0 = new __getMethodAttribs(_getMethodAttribs); + callbacks[0] = Marshal.GetFunctionPointerForDelegate(d0); + delegates[0] = d0; + var d1 = new __setMethodAttribs(_setMethodAttribs); + callbacks[1] = Marshal.GetFunctionPointerForDelegate(d1); + delegates[1] = d1; + var d2 = new __getMethodSig(_getMethodSig); + callbacks[2] = Marshal.GetFunctionPointerForDelegate(d2); + delegates[2] = d2; + var d3 = new __getMethodInfo(_getMethodInfo); + callbacks[3] = Marshal.GetFunctionPointerForDelegate(d3); + delegates[3] = d3; + var d4 = new __canInline(_canInline); + callbacks[4] = Marshal.GetFunctionPointerForDelegate(d4); + delegates[4] = d4; + var d5 = new __reportInliningDecision(_reportInliningDecision); + callbacks[5] = Marshal.GetFunctionPointerForDelegate(d5); + delegates[5] = d5; + var d6 = new __canTailCall(_canTailCall); + callbacks[6] = Marshal.GetFunctionPointerForDelegate(d6); + delegates[6] = d6; + var d7 = new __reportTailCallDecision(_reportTailCallDecision); + callbacks[7] = Marshal.GetFunctionPointerForDelegate(d7); + delegates[7] = d7; + var d8 = new __getEHinfo(_getEHinfo); + callbacks[8] = Marshal.GetFunctionPointerForDelegate(d8); + delegates[8] = d8; + var d9 = new __getMethodClass(_getMethodClass); + callbacks[9] = Marshal.GetFunctionPointerForDelegate(d9); + delegates[9] = d9; + var d10 = new __getMethodModule(_getMethodModule); + callbacks[10] = Marshal.GetFunctionPointerForDelegate(d10); + delegates[10] = d10; + var d11 = new __getMethodVTableOffset(_getMethodVTableOffset); + callbacks[11] = Marshal.GetFunctionPointerForDelegate(d11); + delegates[11] = d11; + var d12 = new __resolveVirtualMethod(_resolveVirtualMethod); + callbacks[12] = Marshal.GetFunctionPointerForDelegate(d12); + delegates[12] = d12; + var d13 = new __getUnboxedEntry(_getUnboxedEntry); + callbacks[13] = Marshal.GetFunctionPointerForDelegate(d13); + delegates[13] = d13; + var d14 = new __getDefaultEqualityComparerClass(_getDefaultEqualityComparerClass); + callbacks[14] = Marshal.GetFunctionPointerForDelegate(d14); + delegates[14] = d14; + var d15 = new __expandRawHandleIntrinsic(_expandRawHandleIntrinsic); + callbacks[15] = Marshal.GetFunctionPointerForDelegate(d15); + delegates[15] = d15; + var d16 = new __getIntrinsicID(_getIntrinsicID); + callbacks[16] = Marshal.GetFunctionPointerForDelegate(d16); + delegates[16] = d16; + var d17 = new __isIntrinsicType(_isIntrinsicType); + callbacks[17] = Marshal.GetFunctionPointerForDelegate(d17); + delegates[17] = d17; + var d18 = new __getUnmanagedCallConv(_getUnmanagedCallConv); + callbacks[18] = Marshal.GetFunctionPointerForDelegate(d18); + delegates[18] = d18; + var d19 = new __pInvokeMarshalingRequired(_pInvokeMarshalingRequired); + callbacks[19] = Marshal.GetFunctionPointerForDelegate(d19); + delegates[19] = d19; + var d20 = new __satisfiesMethodConstraints(_satisfiesMethodConstraints); + callbacks[20] = Marshal.GetFunctionPointerForDelegate(d20); + delegates[20] = d20; + var d21 = new __isCompatibleDelegate(_isCompatibleDelegate); + callbacks[21] = Marshal.GetFunctionPointerForDelegate(d21); + delegates[21] = d21; + var d22 = new __isInstantiationOfVerifiedGeneric(_isInstantiationOfVerifiedGeneric); + callbacks[22] = Marshal.GetFunctionPointerForDelegate(d22); + delegates[22] = d22; + var d23 = new __initConstraintsForVerification(_initConstraintsForVerification); + callbacks[23] = Marshal.GetFunctionPointerForDelegate(d23); + delegates[23] = d23; + var d24 = new __canSkipMethodVerification(_canSkipMethodVerification); + callbacks[24] = Marshal.GetFunctionPointerForDelegate(d24); + delegates[24] = d24; + var d25 = new __methodMustBeLoadedBeforeCodeIsRun(_methodMustBeLoadedBeforeCodeIsRun); + callbacks[25] = Marshal.GetFunctionPointerForDelegate(d25); + delegates[25] = d25; + var d26 = new __mapMethodDeclToMethodImpl(_mapMethodDeclToMethodImpl); + callbacks[26] = Marshal.GetFunctionPointerForDelegate(d26); + delegates[26] = d26; + var d27 = new __getGSCookie(_getGSCookie); + callbacks[27] = Marshal.GetFunctionPointerForDelegate(d27); + delegates[27] = d27; + var d28 = new __resolveToken(_resolveToken); + callbacks[28] = Marshal.GetFunctionPointerForDelegate(d28); + delegates[28] = d28; + var d29 = new __tryResolveToken(_tryResolveToken); + callbacks[29] = Marshal.GetFunctionPointerForDelegate(d29); + delegates[29] = d29; + var d30 = new __findSig(_findSig); + callbacks[30] = Marshal.GetFunctionPointerForDelegate(d30); + delegates[30] = d30; + var d31 = new __findCallSiteSig(_findCallSiteSig); + callbacks[31] = Marshal.GetFunctionPointerForDelegate(d31); + delegates[31] = d31; + var d32 = new __getTokenTypeAsHandle(_getTokenTypeAsHandle); + callbacks[32] = Marshal.GetFunctionPointerForDelegate(d32); + delegates[32] = d32; + var d33 = new __canSkipVerification(_canSkipVerification); + callbacks[33] = Marshal.GetFunctionPointerForDelegate(d33); + delegates[33] = d33; + var d34 = new __isValidToken(_isValidToken); + callbacks[34] = Marshal.GetFunctionPointerForDelegate(d34); + delegates[34] = d34; + var d35 = new __isValidStringRef(_isValidStringRef); + callbacks[35] = Marshal.GetFunctionPointerForDelegate(d35); + delegates[35] = d35; + var d36 = new __shouldEnforceCallvirtRestriction(_shouldEnforceCallvirtRestriction); + callbacks[36] = Marshal.GetFunctionPointerForDelegate(d36); + delegates[36] = d36; + var d37 = new __asCorInfoType(_asCorInfoType); + callbacks[37] = Marshal.GetFunctionPointerForDelegate(d37); + delegates[37] = d37; + var d38 = new __getClassName(_getClassName); + callbacks[38] = Marshal.GetFunctionPointerForDelegate(d38); + delegates[38] = d38; + var d39 = new __getClassNameFromMetadata(_getClassNameFromMetadata); + callbacks[39] = Marshal.GetFunctionPointerForDelegate(d39); + delegates[39] = d39; + var d40 = new __getTypeInstantiationArgument(_getTypeInstantiationArgument); + callbacks[40] = Marshal.GetFunctionPointerForDelegate(d40); + delegates[40] = d40; + var d41 = new __appendClassName(_appendClassName); + callbacks[41] = Marshal.GetFunctionPointerForDelegate(d41); + delegates[41] = d41; + var d42 = new __isValueClass(_isValueClass); + callbacks[42] = Marshal.GetFunctionPointerForDelegate(d42); + delegates[42] = d42; + var d43 = new __canInlineTypeCheck(_canInlineTypeCheck); + callbacks[43] = Marshal.GetFunctionPointerForDelegate(d43); + delegates[43] = d43; + var d44 = new __canInlineTypeCheckWithObjectVTable(_canInlineTypeCheckWithObjectVTable); + callbacks[44] = Marshal.GetFunctionPointerForDelegate(d44); + delegates[44] = d44; + var d45 = new __getClassAttribs(_getClassAttribs); + callbacks[45] = Marshal.GetFunctionPointerForDelegate(d45); + delegates[45] = d45; + var d46 = new __isStructRequiringStackAllocRetBuf(_isStructRequiringStackAllocRetBuf); + callbacks[46] = Marshal.GetFunctionPointerForDelegate(d46); + delegates[46] = d46; + var d47 = new __getClassModule(_getClassModule); + callbacks[47] = Marshal.GetFunctionPointerForDelegate(d47); + delegates[47] = d47; + var d48 = new __getModuleAssembly(_getModuleAssembly); + callbacks[48] = Marshal.GetFunctionPointerForDelegate(d48); + delegates[48] = d48; + var d49 = new __getAssemblyName(_getAssemblyName); + callbacks[49] = Marshal.GetFunctionPointerForDelegate(d49); + delegates[49] = d49; + var d50 = new __LongLifetimeMalloc(_LongLifetimeMalloc); + callbacks[50] = Marshal.GetFunctionPointerForDelegate(d50); + delegates[50] = d50; + var d51 = new __LongLifetimeFree(_LongLifetimeFree); + callbacks[51] = Marshal.GetFunctionPointerForDelegate(d51); + delegates[51] = d51; + var d52 = new __getClassModuleIdForStatics(_getClassModuleIdForStatics); + callbacks[52] = Marshal.GetFunctionPointerForDelegate(d52); + delegates[52] = d52; + var d53 = new __getClassSize(_getClassSize); + callbacks[53] = Marshal.GetFunctionPointerForDelegate(d53); + delegates[53] = d53; + var d54 = new __getHeapClassSize(_getHeapClassSize); + callbacks[54] = Marshal.GetFunctionPointerForDelegate(d54); + delegates[54] = d54; + var d55 = new __canAllocateOnStack(_canAllocateOnStack); + callbacks[55] = Marshal.GetFunctionPointerForDelegate(d55); + delegates[55] = d55; + var d56 = new __getClassAlignmentRequirement(_getClassAlignmentRequirement); + callbacks[56] = Marshal.GetFunctionPointerForDelegate(d56); + delegates[56] = d56; + var d57 = new __getClassGClayout(_getClassGClayout); + callbacks[57] = Marshal.GetFunctionPointerForDelegate(d57); + delegates[57] = d57; + var d58 = new __getClassNumInstanceFields(_getClassNumInstanceFields); + callbacks[58] = Marshal.GetFunctionPointerForDelegate(d58); + delegates[58] = d58; + var d59 = new __getFieldInClass(_getFieldInClass); + callbacks[59] = Marshal.GetFunctionPointerForDelegate(d59); + delegates[59] = d59; + var d60 = new __checkMethodModifier(_checkMethodModifier); + callbacks[60] = Marshal.GetFunctionPointerForDelegate(d60); + delegates[60] = d60; + var d61 = new __getNewHelper(_getNewHelper); + callbacks[61] = Marshal.GetFunctionPointerForDelegate(d61); + delegates[61] = d61; + var d62 = new __getNewArrHelper(_getNewArrHelper); + callbacks[62] = Marshal.GetFunctionPointerForDelegate(d62); + delegates[62] = d62; + var d63 = new __getCastingHelper(_getCastingHelper); + callbacks[63] = Marshal.GetFunctionPointerForDelegate(d63); + delegates[63] = d63; + var d64 = new __getSharedCCtorHelper(_getSharedCCtorHelper); + callbacks[64] = Marshal.GetFunctionPointerForDelegate(d64); + delegates[64] = d64; + var d65 = new __getSecurityPrologHelper(_getSecurityPrologHelper); + callbacks[65] = Marshal.GetFunctionPointerForDelegate(d65); + delegates[65] = d65; + var d66 = new __getTypeForBox(_getTypeForBox); + callbacks[66] = Marshal.GetFunctionPointerForDelegate(d66); + delegates[66] = d66; + var d67 = new __getBoxHelper(_getBoxHelper); + callbacks[67] = Marshal.GetFunctionPointerForDelegate(d67); + delegates[67] = d67; + var d68 = new __getUnBoxHelper(_getUnBoxHelper); + callbacks[68] = Marshal.GetFunctionPointerForDelegate(d68); + delegates[68] = d68; + var d69 = new __getReadyToRunHelper(_getReadyToRunHelper); + callbacks[69] = Marshal.GetFunctionPointerForDelegate(d69); + delegates[69] = d69; + var d70 = new __getReadyToRunDelegateCtorHelper(_getReadyToRunDelegateCtorHelper); + callbacks[70] = Marshal.GetFunctionPointerForDelegate(d70); + delegates[70] = d70; + var d71 = new __getHelperName(_getHelperName); + callbacks[71] = Marshal.GetFunctionPointerForDelegate(d71); + delegates[71] = d71; + var d72 = new __initClass(_initClass); + callbacks[72] = Marshal.GetFunctionPointerForDelegate(d72); + delegates[72] = d72; + var d73 = new __classMustBeLoadedBeforeCodeIsRun(_classMustBeLoadedBeforeCodeIsRun); + callbacks[73] = Marshal.GetFunctionPointerForDelegate(d73); + delegates[73] = d73; + var d74 = new __getBuiltinClass(_getBuiltinClass); + callbacks[74] = Marshal.GetFunctionPointerForDelegate(d74); + delegates[74] = d74; + var d75 = new __getTypeForPrimitiveValueClass(_getTypeForPrimitiveValueClass); + callbacks[75] = Marshal.GetFunctionPointerForDelegate(d75); + delegates[75] = d75; + var d76 = new __getTypeForPrimitiveNumericClass(_getTypeForPrimitiveNumericClass); + callbacks[76] = Marshal.GetFunctionPointerForDelegate(d76); + delegates[76] = d76; + var d77 = new __canCast(_canCast); + callbacks[77] = Marshal.GetFunctionPointerForDelegate(d77); + delegates[77] = d77; + var d78 = new __areTypesEquivalent(_areTypesEquivalent); + callbacks[78] = Marshal.GetFunctionPointerForDelegate(d78); + delegates[78] = d78; + var d79 = new __compareTypesForCast(_compareTypesForCast); + callbacks[79] = Marshal.GetFunctionPointerForDelegate(d79); + delegates[79] = d79; + var d80 = new __compareTypesForEquality(_compareTypesForEquality); + callbacks[80] = Marshal.GetFunctionPointerForDelegate(d80); + delegates[80] = d80; + var d81 = new __mergeClasses(_mergeClasses); + callbacks[81] = Marshal.GetFunctionPointerForDelegate(d81); + delegates[81] = d81; + var d82 = new __isMoreSpecificType(_isMoreSpecificType); + callbacks[82] = Marshal.GetFunctionPointerForDelegate(d82); + delegates[82] = d82; + var d83 = new __getParentType(_getParentType); + callbacks[83] = Marshal.GetFunctionPointerForDelegate(d83); + delegates[83] = d83; + var d84 = new __getChildType(_getChildType); + callbacks[84] = Marshal.GetFunctionPointerForDelegate(d84); + delegates[84] = d84; + var d85 = new __satisfiesClassConstraints(_satisfiesClassConstraints); + callbacks[85] = Marshal.GetFunctionPointerForDelegate(d85); + delegates[85] = d85; + var d86 = new __isSDArray(_isSDArray); + callbacks[86] = Marshal.GetFunctionPointerForDelegate(d86); + delegates[86] = d86; + var d87 = new __getArrayRank(_getArrayRank); + callbacks[87] = Marshal.GetFunctionPointerForDelegate(d87); + delegates[87] = d87; + var d88 = new __getArrayInitializationData(_getArrayInitializationData); + callbacks[88] = Marshal.GetFunctionPointerForDelegate(d88); + delegates[88] = d88; + var d89 = new __canAccessClass(_canAccessClass); + callbacks[89] = Marshal.GetFunctionPointerForDelegate(d89); + delegates[89] = d89; + var d90 = new __getFieldName(_getFieldName); + callbacks[90] = Marshal.GetFunctionPointerForDelegate(d90); + delegates[90] = d90; + var d91 = new __getFieldClass(_getFieldClass); + callbacks[91] = Marshal.GetFunctionPointerForDelegate(d91); + delegates[91] = d91; + var d92 = new __getFieldType(_getFieldType); + callbacks[92] = Marshal.GetFunctionPointerForDelegate(d92); + delegates[92] = d92; + var d93 = new __getFieldOffset(_getFieldOffset); + callbacks[93] = Marshal.GetFunctionPointerForDelegate(d93); + delegates[93] = d93; + var d94 = new __isWriteBarrierHelperRequired(_isWriteBarrierHelperRequired); + callbacks[94] = Marshal.GetFunctionPointerForDelegate(d94); + delegates[94] = d94; + var d95 = new __getFieldInfo(_getFieldInfo); + callbacks[95] = Marshal.GetFunctionPointerForDelegate(d95); + delegates[95] = d95; + var d96 = new __isFieldStatic(_isFieldStatic); + callbacks[96] = Marshal.GetFunctionPointerForDelegate(d96); + delegates[96] = d96; + var d97 = new __getBoundaries(_getBoundaries); + callbacks[97] = Marshal.GetFunctionPointerForDelegate(d97); + delegates[97] = d97; + var d98 = new __setBoundaries(_setBoundaries); + callbacks[98] = Marshal.GetFunctionPointerForDelegate(d98); + delegates[98] = d98; + var d99 = new __getVars(_getVars); + callbacks[99] = Marshal.GetFunctionPointerForDelegate(d99); + delegates[99] = d99; + var d100 = new __setVars(_setVars); + callbacks[100] = Marshal.GetFunctionPointerForDelegate(d100); + delegates[100] = d100; + var d101 = new __allocateArray(_allocateArray); + callbacks[101] = Marshal.GetFunctionPointerForDelegate(d101); + delegates[101] = d101; + var d102 = new __freeArray(_freeArray); + callbacks[102] = Marshal.GetFunctionPointerForDelegate(d102); + delegates[102] = d102; + var d103 = new __getArgNext(_getArgNext); + callbacks[103] = Marshal.GetFunctionPointerForDelegate(d103); + delegates[103] = d103; + var d104 = new __getArgType(_getArgType); + callbacks[104] = Marshal.GetFunctionPointerForDelegate(d104); + delegates[104] = d104; + var d105 = new __getArgClass(_getArgClass); + callbacks[105] = Marshal.GetFunctionPointerForDelegate(d105); + delegates[105] = d105; + var d106 = new __getHFAType(_getHFAType); + callbacks[106] = Marshal.GetFunctionPointerForDelegate(d106); + delegates[106] = d106; + var d107 = new __GetErrorHRESULT(_GetErrorHRESULT); + callbacks[107] = Marshal.GetFunctionPointerForDelegate(d107); + delegates[107] = d107; + var d108 = new __GetErrorMessage(_GetErrorMessage); + callbacks[108] = Marshal.GetFunctionPointerForDelegate(d108); + delegates[108] = d108; + var d109 = new __FilterException(_FilterException); + callbacks[109] = Marshal.GetFunctionPointerForDelegate(d109); + delegates[109] = d109; + var d110 = new __HandleException(_HandleException); + callbacks[110] = Marshal.GetFunctionPointerForDelegate(d110); + delegates[110] = d110; + var d111 = new __ThrowExceptionForJitResult(_ThrowExceptionForJitResult); + callbacks[111] = Marshal.GetFunctionPointerForDelegate(d111); + delegates[111] = d111; + var d112 = new __ThrowExceptionForHelper(_ThrowExceptionForHelper); + callbacks[112] = Marshal.GetFunctionPointerForDelegate(d112); + delegates[112] = d112; + var d113 = new __runWithErrorTrap(_runWithErrorTrap); + callbacks[113] = Marshal.GetFunctionPointerForDelegate(d113); + delegates[113] = d113; + var d114 = new __getEEInfo(_getEEInfo); + callbacks[114] = Marshal.GetFunctionPointerForDelegate(d114); + delegates[114] = d114; + var d115 = new __getJitTimeLogFilename(_getJitTimeLogFilename); + callbacks[115] = Marshal.GetFunctionPointerForDelegate(d115); + delegates[115] = d115; + var d116 = new __getMethodDefFromMethod(_getMethodDefFromMethod); + callbacks[116] = Marshal.GetFunctionPointerForDelegate(d116); + delegates[116] = d116; + var d117 = new __getMethodName(_getMethodName); + callbacks[117] = Marshal.GetFunctionPointerForDelegate(d117); + delegates[117] = d117; + var d118 = new __getMethodNameFromMetadata(_getMethodNameFromMetadata); + callbacks[118] = Marshal.GetFunctionPointerForDelegate(d118); + delegates[118] = d118; + var d119 = new __getMethodHash(_getMethodHash); + callbacks[119] = Marshal.GetFunctionPointerForDelegate(d119); + delegates[119] = d119; + var d120 = new __findNameOfToken(_findNameOfToken); + callbacks[120] = Marshal.GetFunctionPointerForDelegate(d120); + delegates[120] = d120; + var d121 = new __getSystemVAmd64PassStructInRegisterDescriptor(_getSystemVAmd64PassStructInRegisterDescriptor); + callbacks[121] = Marshal.GetFunctionPointerForDelegate(d121); + delegates[121] = d121; + var d122 = new __getThreadTLSIndex(_getThreadTLSIndex); + callbacks[122] = Marshal.GetFunctionPointerForDelegate(d122); + delegates[122] = d122; + var d123 = new __getInlinedCallFrameVptr(_getInlinedCallFrameVptr); + callbacks[123] = Marshal.GetFunctionPointerForDelegate(d123); + delegates[123] = d123; + var d124 = new __getAddrOfCaptureThreadGlobal(_getAddrOfCaptureThreadGlobal); + callbacks[124] = Marshal.GetFunctionPointerForDelegate(d124); + delegates[124] = d124; + var d125 = new __getHelperFtn(_getHelperFtn); + callbacks[125] = Marshal.GetFunctionPointerForDelegate(d125); + delegates[125] = d125; + var d126 = new __getFunctionEntryPoint(_getFunctionEntryPoint); + callbacks[126] = Marshal.GetFunctionPointerForDelegate(d126); + delegates[126] = d126; + var d127 = new __getFunctionFixedEntryPoint(_getFunctionFixedEntryPoint); + callbacks[127] = Marshal.GetFunctionPointerForDelegate(d127); + delegates[127] = d127; + var d128 = new __getMethodSync(_getMethodSync); + callbacks[128] = Marshal.GetFunctionPointerForDelegate(d128); + delegates[128] = d128; + var d129 = new __getLazyStringLiteralHelper(_getLazyStringLiteralHelper); + callbacks[129] = Marshal.GetFunctionPointerForDelegate(d129); + delegates[129] = d129; + var d130 = new __embedModuleHandle(_embedModuleHandle); + callbacks[130] = Marshal.GetFunctionPointerForDelegate(d130); + delegates[130] = d130; + var d131 = new __embedClassHandle(_embedClassHandle); + callbacks[131] = Marshal.GetFunctionPointerForDelegate(d131); + delegates[131] = d131; + var d132 = new __embedMethodHandle(_embedMethodHandle); + callbacks[132] = Marshal.GetFunctionPointerForDelegate(d132); + delegates[132] = d132; + var d133 = new __embedFieldHandle(_embedFieldHandle); + callbacks[133] = Marshal.GetFunctionPointerForDelegate(d133); + delegates[133] = d133; + var d134 = new __embedGenericHandle(_embedGenericHandle); + callbacks[134] = Marshal.GetFunctionPointerForDelegate(d134); + delegates[134] = d134; + var d135 = new __getLocationOfThisType(_getLocationOfThisType); + callbacks[135] = Marshal.GetFunctionPointerForDelegate(d135); + delegates[135] = d135; + var d136 = new __getPInvokeUnmanagedTarget(_getPInvokeUnmanagedTarget); + callbacks[136] = Marshal.GetFunctionPointerForDelegate(d136); + delegates[136] = d136; + var d137 = new __getAddressOfPInvokeFixup(_getAddressOfPInvokeFixup); + callbacks[137] = Marshal.GetFunctionPointerForDelegate(d137); + delegates[137] = d137; + var d138 = new __getAddressOfPInvokeTarget(_getAddressOfPInvokeTarget); + callbacks[138] = Marshal.GetFunctionPointerForDelegate(d138); + delegates[138] = d138; + var d139 = new __GetCookieForPInvokeCalliSig(_GetCookieForPInvokeCalliSig); + callbacks[139] = Marshal.GetFunctionPointerForDelegate(d139); + delegates[139] = d139; + var d140 = new __canGetCookieForPInvokeCalliSig(_canGetCookieForPInvokeCalliSig); + callbacks[140] = Marshal.GetFunctionPointerForDelegate(d140); + delegates[140] = d140; + var d141 = new __getJustMyCodeHandle(_getJustMyCodeHandle); + callbacks[141] = Marshal.GetFunctionPointerForDelegate(d141); + delegates[141] = d141; + var d142 = new __GetProfilingHandle(_GetProfilingHandle); + callbacks[142] = Marshal.GetFunctionPointerForDelegate(d142); + delegates[142] = d142; + var d143 = new __getCallInfo(_getCallInfo); + callbacks[143] = Marshal.GetFunctionPointerForDelegate(d143); + delegates[143] = d143; + var d144 = new __canAccessFamily(_canAccessFamily); + callbacks[144] = Marshal.GetFunctionPointerForDelegate(d144); + delegates[144] = d144; + var d145 = new __isRIDClassDomainID(_isRIDClassDomainID); + callbacks[145] = Marshal.GetFunctionPointerForDelegate(d145); + delegates[145] = d145; + var d146 = new __getClassDomainID(_getClassDomainID); + callbacks[146] = Marshal.GetFunctionPointerForDelegate(d146); + delegates[146] = d146; + var d147 = new __getFieldAddress(_getFieldAddress); + callbacks[147] = Marshal.GetFunctionPointerForDelegate(d147); + delegates[147] = d147; + var d148 = new __getStaticFieldCurrentClass(_getStaticFieldCurrentClass); + callbacks[148] = Marshal.GetFunctionPointerForDelegate(d148); + delegates[148] = d148; + var d149 = new __getVarArgsHandle(_getVarArgsHandle); + callbacks[149] = Marshal.GetFunctionPointerForDelegate(d149); + delegates[149] = d149; + var d150 = new __canGetVarArgsHandle(_canGetVarArgsHandle); + callbacks[150] = Marshal.GetFunctionPointerForDelegate(d150); + delegates[150] = d150; + var d151 = new __constructStringLiteral(_constructStringLiteral); + callbacks[151] = Marshal.GetFunctionPointerForDelegate(d151); + delegates[151] = d151; + var d152 = new __emptyStringLiteral(_emptyStringLiteral); + callbacks[152] = Marshal.GetFunctionPointerForDelegate(d152); + delegates[152] = d152; + var d153 = new __getFieldThreadLocalStoreID(_getFieldThreadLocalStoreID); + callbacks[153] = Marshal.GetFunctionPointerForDelegate(d153); + delegates[153] = d153; + var d154 = new __setOverride(_setOverride); + callbacks[154] = Marshal.GetFunctionPointerForDelegate(d154); + delegates[154] = d154; + var d155 = new __addActiveDependency(_addActiveDependency); + callbacks[155] = Marshal.GetFunctionPointerForDelegate(d155); + delegates[155] = d155; + var d156 = new __GetDelegateCtor(_GetDelegateCtor); + callbacks[156] = Marshal.GetFunctionPointerForDelegate(d156); + delegates[156] = d156; + var d157 = new __MethodCompileComplete(_MethodCompileComplete); + callbacks[157] = Marshal.GetFunctionPointerForDelegate(d157); + delegates[157] = d157; + var d158 = new __getTailCallCopyArgsThunk(_getTailCallCopyArgsThunk); + callbacks[158] = Marshal.GetFunctionPointerForDelegate(d158); + delegates[158] = d158; + var d159 = new __convertPInvokeCalliToCall(_convertPInvokeCalliToCall); + callbacks[159] = Marshal.GetFunctionPointerForDelegate(d159); + delegates[159] = d159; + var d160 = new __getMemoryManager(_getMemoryManager); + callbacks[160] = Marshal.GetFunctionPointerForDelegate(d160); + delegates[160] = d160; + var d161 = new __allocMem(_allocMem); + callbacks[161] = Marshal.GetFunctionPointerForDelegate(d161); + delegates[161] = d161; + var d162 = new __reserveUnwindInfo(_reserveUnwindInfo); + callbacks[162] = Marshal.GetFunctionPointerForDelegate(d162); + delegates[162] = d162; + var d163 = new __allocUnwindInfo(_allocUnwindInfo); + callbacks[163] = Marshal.GetFunctionPointerForDelegate(d163); + delegates[163] = d163; + var d164 = new __allocGCInfo(_allocGCInfo); + callbacks[164] = Marshal.GetFunctionPointerForDelegate(d164); + delegates[164] = d164; + var d165 = new __yieldExecution(_yieldExecution); + callbacks[165] = Marshal.GetFunctionPointerForDelegate(d165); + delegates[165] = d165; + var d166 = new __setEHcount(_setEHcount); + callbacks[166] = Marshal.GetFunctionPointerForDelegate(d166); + delegates[166] = d166; + var d167 = new __setEHinfo(_setEHinfo); + callbacks[167] = Marshal.GetFunctionPointerForDelegate(d167); + delegates[167] = d167; + var d168 = new __logMsg(_logMsg); + callbacks[168] = Marshal.GetFunctionPointerForDelegate(d168); + delegates[168] = d168; + var d169 = new __doAssert(_doAssert); + callbacks[169] = Marshal.GetFunctionPointerForDelegate(d169); + delegates[169] = d169; + var d170 = new __reportFatalError(_reportFatalError); + callbacks[170] = Marshal.GetFunctionPointerForDelegate(d170); + delegates[170] = d170; + var d171 = new __allocMethodBlockCounts(_allocMethodBlockCounts); + callbacks[171] = Marshal.GetFunctionPointerForDelegate(d171); + delegates[171] = d171; + var d172 = new __getMethodBlockCounts(_getMethodBlockCounts); + callbacks[172] = Marshal.GetFunctionPointerForDelegate(d172); + delegates[172] = d172; + var d173 = new __recordCallSite(_recordCallSite); + callbacks[173] = Marshal.GetFunctionPointerForDelegate(d173); + delegates[173] = d173; + var d174 = new __recordRelocation(_recordRelocation); + callbacks[174] = Marshal.GetFunctionPointerForDelegate(d174); + delegates[174] = d174; + var d175 = new __getRelocTypeHint(_getRelocTypeHint); + callbacks[175] = Marshal.GetFunctionPointerForDelegate(d175); + delegates[175] = d175; + var d176 = new __getModuleNativeEntryPointRange(_getModuleNativeEntryPointRange); + callbacks[176] = Marshal.GetFunctionPointerForDelegate(d176); + delegates[176] = d176; + var d177 = new __getExpectedTargetArchitecture(_getExpectedTargetArchitecture); + callbacks[177] = Marshal.GetFunctionPointerForDelegate(d177); + delegates[177] = d177; + var d178 = new __getJitFlags(_getJitFlags); + callbacks[178] = Marshal.GetFunctionPointerForDelegate(d178); + delegates[178] = d178; + + keepAlive = delegates; + return (IntPtr)callbacks; + } + } +} + diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoHelpFunc.cs new file mode 100644 index 00000000000..b879af5a919 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -0,0 +1,320 @@ +// 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.Collections.Generic; +using System.Text; + +namespace Internal.JitInterface +{ + // CorInfoHelpFunc defines the set of helpers (accessed via the ICorDynamicInfo::getHelperFtn()) + // These helpers can be called by native code which executes in the runtime. + // Compilers can emit calls to these helpers. + + public enum CorInfoHelpFunc + { + CORINFO_HELP_UNDEF, // invalid value. This should never be used + + /* Arithmetic helpers */ + + CORINFO_HELP_DIV, // For the ARM 32-bit integer divide uses a helper call :-( + CORINFO_HELP_MOD, + CORINFO_HELP_UDIV, + CORINFO_HELP_UMOD, + + CORINFO_HELP_LLSH, + CORINFO_HELP_LRSH, + CORINFO_HELP_LRSZ, + CORINFO_HELP_LMUL, + CORINFO_HELP_LMUL_OVF, + CORINFO_HELP_ULMUL_OVF, + CORINFO_HELP_LDIV, + CORINFO_HELP_LMOD, + CORINFO_HELP_ULDIV, + CORINFO_HELP_ULMOD, + CORINFO_HELP_LNG2DBL, // Convert a signed int64 to a double + CORINFO_HELP_ULNG2DBL, // Convert a unsigned int64 to a double + CORINFO_HELP_DBL2INT, + CORINFO_HELP_DBL2INT_OVF, + CORINFO_HELP_DBL2LNG, + CORINFO_HELP_DBL2LNG_OVF, + CORINFO_HELP_DBL2UINT, + CORINFO_HELP_DBL2UINT_OVF, + CORINFO_HELP_DBL2ULNG, + CORINFO_HELP_DBL2ULNG_OVF, + CORINFO_HELP_FLTREM, + CORINFO_HELP_DBLREM, + CORINFO_HELP_FLTROUND, + CORINFO_HELP_DBLROUND, + + /* Allocating a new object. Always use ICorClassInfo::getNewHelper() to decide + which is the right helper to use to allocate an object of a given type. */ + + CORINFO_HELP_NEW_CROSSCONTEXT, // cross context new object + CORINFO_HELP_NEWFAST, + CORINFO_HELP_NEWSFAST, // allocator for small, non-finalizer, non-array object + CORINFO_HELP_NEWSFAST_FINALIZE, // allocator for small, finalizable, non-array object + CORINFO_HELP_NEWSFAST_ALIGN8, // allocator for small, non-finalizer, non-array object, 8 byte aligned + CORINFO_HELP_NEWSFAST_ALIGN8_VC,// allocator for small, value class, 8 byte aligned + CORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE, // allocator for small, finalizable, non-array object, 8 byte aligned + CORINFO_HELP_NEW_MDARR, // multi-dim array helper (with or without lower bounds - dimensions passed in as vararg) + CORINFO_HELP_NEW_MDARR_NONVARARG,// multi-dim array helper (with or without lower bounds - dimensions passed in as unmanaged array) + CORINFO_HELP_NEWARR_1_DIRECT, // helper for any one dimensional array creation + CORINFO_HELP_NEWARR_1_R2R_DIRECT, // wrapper for R2R direct call, which extracts method table from ArrayTypeDesc + CORINFO_HELP_NEWARR_1_OBJ, // optimized 1-D object arrays + CORINFO_HELP_NEWARR_1_VC, // optimized 1-D value class arrays + CORINFO_HELP_NEWARR_1_ALIGN8, // like VC, but aligns the array start + + CORINFO_HELP_STRCNS, // create a new string literal + CORINFO_HELP_STRCNS_CURRENT_MODULE, // create a new string literal from the current module (used by NGen code) + /* Object model */ + + CORINFO_HELP_INITCLASS, // Initialize class if not already initialized + CORINFO_HELP_INITINSTCLASS, // Initialize class for instantiated type + + // Use ICorClassInfo::getCastingHelper to determine + // the right helper to use + + CORINFO_HELP_ISINSTANCEOFINTERFACE, // Optimized helper for interfaces + CORINFO_HELP_ISINSTANCEOFARRAY, // Optimized helper for arrays + CORINFO_HELP_ISINSTANCEOFCLASS, // Optimized helper for classes + CORINFO_HELP_ISINSTANCEOFANY, // Slow helper for any type + + CORINFO_HELP_CHKCASTINTERFACE, + CORINFO_HELP_CHKCASTARRAY, + CORINFO_HELP_CHKCASTCLASS, + CORINFO_HELP_CHKCASTANY, + CORINFO_HELP_CHKCASTCLASS_SPECIAL, // Optimized helper for classes. Assumes that the trivial cases + // has been taken care of by the inlined check + + CORINFO_HELP_BOX, + CORINFO_HELP_BOX_NULLABLE, // special form of boxing for Nullable + CORINFO_HELP_UNBOX, + CORINFO_HELP_UNBOX_NULLABLE, // special form of unboxing for Nullable + CORINFO_HELP_GETREFANY, // Extract the byref from a TypedReference, checking that it is the expected type + + CORINFO_HELP_ARRADDR_ST, // assign to element of object array with type-checking + CORINFO_HELP_LDELEMA_REF, // does a precise type comparision and returns address + + /* Exceptions */ + + CORINFO_HELP_THROW, // Throw an exception object + CORINFO_HELP_RETHROW, // Rethrow the currently active exception + CORINFO_HELP_USER_BREAKPOINT, // For a user program to break to the debugger + CORINFO_HELP_RNGCHKFAIL, // array bounds check failed + CORINFO_HELP_OVERFLOW, // throw an overflow exception + CORINFO_HELP_THROWDIVZERO, // throw a divide by zero exception + CORINFO_HELP_THROWNULLREF, // throw a null reference exception + + CORINFO_HELP_INTERNALTHROW, // Support for really fast jit + CORINFO_HELP_VERIFICATION, // Throw a VerificationException + CORINFO_HELP_SEC_UNMGDCODE_EXCPT, // throw a security unmanaged code exception + CORINFO_HELP_FAIL_FAST, // Kill the process avoiding any exceptions or stack and data dependencies (use for GuardStack unsafe buffer checks) + + CORINFO_HELP_METHOD_ACCESS_EXCEPTION,//Throw an access exception due to a failed member/class access check. + CORINFO_HELP_FIELD_ACCESS_EXCEPTION, + CORINFO_HELP_CLASS_ACCESS_EXCEPTION, + + CORINFO_HELP_ENDCATCH, // call back into the EE at the end of a catch block + + /* Synchronization */ + + CORINFO_HELP_MON_ENTER, + CORINFO_HELP_MON_EXIT, + CORINFO_HELP_MON_ENTER_STATIC, + CORINFO_HELP_MON_EXIT_STATIC, + + CORINFO_HELP_GETCLASSFROMMETHODPARAM, // Given a generics method handle, returns a class handle + CORINFO_HELP_GETSYNCFROMCLASSHANDLE, // Given a generics class handle, returns the sync monitor + // in its ManagedClassObject + + /* Security callout support */ + + CORINFO_HELP_SECURITY_PROLOG, // Required if CORINFO_FLG_SECURITYCHECK is set, or CORINFO_FLG_NOSECURITYWRAP is not set + CORINFO_HELP_SECURITY_PROLOG_FRAMED, // Slow version of CORINFO_HELP_SECURITY_PROLOG. Used for instrumentation. + + CORINFO_HELP_METHOD_ACCESS_CHECK, // Callouts to runtime security access checks + CORINFO_HELP_FIELD_ACCESS_CHECK, + CORINFO_HELP_CLASS_ACCESS_CHECK, + + CORINFO_HELP_DELEGATE_SECURITY_CHECK, // Callout to delegate security transparency check + + /* Verification runtime callout support */ + + CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, // Do a Demand for UnmanagedCode permission at runtime + + /* GC support */ + + CORINFO_HELP_STOP_FOR_GC, // Call GC (force a GC) + CORINFO_HELP_POLL_GC, // Ask GC if it wants to collect + + CORINFO_HELP_STRESS_GC, // Force a GC, but then update the JITTED code to be a noop call + CORINFO_HELP_CHECK_OBJ, // confirm that ECX is a valid object pointer (debugging only) + + /* GC Write barrier support */ + + CORINFO_HELP_ASSIGN_REF, // universal helpers with F_CALL_CONV calling convention + CORINFO_HELP_CHECKED_ASSIGN_REF, + CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP, // Do the store, and ensure that the target was not in the heap. + + CORINFO_HELP_ASSIGN_BYREF, + CORINFO_HELP_ASSIGN_STRUCT, + + + /* Accessing fields */ + + // For COM object support (using COM get/set routines to update object) + // and EnC and cross-context support + CORINFO_HELP_GETFIELD8, + CORINFO_HELP_SETFIELD8, + CORINFO_HELP_GETFIELD16, + CORINFO_HELP_SETFIELD16, + CORINFO_HELP_GETFIELD32, + CORINFO_HELP_SETFIELD32, + CORINFO_HELP_GETFIELD64, + CORINFO_HELP_SETFIELD64, + CORINFO_HELP_GETFIELDOBJ, + CORINFO_HELP_SETFIELDOBJ, + CORINFO_HELP_GETFIELDSTRUCT, + CORINFO_HELP_SETFIELDSTRUCT, + CORINFO_HELP_GETFIELDFLOAT, + CORINFO_HELP_SETFIELDFLOAT, + CORINFO_HELP_GETFIELDDOUBLE, + CORINFO_HELP_SETFIELDDOUBLE, + + CORINFO_HELP_GETFIELDADDR, + + CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT, // Helper for context-static fields + CORINFO_HELP_GETSTATICFIELDADDR_TLS, // Helper for PE TLS fields + + // There are a variety of specialized helpers for accessing static fields. The JIT should use + // ICorClassInfo::getSharedStaticsOrCCtorHelper to determine which helper to use + + // Helpers for regular statics + CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, + CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, + CORINFO_HELP_GETSHARED_GCSTATIC_BASE, + CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, + CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS, + CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS, + // Helper to class initialize shared generic with dynamicclass, but not get static field address + CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS, + + // Helpers for thread statics + CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, + CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE, + CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE, + CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, + CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, + CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, + + /* Debugger */ + + CORINFO_HELP_DBG_IS_JUST_MY_CODE, // Check if this is "JustMyCode" and needs to be stepped through. + + /* Profiling enter/leave probe addresses */ + CORINFO_HELP_PROF_FCN_ENTER, // record the entry to a method (caller) + CORINFO_HELP_PROF_FCN_LEAVE, // record the completion of current method (caller) + CORINFO_HELP_PROF_FCN_TAILCALL, // record the completionof current method through tailcall (caller) + + /* Miscellaneous */ + + CORINFO_HELP_BBT_FCN_ENTER, // record the entry to a method for collecting Tuning data + + CORINFO_HELP_PINVOKE_CALLI, // Indirect pinvoke call + CORINFO_HELP_TAILCALL, // Perform a tail call + + CORINFO_HELP_GETCURRENTMANAGEDTHREADID, + + CORINFO_HELP_INIT_PINVOKE_FRAME, // initialize an inlined PInvoke Frame for the JIT-compiler + + CORINFO_HELP_MEMSET, // Init block of memory + CORINFO_HELP_MEMCPY, // Copy block of memory + + CORINFO_HELP_RUNTIMEHANDLE_METHOD, // determine a type/field/method handle at run-time + CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG,// determine a type/field/method handle at run-time, with IBC logging + CORINFO_HELP_RUNTIMEHANDLE_CLASS, // determine a type/field/method handle at run-time + CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG,// determine a type/field/method handle at run-time, with IBC logging + + CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time + CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time, the type may be null + CORINFO_HELP_METHODDESC_TO_STUBRUNTIMEMETHOD, // Convert from a MethodDesc (native structure pointer) to RuntimeMethodHandle at run-time + CORINFO_HELP_FIELDDESC_TO_STUBRUNTIMEFIELD, // Convert from a FieldDesc (native structure pointer) to RuntimeFieldHandle at run-time + CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time + CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time, handle might point to a null type + + CORINFO_HELP_ARE_TYPES_EQUIVALENT, // Check whether two TypeHandles (native structure pointers) are equivalent + + CORINFO_HELP_VIRTUAL_FUNC_PTR, // look up a virtual method at run-time + //CORINFO_HELP_VIRTUAL_FUNC_PTR_LOG, // look up a virtual method at run-time, with IBC logging + + // Not a real helpers. Instead of taking handle arguments, these helpers point to a small stub that loads the handle argument and calls the static helper. + CORINFO_HELP_READYTORUN_NEW, + CORINFO_HELP_READYTORUN_NEWARR_1, + CORINFO_HELP_READYTORUN_ISINSTANCEOF, + CORINFO_HELP_READYTORUN_CHKCAST, + CORINFO_HELP_READYTORUN_STATIC_BASE, + CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, + CORINFO_HELP_READYTORUN_GENERIC_HANDLE, + CORINFO_HELP_READYTORUN_DELEGATE_CTOR, + CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE, + + CORINFO_HELP_EE_PRESTUB, // Not real JIT helper. Used in native images. + + CORINFO_HELP_EE_PRECODE_FIXUP, // Not real JIT helper. Used for Precode fixup in native images. + CORINFO_HELP_EE_PINVOKE_FIXUP, // Not real JIT helper. Used for PInvoke target fixup in native images. + CORINFO_HELP_EE_VSD_FIXUP, // Not real JIT helper. Used for VSD cell fixup in native images. + CORINFO_HELP_EE_EXTERNAL_FIXUP, // Not real JIT helper. Used for to fixup external method thunks in native images. + CORINFO_HELP_EE_VTABLE_FIXUP, // Not real JIT helper. Used for inherited vtable slot fixup in native images. + + CORINFO_HELP_EE_REMOTING_THUNK, // Not real JIT helper. Used for remoting precode in native images. + + CORINFO_HELP_EE_PERSONALITY_ROUTINE,// Not real JIT helper. Used in native images. + CORINFO_HELP_EE_PERSONALITY_ROUTINE_FILTER_FUNCLET,// Not real JIT helper. Used in native images to detect filter funclets. + + // ASSIGN_REF_EAX - CHECKED_ASSIGN_REF_EBP: NOGC_WRITE_BARRIERS JIT helper calls + // + // For unchecked versions EDX is required to point into GC heap. + // + // NOTE: these helpers are only used for x86. + CORINFO_HELP_ASSIGN_REF_EAX, // EAX holds GC ptr, do a 'mov [EDX], EAX' and inform GC + CORINFO_HELP_ASSIGN_REF_EBX, // EBX holds GC ptr, do a 'mov [EDX], EBX' and inform GC + CORINFO_HELP_ASSIGN_REF_ECX, // ECX holds GC ptr, do a 'mov [EDX], ECX' and inform GC + CORINFO_HELP_ASSIGN_REF_ESI, // ESI holds GC ptr, do a 'mov [EDX], ESI' and inform GC + CORINFO_HELP_ASSIGN_REF_EDI, // EDI holds GC ptr, do a 'mov [EDX], EDI' and inform GC + CORINFO_HELP_ASSIGN_REF_EBP, // EBP holds GC ptr, do a 'mov [EDX], EBP' and inform GC + + CORINFO_HELP_CHECKED_ASSIGN_REF_EAX, // These are the same as ASSIGN_REF above ... + CORINFO_HELP_CHECKED_ASSIGN_REF_EBX, // ... but also check if EDX points into heap. + CORINFO_HELP_CHECKED_ASSIGN_REF_ECX, + CORINFO_HELP_CHECKED_ASSIGN_REF_ESI, + CORINFO_HELP_CHECKED_ASSIGN_REF_EDI, + CORINFO_HELP_CHECKED_ASSIGN_REF_EBP, + + CORINFO_HELP_LOOP_CLONE_CHOICE_ADDR, // Return the reference to a counter to decide to take cloned path in debug stress. + CORINFO_HELP_DEBUG_LOG_LOOP_CLONING, // Print a message that a loop cloning optimization has occurred in debug mode. + + CORINFO_HELP_THROW_ARGUMENTEXCEPTION, // throw ArgumentException + CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, // throw ArgumentOutOfRangeException + CORINFO_HELP_THROW_NOT_IMPLEMENTED, // throw NotImplementedException + CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, // throw PlatformNotSupportedException + CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED, // throw TypeNotSupportedException + + CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument + CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument + + CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, // Transition to cooperative mode in reverse P/Invoke prolog, frame is the first argument + CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, // Transition to preemptive mode in reverse P/Invoke epilog, frame is the first argument + + CORINFO_HELP_GVMLOOKUP_FOR_SLOT, // Resolve a generic virtual method target from this pointer and runtime method handle + + CORINFO_HELP_STACK_PROBE, // Probes each page of the allocated stack frame + + CORINFO_HELP_COUNT, + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.Intrinsics.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.Intrinsics.cs new file mode 100644 index 00000000000..f42e74a9e91 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.Intrinsics.cs @@ -0,0 +1,269 @@ +// 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.TypeSystem; + +namespace Internal.JitInterface +{ + internal unsafe partial class CorInfoImpl + { + private struct IntrinsicKey + { + public string MethodName; + public string TypeNamespace; + public string TypeName; + + public bool Equals(IntrinsicKey other) + { + return (MethodName == other.MethodName) && + (TypeNamespace == other.TypeNamespace) && + (TypeName == other.TypeName); + } + + public override int GetHashCode() + { + return MethodName.GetHashCode() + + ((TypeNamespace != null) ? TypeNamespace.GetHashCode() : 0) + + ((TypeName != null) ? TypeName.GetHashCode() : 0); + } + } + + private class IntrinsicEntry + { + public IntrinsicKey Key; + public CorInfoIntrinsics Id; + } + + private class IntrinsicHashtable : LockFreeReaderHashtable + { + protected override bool CompareKeyToValue(IntrinsicKey key, IntrinsicEntry value) + { + return key.Equals(value.Key); + } + protected override bool CompareValueToValue(IntrinsicEntry value1, IntrinsicEntry value2) + { + return value1.Key.Equals(value2.Key); + } + protected override IntrinsicEntry CreateValueFromKey(IntrinsicKey key) + { + Debug.Fail("CreateValueFromKey not supported"); + return null; + } + protected override int GetKeyHashCode(IntrinsicKey key) + { + return key.GetHashCode(); + } + protected override int GetValueHashCode(IntrinsicEntry value) + { + return value.Key.GetHashCode(); + } + + public void Add(CorInfoIntrinsics id, string methodName, string typeNamespace, string typeName) + { + var entry = new IntrinsicEntry(); + entry.Id = id; + entry.Key.MethodName = methodName; + entry.Key.TypeNamespace = typeNamespace; + entry.Key.TypeName = typeName; + AddOrGetExisting(entry); + } + } + + static IntrinsicHashtable InitializeIntrinsicHashtable() + { + IntrinsicHashtable table = new IntrinsicHashtable(); + + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sin, "Sin", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sin, "Sin", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cos, "Cos", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cos, "Cos", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cbrt, "Cbrt", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cbrt, "Cbrt", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sqrt, "Sqrt", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sqrt, "Sqrt", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Abs, "Abs", "System", "Math"); + // No System.MathF entry for CORINFO_INTRTINSIC_Abs as System.Math exposes and handles both float and double + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Round, "Round", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Round, "Round", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cosh, "Cosh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cosh, "Cosh", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sinh, "Sinh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sinh, "Sinh", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tan, "Tan", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tan, "Tan", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tanh, "Tanh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tanh, "Tanh", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asin, "Asin", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asin, "Asin", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asinh, "Asinh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asinh, "Asinh", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acos, "Acos", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acos, "Acos", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acosh, "Acosh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acosh, "Acosh", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan, "Atan", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan, "Atan", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan2, "Atan2", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan2, "Atan2", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atanh, "Atanh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atanh, "Atanh", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Log10, "Log10", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Log10, "Log10", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Pow, "Pow", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Pow, "Pow", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Exp, "Exp", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Exp, "Exp", "System", "MathF"); +#if !READYTORUN + // These are normally handled via the SSE4.1 instructions ROUNDSS/ROUNDSD. + // However, we don't know the ISAs the target machine supports so we should + // fallback to the method call implementation instead. + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Ceiling, "Ceiling", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Ceiling, "Ceiling", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Floor, "Floor", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Floor, "Floor", "System", "MathF"); +#endif + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetChar, null, null, null); // unused + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_GetDimLength, "GetLength", "System", "Array"); // not handled + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Get, "Get", null, null); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Address, "Address", null, null); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Set, "Set", null, null); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StringGetChar, "get_Chars", "System", "String"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StringLength, "get_Length", "System", "String"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InitializeArray, "InitializeArray", "System.Runtime.CompilerServices", "RuntimeHelpers"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetTypeFromHandle, "GetTypeFromHandle", "System", "Type"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_RTH_GetValueInternal, "GetValueInternal", "System", "RuntimeTypeHandle"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_TypeEQ, "op_Equality", "System", "Type"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_TypeNEQ, "op_Inequality", "System", "Type"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Object_GetType, "GetType", "System", "Object"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetStubContext, "GetStubContext", "System.StubHelpers", "StubHelpers"); // interop-specific + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr, "GetStubContextAddr", "System.StubHelpers", "StubHelpers"); // interop-specific + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetNDirectTarget, "GetNDirectTarget", "System.StubHelpers", "StubHelpers"); // interop-specific + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedAdd32, "Add", System.Threading", "Interlocked"); // unused + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedAdd64, "Add", System.Threading", "Interlocked"); // unused + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd32, "ExchangeAdd", "System.Threading", "Interlocked"); + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd64, "ExchangeAdd", "System.Threading", "Interlocked"); // ambiguous match + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg32, "Exchange", "System.Threading", "Interlocked"); + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg64, "Exchange", "System.Threading", "Interlocked"); // ambiguous match + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg32, "CompareExchange", "System.Threading", "Interlocked"); + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg64, "CompareExchange", "System.Threading", "Interlocked"); // ambiguous match + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_MemoryBarrier, "MemoryBarrier", "System.Threading", "Interlocked"); + // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetCurrentManagedThread, "GetCurrentThreadNative", "System", "Thread"); // not in .NET Core + // 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"); + 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 == 54); + + return table; + } + + static IntrinsicHashtable s_IntrinsicHashtable = InitializeIntrinsicHashtable(); + + private CorInfoIntrinsics getIntrinsicID(CORINFO_METHOD_STRUCT_* ftn, byte* pMustExpand) + { + var method = HandleToObject(ftn); + return getIntrinsicID(method, pMustExpand); + } + + private CorInfoIntrinsics getIntrinsicID(MethodDesc method, byte* pMustExpand) + { + if (pMustExpand != null) + *pMustExpand = 0; + + Debug.Assert(method.IsIntrinsic); + + IntrinsicKey key = new IntrinsicKey(); + key.MethodName = method.Name; + + var metadataType = method.OwningType as MetadataType; + if (metadataType != null) + { + key.TypeNamespace = metadataType.Namespace; + key.TypeName = metadataType.Name; + } + + IntrinsicEntry entry; + if (!s_IntrinsicHashtable.TryGetValue(key, out entry)) + return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; + + // Some intrinsics need further disambiguation + CorInfoIntrinsics id = entry.Id; + switch (id) + { + case CorInfoIntrinsics.CORINFO_INTRINSIC_Abs: + { + // RyuJIT handles floating point overloads only + var returnTypeCategory = method.Signature.ReturnType.Category; + if (returnTypeCategory != TypeFlags.Double && returnTypeCategory != TypeFlags.Single) + return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; + } + break; + case CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Get: + case CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Address: + case CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Set: + if (!method.OwningType.IsArray) + return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; + break; + + case CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd32: + case CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg32: + case CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg32: + { + // RyuJIT handles int32 and int64 overloads only + var returnTypeCategory = method.Signature.ReturnType.Category; + if (returnTypeCategory != TypeFlags.Int32 && returnTypeCategory != TypeFlags.Int64 && returnTypeCategory != TypeFlags.IntPtr) + return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; + + // int64 overloads have different ids + if (returnTypeCategory == TypeFlags.Int64) + { + Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd32 + 1 == (int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd64); + Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg32 + 1 == (int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg64); + Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg32 + 1 == (int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg64); + id = (CorInfoIntrinsics)((int)id + 1); + } + } + break; + + case CorInfoIntrinsics.CORINFO_INTRINSIC_RTH_GetValueInternal: +#if !READYTORUN + case CorInfoIntrinsics.CORINFO_INTRINSIC_InitializeArray: +#endif + case CorInfoIntrinsics.CORINFO_INTRINSIC_ByReference_Ctor: + case CorInfoIntrinsics.CORINFO_INTRINSIC_ByReference_Value: + if (pMustExpand != null) + *pMustExpand = 1; + break; + + case CorInfoIntrinsics.CORINFO_INTRINSIC_GetRawHandle: + if (pMustExpand != null) + *pMustExpand = 1; + break; + + case CorInfoIntrinsics.CORINFO_INTRINSIC_Span_GetItem: + case CorInfoIntrinsics.CORINFO_INTRINSIC_ReadOnlySpan_GetItem: + { + // RyuJIT handles integer overload only + var argumentTypeCategory = method.Signature[0].Category; + if (argumentTypeCategory != TypeFlags.Int32) + return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; + } + break; + + default: + break; + } + + return id; + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs new file mode 100644 index 00000000000..a3301691758 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs @@ -0,0 +1,3075 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; + +#if SUPPORT_JIT +using Internal.Runtime.CompilerServices; +#endif + +using Internal.IL; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; +using Internal.CorConstants; + +using ILCompiler; +using ILCompiler.DependencyAnalysis; + +#if READYTORUN +using System.Reflection.Metadata.Ecma335; +using ILCompiler.DependencyAnalysis.ReadyToRun; +#endif + +namespace Internal.JitInterface +{ + internal unsafe sealed partial class CorInfoImpl + { + // + // Global initialization and state + // + private enum ImageFileMachine + { + I386 = 0x014c, + IA64 = 0x0200, + AMD64 = 0x8664, + ARM = 0x01c4, + } + + private const string JitLibrary = "clrjitilc"; + +#if SUPPORT_JIT + private const string JitSupportLibrary = "*"; +#else + private const string JitSupportLibrary = "jitinterface"; +#endif + + private IntPtr _jit; + + private IntPtr _unmanagedCallbacks; // array of pointers to JIT-EE interface callbacks + private Object _keepAlive; // Keeps delegates for the callbacks alive + + private ExceptionDispatchInfo _lastException; + + private static bool s_jitRegistered = RegisterJITModule(); + + [DllImport(JitLibrary)] + private extern static IntPtr PAL_RegisterModule([MarshalAs(UnmanagedType.LPUTF8Str)] string moduleName); + + [DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)] // stdcall in CoreCLR! + private extern static IntPtr jitStartup(IntPtr host); + + [DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr getJit(); + + [DllImport(JitSupportLibrary)] + private extern static IntPtr GetJitHost(IntPtr configProvider); + + // + // Per-method initialization and state + // + private static CorInfoImpl GetThis(IntPtr thisHandle) + { + CorInfoImpl _this = Unsafe.Read((void*)thisHandle); + Debug.Assert(_this is CorInfoImpl); + return _this; + } + + [DllImport(JitSupportLibrary)] + private extern static CorJitResult JitCompileMethod(out IntPtr exception, + IntPtr jit, IntPtr thisHandle, IntPtr callbacks, + ref CORINFO_METHOD_INFO info, uint flags, out IntPtr nativeEntry, out uint codeSize); + + [DllImport(JitSupportLibrary)] + private extern static uint GetMaxIntrinsicSIMDVectorLength(IntPtr jit, CORJIT_FLAGS* flags); + + [DllImport(JitSupportLibrary)] + private extern static IntPtr AllocException([MarshalAs(UnmanagedType.LPWStr)]string message, int messageLength); + + private IntPtr AllocException(Exception ex) + { + _lastException = ExceptionDispatchInfo.Capture(ex); + + string exString = ex.ToString(); + IntPtr nativeException = AllocException(exString, exString.Length); + if (_nativeExceptions == null) + { + _nativeExceptions = new List(); + } + _nativeExceptions.Add(nativeException); + return nativeException; + } + + [DllImport(JitSupportLibrary)] + private extern static void FreeException(IntPtr obj); + + [DllImport(JitSupportLibrary)] + private extern static char* GetExceptionMessage(IntPtr obj); + + private JitConfigProvider _jitConfig; + + private readonly UnboxingMethodDescFactory _unboxingThunkFactory; + + private static bool RegisterJITModule() + { + if ((Environment.OSVersion.Platform == PlatformID.Unix) || (Environment.OSVersion.Platform == PlatformID.MacOSX)) + { + return PAL_RegisterModule("libclrjitilc.so") != (IntPtr)1; + } + else + { + return true; + } + } + + private IntPtr JitLibraryResolver(string libraryName, System.Reflection.Assembly assembly, DllImportSearchPath? searchPath) + { + IntPtr libHandle = IntPtr.Zero; + if (libraryName == JitLibrary) + { + libHandle = NativeLibrary.Load(_jitConfig.JitPath, assembly, searchPath); + } + return libHandle; + } + + public CorInfoImpl(JitConfigProvider jitConfig) + { + // + // Global initialization + // + _jitConfig = jitConfig; + if (!s_jitRegistered) + { + throw new IOException("Failed to register JIT"); + } + + if (_jitConfig.JitPath != null) + { + NativeLibrary.SetDllImportResolver(typeof(CorInfoImpl).Assembly, JitLibraryResolver); + } + + jitStartup(GetJitHost(_jitConfig.UnmanagedInstance)); + + _jit = getJit(); + if (_jit == IntPtr.Zero) + { + throw new IOException("Failed to initialize JIT"); + } + + _unmanagedCallbacks = GetUnmanagedCallbacks(out _keepAlive); + + _unboxingThunkFactory = new UnboxingMethodDescFactory(); + } + + public TextWriter Log + { + get + { + return _compilation.Logger.Writer; + } + } + + private CORINFO_MODULE_STRUCT_* _methodScope; // Needed to resolve CORINFO_EH_CLAUSE tokens + + private bool _isFallbackBodyCompilation; // True if we're compiling a fallback method body after compiling the real body failed + + private void CompileMethodInternal(IMethodNode methodCodeNodeNeedingCode, MethodIL methodIL = null) + { + _isFallbackBodyCompilation = methodIL != null; + + CORINFO_METHOD_INFO methodInfo; + methodIL = Get_CORINFO_METHOD_INFO(MethodBeingCompiled, methodIL, &methodInfo); + + // This is e.g. an "extern" method in C# without a DllImport or InternalCall. + if (methodIL == null) + { + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramSpecific, MethodBeingCompiled); + } + + _methodScope = methodInfo.scope; + +#if !READYTORUN + SetDebugInformation(methodCodeNodeNeedingCode, methodIL); +#endif + + CorInfoImpl _this = this; + + IntPtr exception; + IntPtr nativeEntry; + uint codeSize; + var result = JitCompileMethod(out exception, + _jit, (IntPtr)Unsafe.AsPointer(ref _this), _unmanagedCallbacks, + ref methodInfo, (uint)CorJitFlag.CORJIT_FLAG_CALL_GETJITFLAGS, out nativeEntry, out codeSize); + if (exception != IntPtr.Zero) + { + if (_lastException != null) + { + // If we captured a managed exception, rethrow that. + // TODO: might not actually be the real reason. It could be e.g. a JIT failure/bad IL that followed + // an inlining attempt with a type system problem in it... +#if SUPPORT_JIT + _lastException.Throw(); +#else + if (_lastException.SourceException is TypeSystemException) + { + // Type system exceptions can be turned into code that throws the exception at runtime. + _lastException.Throw(); + } +#if READYTORUN + else if (_lastException.SourceException is RequiresRuntimeJitException) + { + // Runtime JIT requirement is not a cause for failure, we just mustn't JIT a particular method + _lastException.Throw(); + } +#endif + else + { + // This is just a bug somewhere. + throw new CodeGenerationFailedException(_methodCodeNode.Method, _lastException.SourceException); + } +#endif + } + + // This is a failure we don't know much about. + char* szMessage = GetExceptionMessage(exception); + string message = szMessage != null ? new string(szMessage) : "JIT Exception"; + throw new Exception(message); + } + if (result == CorJitResult.CORJIT_BADCODE) + { + ThrowHelper.ThrowInvalidProgramException(); + } + if (result != CorJitResult.CORJIT_OK) + { +#if SUPPORT_JIT + // FailFast? + throw new Exception("JIT failed"); +#else + throw new CodeGenerationFailedException(_methodCodeNode.Method); +#endif + } + + PublishCode(); + } + + private void PublishCode() + { + var relocs = _relocs.ToArray(); + Array.Sort(relocs, (x, y) => (x.Offset - y.Offset)); + + int alignment = _jitConfig.HasFlag(CorJitFlag.CORJIT_FLAG_SIZE_OPT) ? + _compilation.NodeFactory.Target.MinimumFunctionAlignment : + _compilation.NodeFactory.Target.OptimumFunctionAlignment; + + var objectData = new ObjectNode.ObjectData(_code, + relocs, + alignment, + new ISymbolDefinitionNode[] { _methodCodeNode }); + ObjectNode.ObjectData ehInfo = _ehClauses != null ? EncodeEHInfo() : null; + DebugEHClauseInfo[] debugEHClauseInfos = null; + if (_ehClauses != null) + { + debugEHClauseInfos = new DebugEHClauseInfo[_ehClauses.Length]; + for (int i = 0; i < _ehClauses.Length; i++) + { + var clause = _ehClauses[i]; + debugEHClauseInfos[i] = new DebugEHClauseInfo(clause.TryOffset, clause.TryLength, + clause.HandlerOffset, clause.HandlerLength); + } + } + + _methodCodeNode.SetCode(objectData +#if !SUPPORT_JIT && !READYTORUN + , isFoldable: (_compilation._compilationOptions & RyuJitCompilationOptions.MethodBodyFolding) != 0 +#endif + ); + + _methodCodeNode.InitializeFrameInfos(_frameInfos); + _methodCodeNode.InitializeDebugEHClauseInfos(debugEHClauseInfos); + _methodCodeNode.InitializeGCInfo(_gcInfo); + _methodCodeNode.InitializeEHInfo(ehInfo); + + _methodCodeNode.InitializeDebugLocInfos(_debugLocInfos); + _methodCodeNode.InitializeDebugVarInfos(_debugVarInfos); + PublishProfileData(); + } + + partial void PublishProfileData(); + + private MethodDesc MethodBeingCompiled + { + get + { + return _methodCodeNode.Method; + } + } + + private int PointerSize + { + get + { + return _compilation.TypeSystemContext.Target.PointerSize; + } + } + + private Dictionary _pins = new Dictionary(); + + private IntPtr GetPin(Object obj) + { + GCHandle handle; + if (!_pins.TryGetValue(obj, out handle)) + { + handle = GCHandle.Alloc(obj, GCHandleType.Pinned); + _pins.Add(obj, handle); + } + return handle.AddrOfPinnedObject(); + } + + private List _nativeExceptions; + + private void CompileMethodCleanup() + { + foreach (var pin in _pins) + pin.Value.Free(); + _pins.Clear(); + + if (_nativeExceptions != null) + { + foreach (IntPtr ex in _nativeExceptions) + FreeException(ex); + _nativeExceptions = null; + } + + _methodCodeNode = null; + + _code = null; + _coldCode = null; + + _roData = null; + _roDataBlob = null; + + _relocs = new ArrayBuilder(); + + _numFrameInfos = 0; + _usedFrameInfos = 0; + _frameInfos = null; + + _gcInfo = null; + _ehClauses = null; + +#if !READYTORUN + _sequencePoints = null; + _variableToTypeDesc = null; +#endif + _debugLocInfos = null; + _debugVarInfos = null; + _lastException = null; + +#if READYTORUN + _profileDataNode = null; +#endif + } + + private Dictionary _objectToHandle = new Dictionary(); + private List _handleToObject = new List(); + + private const int handleMultipler = 8; + private const int handleBase = 0x420000; + + private IntPtr ObjectToHandle(Object obj) + { + IntPtr handle; + if (!_objectToHandle.TryGetValue(obj, out handle)) + { + handle = (IntPtr)(handleMultipler * _handleToObject.Count + handleBase); + _handleToObject.Add(obj); + _objectToHandle.Add(obj, handle); + } + return handle; + } + + private Object HandleToObject(IntPtr handle) + { + int index = ((int)handle - handleBase) / handleMultipler; + return _handleToObject[index]; + } + + private MethodDesc HandleToObject(CORINFO_METHOD_STRUCT_* method) { return (MethodDesc)HandleToObject((IntPtr)method); } + private CORINFO_METHOD_STRUCT_* ObjectToHandle(MethodDesc method) { return (CORINFO_METHOD_STRUCT_*)ObjectToHandle((Object)method); } + + private TypeDesc HandleToObject(CORINFO_CLASS_STRUCT_* type) { return (TypeDesc)HandleToObject((IntPtr)type); } + private CORINFO_CLASS_STRUCT_* ObjectToHandle(TypeDesc type) { return (CORINFO_CLASS_STRUCT_*)ObjectToHandle((Object)type); } + + private FieldDesc HandleToObject(CORINFO_FIELD_STRUCT_* field) { return (FieldDesc)HandleToObject((IntPtr)field); } + private CORINFO_FIELD_STRUCT_* ObjectToHandle(FieldDesc field) { return (CORINFO_FIELD_STRUCT_*)ObjectToHandle((Object)field); } + + private MethodIL Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, CORINFO_METHOD_INFO* methodInfo) + { + // MethodIL can be provided externally for the case of a method whose IL was replaced because we couldn't compile it. + if (methodIL == null) + methodIL = _compilation.GetMethodIL(method); + + if (methodIL == null) + { + *methodInfo = default(CORINFO_METHOD_INFO); + return null; + } + + methodInfo->ftn = ObjectToHandle(method); + methodInfo->scope = (CORINFO_MODULE_STRUCT_*)ObjectToHandle(methodIL); + var ilCode = methodIL.GetILBytes(); + methodInfo->ILCode = (byte*)GetPin(ilCode); + methodInfo->ILCodeSize = (uint)ilCode.Length; + methodInfo->maxStack = (uint)methodIL.MaxStack; + methodInfo->EHcount = (uint)methodIL.GetExceptionRegions().Length; + methodInfo->options = methodIL.IsInitLocals ? CorInfoOptions.CORINFO_OPT_INIT_LOCALS : (CorInfoOptions)0; + + if (method.AcquiresInstMethodTableFromThis()) + { + methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_FROM_THIS; + } + else if (method.RequiresInstMethodDescArg()) + { + methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_FROM_METHODDESC; + } + else if (method.RequiresInstMethodTableArg()) + { + methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_FROM_METHODTABLE; + } + + methodInfo->regionKind = CorInfoRegionKind.CORINFO_REGION_NONE; + Get_CORINFO_SIG_INFO(method, &methodInfo->args); + Get_CORINFO_SIG_INFO(methodIL.GetLocals(), &methodInfo->locals); + + return methodIL; + } + + private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool suppressHiddenArgument = false) + { + Get_CORINFO_SIG_INFO(method.Signature, sig); + + // Does the method have a hidden parameter? + bool hasHiddenParameter = !suppressHiddenArgument && method.RequiresInstArg(); + + if (method.IsIntrinsic) + { + // Some intrinsics will beg to differ about the hasHiddenParameter decision +#if !READYTORUN + if (_compilation.TypeSystemContext.IsSpecialUnboxingThunkTargetMethod(method)) + hasHiddenParameter = false; +#endif + + if (method.IsArrayAddressMethod()) + hasHiddenParameter = true; + + // We only populate sigInst for intrinsic methods because most of the time, + // JIT doesn't care what the instantiation is and this is expensive. + Instantiation owningTypeInst = method.OwningType.Instantiation; + sig->sigInst.classInstCount = (uint)owningTypeInst.Length; + if (owningTypeInst.Length > 0) + { + var classInst = new IntPtr[owningTypeInst.Length]; + for (int i = 0; i < owningTypeInst.Length; i++) + classInst[i] = (IntPtr)ObjectToHandle(owningTypeInst[i]); + sig->sigInst.classInst = (CORINFO_CLASS_STRUCT_**)GetPin(classInst); + } + } + + if (hasHiddenParameter) + { + sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_PARAMTYPE; + } + } + + private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* sig) + { + sig->callConv = (CorInfoCallConv)(signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask); + + // Varargs are not supported in .NET Core + if (sig->callConv == CorInfoCallConv.CORINFO_CALLCONV_VARARG) + ThrowHelper.ThrowBadImageFormatException(); + + if (!signature.IsStatic) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_HASTHIS; + + TypeDesc returnType = signature.ReturnType; + + CorInfoType corInfoRetType = asCorInfoType(signature.ReturnType, &sig->retTypeClass); + sig->_retType = (byte)corInfoRetType; + sig->retTypeSigClass = sig->retTypeClass; // The difference between the two is not relevant for ILCompiler + + sig->flags = 0; // used by IL stubs code + + sig->numArgs = (ushort)signature.Length; + + sig->args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index + + sig->sigInst.classInst = null; // Not used by the JIT + sig->sigInst.classInstCount = 0; // Not used by the JIT + sig->sigInst.methInst = null; // Not used by the JIT + sig->sigInst.methInstCount = (uint)signature.GenericParameterCount; + + sig->pSig = (byte*)ObjectToHandle(signature); + sig->cbSig = 0; // Not used by the JIT + sig->scope = null; // Not used by the JIT + sig->token = 0; // Not used by the JIT + } + + private void Get_CORINFO_SIG_INFO(LocalVariableDefinition[] locals, CORINFO_SIG_INFO* sig) + { + sig->callConv = CorInfoCallConv.CORINFO_CALLCONV_DEFAULT; + sig->_retType = (byte)CorInfoType.CORINFO_TYPE_VOID; + sig->retTypeClass = null; + sig->retTypeSigClass = null; + sig->flags = (byte)CorInfoSigInfoFlags.CORINFO_SIGFLAG_IS_LOCAL_SIG; + + sig->numArgs = (ushort)locals.Length; + + sig->sigInst.classInst = null; + sig->sigInst.classInstCount = 0; + sig->sigInst.methInst = null; + sig->sigInst.methInstCount = 0; + + sig->args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index + + sig->pSig = (byte*)ObjectToHandle(locals); + sig->cbSig = 0; // Not used by the JIT + sig->scope = null; // Not used by the JIT + sig->token = 0; // Not used by the JIT + } + + private CorInfoType asCorInfoType(TypeDesc type) + { + if (type.IsEnum) + { + type = type.UnderlyingType; + } + + if (type.IsPrimitive) + { + Debug.Assert((CorInfoType)TypeFlags.Void == CorInfoType.CORINFO_TYPE_VOID); + Debug.Assert((CorInfoType)TypeFlags.Double == CorInfoType.CORINFO_TYPE_DOUBLE); + + return (CorInfoType)type.Category; + } + + if (type.IsPointer || type.IsFunctionPointer) + { + return CorInfoType.CORINFO_TYPE_PTR; + } + + if (type.IsByRef) + { + return CorInfoType.CORINFO_TYPE_BYREF; + } + + if (type.IsValueType) + { + return CorInfoType.CORINFO_TYPE_VALUECLASS; + } + + return CorInfoType.CORINFO_TYPE_CLASS; + } + + private CorInfoType asCorInfoType(TypeDesc type, CORINFO_CLASS_STRUCT_** structType) + { + var corInfoType = asCorInfoType(type); + *structType = ((corInfoType == CorInfoType.CORINFO_TYPE_CLASS) || + (corInfoType == CorInfoType.CORINFO_TYPE_VALUECLASS) || + (corInfoType == CorInfoType.CORINFO_TYPE_BYREF)) ? ObjectToHandle(type) : null; + return corInfoType; + } + + private CORINFO_CONTEXT_STRUCT* contextFromMethod(MethodDesc method) + { + return (CORINFO_CONTEXT_STRUCT*)(((ulong)ObjectToHandle(method)) | (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_METHOD); + } + + private CORINFO_CONTEXT_STRUCT* contextFromType(TypeDesc type) + { + return (CORINFO_CONTEXT_STRUCT*)(((ulong)ObjectToHandle(type)) | (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_CLASS); + } + + private MethodDesc methodFromContext(CORINFO_CONTEXT_STRUCT* contextStruct) + { + if (((ulong)contextStruct & (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK) == (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_CLASS) + { + return null; + } + else + { + return HandleToObject((CORINFO_METHOD_STRUCT_*)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK)); + } + } + + private TypeDesc typeFromContext(CORINFO_CONTEXT_STRUCT* contextStruct) + { + if (((ulong)contextStruct & (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK) == (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_CLASS) + { + return HandleToObject((CORINFO_CLASS_STRUCT_*)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK)); + } + else + { + return methodFromContext(contextStruct).OwningType; + } + } + + private TypeSystemEntity entityFromContext(CORINFO_CONTEXT_STRUCT* contextStruct) + { + return (TypeSystemEntity)HandleToObject((IntPtr)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK)); + } + + private uint getMethodAttribsInternal(MethodDesc method) + { + CorInfoFlag result = 0; + + // CORINFO_FLG_PROTECTED - verification only + + if (method.Signature.IsStatic) + result |= CorInfoFlag.CORINFO_FLG_STATIC; + + if (method.IsSynchronized) + result |= CorInfoFlag.CORINFO_FLG_SYNCH; + if (method.IsIntrinsic) + result |= CorInfoFlag.CORINFO_FLG_INTRINSIC | CorInfoFlag.CORINFO_FLG_JIT_INTRINSIC; + if (method.IsVirtual) + result |= CorInfoFlag.CORINFO_FLG_VIRTUAL; + if (method.IsAbstract) + result |= CorInfoFlag.CORINFO_FLG_ABSTRACT; + if (method.IsConstructor || method.IsStaticConstructor) + result |= CorInfoFlag.CORINFO_FLG_CONSTRUCTOR; + + // + // See if we need to embed a .cctor call at the head of the + // method body. + // + + // method or class might have the final bit + if (_compilation.IsEffectivelySealed(method)) + result |= CorInfoFlag.CORINFO_FLG_FINAL; + + if (method.IsSharedByGenericInstantiations) + result |= CorInfoFlag.CORINFO_FLG_SHAREDINST; + + if (method.IsPInvoke) + { + result |= CorInfoFlag.CORINFO_FLG_PINVOKE; + + if (method.IsRawPInvoke()) + { + result |= CorInfoFlag.CORINFO_FLG_FORCEINLINE; + } + } + +#if READYTORUN + if (method.RequireSecObject) + { + result |= CorInfoFlag.CORINFO_FLG_DONT_INLINE_CALLER; + } +#endif + + if (method.IsAggressiveOptimization) + { + result |= CorInfoFlag.CORINFO_FLG_AGGRESSIVE_OPT; + } + + // TODO: Cache inlining hits + // Check for an inlining directive. + + if (method.IsNoInlining) + { + /* Function marked as not inlineable */ + result |= CorInfoFlag.CORINFO_FLG_DONT_INLINE; + } + else if (method.IsAggressiveInlining) + { + result |= CorInfoFlag.CORINFO_FLG_FORCEINLINE; + } + + if (method.OwningType.IsDelegate && method.Name == "Invoke") + { + // This is now used to emit efficient invoke code for any delegate invoke, + // including multicast. + result |= CorInfoFlag.CORINFO_FLG_DELEGATE_INVOKE; + + // RyuJIT special cases this method; it would assert if it's not final + // and we might not have set the bit in the code above. + result |= CorInfoFlag.CORINFO_FLG_FINAL; + } + +#if READYTORUN + // Check for SIMD intrinsics + DefType owningDefType = method.OwningType as DefType; + if (owningDefType != null && VectorFieldLayoutAlgorithm.IsVectorOfTType(owningDefType)) + { + throw new RequiresRuntimeJitException("This function is using SIMD intrinsics, their size is machine specific"); + } +#endif + + // Check for hardware intrinsics + if (HardwareIntrinsicHelpers.IsHardwareIntrinsic(method)) + { +#if READYTORUN + if (!isMethodDefinedInCoreLib()) + { + throw new RequiresRuntimeJitException("This function is not defined in CoreLib and it is using hardware intrinsics."); + } +#endif +#if !READYTORUN + // Do not report the get_IsSupported method as an intrinsic - RyuJIT would expand it to + // a constant depending on the code generation flags passed to it, but we would like to + // do a dynamic check instead. + if (!HardwareIntrinsicHelpers.IsIsSupportedMethod(method) + || HardwareIntrinsicHelpers.IsKnownSupportedIntrinsicAtCompileTime(method)) +#endif + { + result |= CorInfoFlag.CORINFO_FLG_JIT_INTRINSIC; + } + } + + result |= CorInfoFlag.CORINFO_FLG_NOSECURITYWRAP; + + return (uint)result; + } + + private void setMethodAttribs(CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) + { + // TODO: Inlining + } + + private void getMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) + { + MethodDesc method = HandleToObject(ftn); + + // There might be a more concrete parent type specified - this can happen when inlining. + if (memberParent != null) + { + TypeDesc type = HandleToObject(memberParent); + + // Typically, the owning type of the method is a canonical type and the member parent + // supplied by RyuJIT is a concrete instantiation. + if (type != method.OwningType) + { + Debug.Assert(type.HasSameTypeDefinition(method.OwningType)); + Instantiation methodInst = method.Instantiation; + method = _compilation.TypeSystemContext.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)type); + if (methodInst.Length > 0) + { + method = method.MakeInstantiatedMethod(methodInst); + } + } + } + + Get_CORINFO_SIG_INFO(method, sig); + } + + private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info) + { + MethodIL methodIL = Get_CORINFO_METHOD_INFO(HandleToObject(ftn), null, info); + return methodIL != null; + } + + private CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint pRestrictions) + { + MethodDesc callerMethod = HandleToObject(callerHnd); + MethodDesc calleeMethod = HandleToObject(calleeHnd); + + if (_compilation.CanInline(callerMethod, calleeMethod)) + { + // No restrictions on inlining + return CorInfoInline.INLINE_PASS; + } + else + { + // Call may not be inlined + return CorInfoInline.INLINE_NEVER; + } + } + + private void reportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) + { + } + + private void reportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason) + { + } + + private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + var methodIL = _compilation.GetMethodIL(HandleToObject(ftn)); + + var ehRegion = methodIL.GetExceptionRegions()[EHnumber]; + + clause.Flags = (CORINFO_EH_CLAUSE_FLAGS)ehRegion.Kind; + clause.TryOffset = (uint)ehRegion.TryOffset; + clause.TryLength = (uint)ehRegion.TryLength; + clause.HandlerOffset = (uint)ehRegion.HandlerOffset; + clause.HandlerLength = (uint)ehRegion.HandlerLength; + clause.ClassTokenOrOffset = (uint)((ehRegion.Kind == ILExceptionRegionKind.Filter) ? ehRegion.FilterOffset : ehRegion.ClassToken); + } + + private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) + { + var m = HandleToObject(method); + return ObjectToHandle(m.OwningType); + } + + private CORINFO_MODULE_STRUCT_* getMethodModule(CORINFO_METHOD_STRUCT_* method) + { + MethodDesc m = HandleToObject(method); + if (m is UnboxingMethodDesc unboxingMethodDesc) + { + m = unboxingMethodDesc.Target; + } + + MethodIL methodIL = _compilation.GetMethodIL(m); + if (methodIL == null) + { + return null; + } + return (CORINFO_MODULE_STRUCT_*)ObjectToHandle(methodIL); + } + + private CORINFO_METHOD_STRUCT_* resolveVirtualMethod(CORINFO_METHOD_STRUCT_* baseMethod, CORINFO_CLASS_STRUCT_* derivedClass, CORINFO_CONTEXT_STRUCT* ownerType) + { + TypeDesc implType = HandleToObject(derivedClass); + + // __Canon cannot be devirtualized + if (implType.IsCanonicalDefinitionType(CanonicalFormKind.Any)) + { + return null; + } + + MethodDesc decl = HandleToObject(baseMethod); + Debug.Assert(!decl.HasInstantiation); + + if (ownerType != null) + { + TypeDesc ownerTypeDesc = typeFromContext(ownerType); + if (decl.OwningType != ownerTypeDesc) + { + Debug.Assert(ownerTypeDesc is InstantiatedType); + decl = _compilation.TypeSystemContext.GetMethodForInstantiatedType(decl.GetTypicalMethodDefinition(), (InstantiatedType)ownerTypeDesc); + } + } + + MethodDesc impl = _compilation.ResolveVirtualMethod(decl, implType); + + if (impl != null) + { + if (impl.OwningType.IsValueType) + { + impl = _unboxingThunkFactory.GetUnboxingMethod(impl); + } + + return ObjectToHandle(impl); + } + + return null; + } + + private CORINFO_METHOD_STRUCT_* getUnboxedEntry(CORINFO_METHOD_STRUCT_* ftn, byte* requiresInstMethodTableArg) + { + MethodDesc result = null; + bool requiresInstMTArg = false; + + MethodDesc method = HandleToObject(ftn); + if (method.IsUnboxingThunk()) + { + result = method.GetUnboxedMethod(); + requiresInstMTArg = method.RequiresInstMethodTableArg(); + } + + if (requiresInstMethodTableArg != null) + { + *requiresInstMethodTableArg = requiresInstMTArg ? (byte)1 : (byte)0; + } + + return result != null ? ObjectToHandle(result) : null; + } + + private CORINFO_CLASS_STRUCT_* getDefaultEqualityComparerClass(CORINFO_CLASS_STRUCT_* elemType) + { + TypeDesc comparand = HandleToObject(elemType); + TypeDesc comparer = IL.Stubs.ComparerIntrinsics.GetEqualityComparerForType(comparand); + return comparer != null ? ObjectToHandle(comparer) : null; + } + + private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) + { + TypeDesc type = HandleToObject(classHnd); + return type.IsIntrinsic; + } + + private CorInfoUnmanagedCallConv getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method) + { + MethodSignatureFlags unmanagedCallConv = HandleToObject(method).GetPInvokeMethodMetadata().Flags.UnmanagedCallingConvention; + + // Verify that it is safe to convert MethodSignatureFlags.UnmanagedCallingConvention to CorInfoUnmanagedCallConv via a simple cast + Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_C == (int)MethodSignatureFlags.UnmanagedCallingConventionCdecl); + Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_STDCALL == (int)MethodSignatureFlags.UnmanagedCallingConventionStdCall); + Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_THISCALL == (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall); + + return (CorInfoUnmanagedCallConv)unmanagedCallConv; + } + + private bool satisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) + { 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 CorInfoInstantiationVerification isInstantiationOfVerifiedGeneric(CORINFO_METHOD_STRUCT_* method) + { throw new NotImplementedException("isInstantiationOfVerifiedGeneric"); } + private void initConstraintsForVerification(CORINFO_METHOD_STRUCT_* method, ref bool pfHasCircularClassConstraints, ref bool pfHasCircularMethodConstraint) + { throw new NotImplementedException("isInstantiationOfVerifiedGeneric"); } + + private CorInfoCanSkipVerificationResult canSkipMethodVerification(CORINFO_METHOD_STRUCT_* ftnHandle) + { + return CorInfoCanSkipVerificationResult.CORINFO_VERIFICATION_CAN_SKIP; + } + + private void methodMustBeLoadedBeforeCodeIsRun(CORINFO_METHOD_STRUCT_* method) + { + } + + private CORINFO_METHOD_STRUCT_* mapMethodDeclToMethodImpl(CORINFO_METHOD_STRUCT_* method) + { throw new NotImplementedException("mapMethodDeclToMethodImpl"); } + + private static object ResolveTokenWithSubstitution(MethodIL methodIL, mdToken token, Instantiation typeInst, Instantiation methodInst) + { + // Grab the generic definition of the method IL, resolve the token within the definition, + // and instantiate it with the given context. + object result = methodIL.GetMethodILDefinition().GetObject((int)token); + + if (result is MethodDesc methodResult) + { + result = methodResult.InstantiateSignature(typeInst, methodInst); + } + else if (result is FieldDesc fieldResult) + { + result = fieldResult.InstantiateSignature(typeInst, methodInst); + } + else + { + result = ((TypeDesc)result).InstantiateSignature(typeInst, methodInst); + } + + return result; + } + + private static object ResolveTokenInScope(MethodIL methodIL, object typeOrMethodContext, mdToken token) + { + MethodDesc owningMethod = methodIL.OwningMethod; + + // If token context differs from the scope, it means we're inlining. + // If we're inlining a shared method body, we might be able to un-share + // the referenced token and avoid runtime lookups. + // Resolve the token in the inlining context. + + object result; + if (owningMethod != typeOrMethodContext && + owningMethod.IsCanonicalMethod(CanonicalFormKind.Any)) + { + Instantiation typeInst = default; + Instantiation methodInst = default; + + if (typeOrMethodContext is TypeDesc typeContext) + { + Debug.Assert(typeContext.HasSameTypeDefinition(owningMethod.OwningType)); + typeInst = typeContext.Instantiation; + } + else + { + var methodContext = (MethodDesc)typeOrMethodContext; + Debug.Assert(methodContext.GetTypicalMethodDefinition() == owningMethod.GetTypicalMethodDefinition()); + typeInst = methodContext.OwningType.Instantiation; + methodInst = methodContext.Instantiation; + } + + result = ResolveTokenWithSubstitution(methodIL, token, typeInst, methodInst); + } + else + { + // Not inlining - just resolve the token within the methodIL + result = methodIL.GetObject((int)token); + } + + return result; + } + + private object GetRuntimeDeterminedObjectForToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + // Since RyuJIT operates on canonical types (as opposed to runtime determined ones), but the + // dependency analysis operates on runtime determined ones, we convert the resolved token + // to the runtime determined form (e.g. Foo<__Canon> becomes Foo). + + var methodIL = (MethodIL)HandleToObject((IntPtr)pResolvedToken.tokenScope); + var typeOrMethodContext = HandleToObject((IntPtr)pResolvedToken.tokenContext); + + object result = ResolveTokenInScope(methodIL, typeOrMethodContext, pResolvedToken.token); + + if (result is MethodDesc method) + { + if (method.IsSharedByGenericInstantiations) + { + MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget(); + result = ResolveTokenWithSubstitution(methodIL, pResolvedToken.token, sharedMethod.OwningType.Instantiation, sharedMethod.Instantiation); + Debug.Assert(((MethodDesc)result).IsRuntimeDeterminedExactMethod); + } + } + else if (result is FieldDesc field) + { + if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget(); + result = ResolveTokenWithSubstitution(methodIL, pResolvedToken.token, sharedMethod.OwningType.Instantiation, sharedMethod.Instantiation); + Debug.Assert(((FieldDesc)result).OwningType.IsRuntimeDeterminedSubtype); + } + } + else + { + TypeDesc type = (TypeDesc)result; + if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget(); + result = ResolveTokenWithSubstitution(methodIL, pResolvedToken.token, sharedMethod.OwningType.Instantiation, sharedMethod.Instantiation); + Debug.Assert(((TypeDesc)result).IsRuntimeDeterminedSubtype || + /* If the resolved type is not runtime determined there's a chance we went down this path + because there was a literal typeof(__Canon) in the compiled IL - check for that + by resolving the token in the definition. */ + ((TypeDesc)methodIL.GetMethodILDefinition().GetObject((int)pResolvedToken.token)).IsCanonicalDefinitionType(CanonicalFormKind.Any)); + } + + if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Newarr) + result = ((TypeDesc)result).MakeArrayType(); + } + + return result; + } + + private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + var methodIL = (MethodIL)HandleToObject((IntPtr)pResolvedToken.tokenScope); + var typeOrMethodContext = HandleToObject((IntPtr)pResolvedToken.tokenContext); + + object result = ResolveTokenInScope(methodIL, typeOrMethodContext, pResolvedToken.token); + + pResolvedToken.hClass = null; + pResolvedToken.hMethod = null; + pResolvedToken.hField = null; + +#if READYTORUN + TypeDesc owningType = methodIL.OwningMethod.GetTypicalMethodDefinition().OwningType; + bool recordToken = _compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(owningType) && owningType is EcmaType; +#endif + + if (result is MethodDesc) + { + MethodDesc method = result as MethodDesc; + pResolvedToken.hMethod = ObjectToHandle(method); + + TypeDesc owningClass = method.OwningType; + pResolvedToken.hClass = ObjectToHandle(owningClass); + +#if !SUPPORT_JIT + _compilation.TypeSystemContext.EnsureLoadableType(owningClass); +#endif + +#if READYTORUN + if (recordToken) + { + _compilation.NodeFactory.Resolver.AddModuleTokenForMethod(method, HandleToModuleToken(ref pResolvedToken)); + } +#endif + } + else + if (result is FieldDesc) + { + FieldDesc field = result as FieldDesc; + + // References to literal fields from IL body should never resolve. + // The CLR would throw a MissingFieldException while jitting and so should we. + if (field.IsLiteral) + ThrowHelper.ThrowMissingFieldException(field.OwningType, field.Name); + + pResolvedToken.hField = ObjectToHandle(field); + + TypeDesc owningClass = field.OwningType; + pResolvedToken.hClass = ObjectToHandle(owningClass); + +#if !SUPPORT_JIT + _compilation.TypeSystemContext.EnsureLoadableType(owningClass); +#endif + +#if READYTORUN + if (recordToken) + { + _compilation.NodeFactory.Resolver.AddModuleTokenForField(field, HandleToModuleToken(ref pResolvedToken)); + } +#endif + } + else + { + TypeDesc type = (TypeDesc)result; + +#if READYTORUN + if (recordToken) + { + _compilation.NodeFactory.Resolver.AddModuleTokenForType(type, HandleToModuleToken(ref pResolvedToken)); + } +#endif + + if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Newarr) + { + if (type.IsVoid) + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramSpecific, methodIL.OwningMethod); + + type = type.MakeArrayType(); + } + pResolvedToken.hClass = ObjectToHandle(type); + +#if !SUPPORT_JIT + _compilation.TypeSystemContext.EnsureLoadableType(type); +#endif + } + + pResolvedToken.pTypeSpec = null; + pResolvedToken.cbTypeSpec = 0; + pResolvedToken.pMethodSpec = null; + pResolvedToken.cbMethodSpec = 0; + } + + private bool tryResolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + resolveToken(ref pResolvedToken); + return true; + } + + private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + var methodIL = (MethodIL)HandleToObject((IntPtr)module); + Get_CORINFO_SIG_INFO((MethodSignature)methodIL.GetObject((int)sigTOK), sig); + } + + private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + var methodIL = (MethodIL)HandleToObject((IntPtr)module); + Get_CORINFO_SIG_INFO(((MethodDesc)methodIL.GetObject((int)methTOK)), sig); + } + + private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + WellKnownType result = WellKnownType.RuntimeTypeHandle; + + if (pResolvedToken.hMethod != null) + { + result = WellKnownType.RuntimeMethodHandle; + } + else + if (pResolvedToken.hField != null) + { + result = WellKnownType.RuntimeFieldHandle; + } + + return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(result)); + } + + private CorInfoCanSkipVerificationResult canSkipVerification(CORINFO_MODULE_STRUCT_* module) + { + return CorInfoCanSkipVerificationResult.CORINFO_VERIFICATION_CAN_SKIP; + } + + private bool isValidToken(CORINFO_MODULE_STRUCT_* module, uint metaTOK) + { throw new NotImplementedException("isValidToken"); } + private bool isValidStringRef(CORINFO_MODULE_STRUCT_* module, uint metaTOK) + { throw new NotImplementedException("isValidStringRef"); } + private bool shouldEnforceCallvirtRestriction(CORINFO_MODULE_STRUCT_* scope) + { throw new NotImplementedException("shouldEnforceCallvirtRestriction"); } + + private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) + { + var type = HandleToObject(cls); + return asCorInfoType(type); + } + + private byte* getClassName(CORINFO_CLASS_STRUCT_* cls) + { + var type = HandleToObject(cls); + return (byte*)GetPin(StringToUTF8(type.ToString())); + } + + private byte* getClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) + { + var type = HandleToObject(cls) as MetadataType; + if (type != null) + { + if (namespaceName != null) + *namespaceName = (byte*)GetPin(StringToUTF8(type.Namespace)); + return (byte*)GetPin(StringToUTF8(type.Name)); + } + + if (namespaceName != null) + *namespaceName = null; + return null; + } + + private CORINFO_CLASS_STRUCT_* getTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index) + { + TypeDesc type = HandleToObject(cls); + Instantiation inst = type.Instantiation; + + return index < (uint)inst.Length ? ObjectToHandle(inst[(int)index]) : null; + } + + + private int appendClassName(short** ppBuf, ref int pnBufLen, CORINFO_CLASS_STRUCT_* cls, bool fNamespace, bool fFullInst, bool fAssembly) + { + // We support enough of this to make SIMD work, but not much else. + + Debug.Assert(fNamespace && !fFullInst && !fAssembly); + + var type = HandleToObject(cls); + string name = TypeString.Instance.FormatName(type); + + int length = name.Length; + if (pnBufLen > 0) + { + short* buffer = *ppBuf; + for (int i = 0; i < Math.Min(name.Length, pnBufLen); i++) + buffer[i] = (short)name[i]; + if (name.Length < pnBufLen) + buffer[name.Length] = 0; + else + buffer[pnBufLen - 1] = 0; + pnBufLen -= length; + *ppBuf = buffer + length; + } + + return length; + } + + private bool isValueClass(CORINFO_CLASS_STRUCT_* cls) + { + return HandleToObject(cls).IsValueType; + } + + private CorInfoInlineTypeCheck canInlineTypeCheck(CORINFO_CLASS_STRUCT_* cls, CorInfoInlineTypeCheckSource source) + { + // TODO: when we support multiple modules at runtime, this will need to do more work + // NOTE: cls can be null + return CorInfoInlineTypeCheck.CORINFO_INLINE_TYPECHECK_PASS; + } + + private bool canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_STRUCT_* cls) { throw new NotImplementedException(); } + + private uint getClassAttribs(CORINFO_CLASS_STRUCT_* cls) + { + TypeDesc type = HandleToObject(cls); + return getClassAttribsInternal(type); + } + + private uint getClassAttribsInternal(TypeDesc type) + { + // TODO: Support for verification (CORINFO_FLG_GENERIC_TYPE_VARIABLE) + + CorInfoFlag result = (CorInfoFlag)0; + + var metadataType = type as MetadataType; + + // The array flag is used to identify the faked-up methods on + // array types, i.e. .ctor, Get, Set and Address + if (type.IsArray) + result |= CorInfoFlag.CORINFO_FLG_ARRAY; + + if (type.IsInterface) + result |= CorInfoFlag.CORINFO_FLG_INTERFACE; + + if (type.IsArray || type.IsString) + result |= CorInfoFlag.CORINFO_FLG_VAROBJSIZE; + + if (type.IsValueType) + { + result |= CorInfoFlag.CORINFO_FLG_VALUECLASS; + + if (metadataType.IsByRefLike) + result |= CorInfoFlag.CORINFO_FLG_CONTAINS_STACK_PTR; + + // The CLR has more complicated rules around CUSTOMLAYOUT, but this will do. + if (metadataType.IsExplicitLayout || metadataType.IsWellKnownType(WellKnownType.TypedReference)) + result |= CorInfoFlag.CORINFO_FLG_CUSTOMLAYOUT; + + // TODO + // if (type.IsUnsafeValueType) + // result |= CorInfoFlag.CORINFO_FLG_UNSAFE_VALUECLASS; + } + + if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) + result |= CorInfoFlag.CORINFO_FLG_SHAREDINST; + + if (type.HasVariance) + result |= CorInfoFlag.CORINFO_FLG_VARIANCE; + + if (type.IsDelegate) + result |= CorInfoFlag.CORINFO_FLG_DELEGATE; + + if (_compilation.IsEffectivelySealed(type)) + result |= CorInfoFlag.CORINFO_FLG_FINAL; + + if (type.IsIntrinsic) + result |= CorInfoFlag.CORINFO_FLG_INTRINSIC_TYPE; + + if (metadataType != null) + { + if (metadataType.ContainsGCPointers) + result |= CorInfoFlag.CORINFO_FLG_CONTAINS_GC_PTR; + + if (metadataType.IsBeforeFieldInit) + result |= CorInfoFlag.CORINFO_FLG_BEFOREFIELDINIT; + + // Assume overlapping fields for explicit layout. + if (metadataType.IsExplicitLayout) + result |= CorInfoFlag.CORINFO_FLG_OVERLAPPING_FIELDS; + + if (metadataType.IsAbstract) + result |= CorInfoFlag.CORINFO_FLG_ABSTRACT; + } + + return (uint)result; + } + + private bool isStructRequiringStackAllocRetBuf(CORINFO_CLASS_STRUCT_* cls) + { + // Disable this optimization. It has limited value (only kicks in on x86, and only for less common structs), + // causes bugs and introduces odd ABI differences not compatible with ReadyToRun. + return false; + } + + private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls) + { throw new NotImplementedException("getClassModule"); } + private CORINFO_ASSEMBLY_STRUCT_* getModuleAssembly(CORINFO_MODULE_STRUCT_* mod) + { throw new NotImplementedException("getModuleAssembly"); } + private byte* getAssemblyName(CORINFO_ASSEMBLY_STRUCT_* assem) + { throw new NotImplementedException("getAssemblyName"); } + + private void* LongLifetimeMalloc(UIntPtr sz) + { + return (void*)Marshal.AllocCoTaskMem((int)sz); + } + + private void LongLifetimeFree(void* obj) + { + Marshal.FreeCoTaskMem((IntPtr)obj); + } + + private byte* getClassModuleIdForStatics(CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection) + { throw new NotImplementedException("getClassModuleIdForStatics"); } + + private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) + { + TypeDesc type = HandleToObject(cls); + LayoutInt classSize = type.GetElementSize(); +#if READYTORUN + if (classSize.IsIndeterminate) + { + throw new RequiresRuntimeJitException(type); + } +#endif + return (uint)classSize.AsInt; + } + + private uint getHeapClassSize(CORINFO_CLASS_STRUCT_* cls) + { + TypeDesc type = HandleToObject(cls); + + Debug.Assert(!type.IsValueType); + Debug.Assert(type.IsDefType); + Debug.Assert(!type.IsString); +#if READYTORUN + Debug.Assert(_compilation.IsInheritanceChainLayoutFixedInCurrentVersionBubble(type)); +#endif + + return (uint)((DefType)type).InstanceByteCount.AsInt; + } + + private bool canAllocateOnStack(CORINFO_CLASS_STRUCT_* cls) + { + TypeDesc type = HandleToObject(cls); + + Debug.Assert(!type.IsValueType); + Debug.Assert(type.IsDefType); + + bool result = !type.HasFinalizer; + +#if READYTORUN + if (!_compilation.IsInheritanceChainLayoutFixedInCurrentVersionBubble(type)) + result = false; +#endif + + return result; + } + + private uint getClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint) + { + DefType type = (DefType)HandleToObject(cls); + return (uint)type.InstanceFieldAlignment.AsInt; + } + + private int GatherClassGCLayout(TypeDesc type, byte* gcPtrs) + { + int result = 0; + + if (type.IsByReferenceOfT) + { + *gcPtrs = (byte)CorInfoGCType.TYPE_GC_BYREF; + return 1; + } + + foreach (var field in type.GetFields()) + { + if (field.IsStatic) + continue; + + CorInfoGCType gcType = CorInfoGCType.TYPE_GC_NONE; + + var fieldType = field.FieldType; + if (fieldType.IsValueType) + { + var fieldDefType = (DefType)fieldType; + if (!fieldDefType.ContainsGCPointers && !fieldDefType.IsByRefLike) + continue; + + gcType = CorInfoGCType.TYPE_GC_OTHER; + } + else if (fieldType.IsGCPointer) + { + gcType = CorInfoGCType.TYPE_GC_REF; + } + else if (fieldType.IsByRef) + { + gcType = CorInfoGCType.TYPE_GC_BYREF; + } + else + { + continue; + } + + Debug.Assert(field.Offset.AsInt % PointerSize == 0); + byte* fieldGcPtrs = gcPtrs + field.Offset.AsInt / PointerSize; + + if (gcType == CorInfoGCType.TYPE_GC_OTHER) + { + result += GatherClassGCLayout(fieldType, fieldGcPtrs); + } + else + { + // Ensure that if we have multiple fields with the same offset, + // that we don't double count the data in the gc layout. + if (*fieldGcPtrs == (byte)CorInfoGCType.TYPE_GC_NONE) + { + *fieldGcPtrs = (byte)gcType; + result++; + } + else + { + Debug.Assert(*fieldGcPtrs == (byte)gcType); + } + } + } + + return result; + } + + private uint getClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) + { + uint result = 0; + + DefType type = (DefType)HandleToObject(cls); + + int pointerSize = PointerSize; + + int ptrsCount = AlignmentHelper.AlignUp(type.InstanceFieldSize.AsInt, pointerSize) / pointerSize; + + // Assume no GC pointers at first + for (int i = 0; i < ptrsCount; i++) + gcPtrs[i] = (byte)CorInfoGCType.TYPE_GC_NONE; + + if (type.ContainsGCPointers || type.IsByRefLike) + { + result = (uint)GatherClassGCLayout(type, gcPtrs); + } + return result; + } + + private uint getClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls) + { + TypeDesc type = HandleToObject(cls); + + uint result = 0; + foreach (var field in type.GetFields()) + { + if (!field.IsStatic) + result++; + } + + return result; + } + + private CORINFO_FIELD_STRUCT_* getFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) + { + TypeDesc classWithFields = HandleToObject(clsHnd); + + int iCurrentFoundField = -1; + foreach (var field in classWithFields.GetFields()) + { + if (field.IsStatic) + continue; + + ++iCurrentFoundField; + if (iCurrentFoundField == num) + { + return ObjectToHandle(field); + } + } + + // We could not find the field that was searched for. + throw new InvalidOperationException(); + } + + private bool checkMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, bool fOptional) + { throw new NotImplementedException("checkMethodModifier"); } + + private CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) + { throw new NotImplementedException("getSharedCCtorHelper"); } + private CorInfoHelpFunc getSecurityPrologHelper(CORINFO_METHOD_STRUCT_* ftn) + { throw new NotImplementedException("getSecurityPrologHelper"); } + + private CORINFO_CLASS_STRUCT_* getTypeForBox(CORINFO_CLASS_STRUCT_* cls) + { + var type = HandleToObject(cls); + + var typeForBox = type.IsNullable ? type.Instantiation[0] : type; + + return ObjectToHandle(typeForBox); + } + + private CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + var type = HandleToObject(cls); + + // we shouldn't allow boxing of types that contains stack pointers + // csc and vbc already disallow it. + if (type.IsByRefLike) + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramSpecific, MethodBeingCompiled); + + return type.IsNullable ? CorInfoHelpFunc.CORINFO_HELP_BOX_NULLABLE : CorInfoHelpFunc.CORINFO_HELP_BOX; + } + + private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + var type = HandleToObject(cls); + + return type.IsNullable ? CorInfoHelpFunc.CORINFO_HELP_UNBOX_NULLABLE : CorInfoHelpFunc.CORINFO_HELP_UNBOX; + } + + private byte* getHelperName(CorInfoHelpFunc helpFunc) + { + return (byte*)GetPin(StringToUTF8(helpFunc.ToString())); + } + + private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context, bool speculative) + { + FieldDesc fd = field == null ? null : HandleToObject(field); + Debug.Assert(fd == null || fd.IsStatic); + + MethodDesc md = HandleToObject(method); + TypeDesc type = fd != null ? fd.OwningType : typeFromContext(context); + + if (_isFallbackBodyCompilation || +#if READYTORUN + IsClassPreInited(type) +#else + !_compilation.HasLazyStaticConstructor(type) +#endif + ) + { + return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; + } + + MetadataType typeToInit = (MetadataType)type; + + if (fd == null) + { + if (typeToInit.IsBeforeFieldInit) + { + // We can wait for field accesses to run .cctor + return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; + } + + // Run .cctor on statics & constructors + if (md.Signature.IsStatic) + { + // Except don't class construct on .cctor - it would be circular + if (md.IsStaticConstructor) + { + return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; + } + } + else if (!md.IsConstructor && !typeToInit.IsValueType) + { + // According to the spec, we should be able to do this optimization for both reference and valuetypes. + // To maintain backward compatibility, we are doing it for reference types only. + // For instance methods of types with precise-initialization + // semantics, we can assume that the .ctor triggerred the + // type initialization. + // This does not hold for NULL "this" object. However, the spec does + // not require that case to work. + return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; + } + } + + if (typeToInit.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + // Shared generic code has to use helper. Moreover, tell JIT not to inline since + // inlining of generic dictionary lookups is not supported. + return CorInfoInitClassResult.CORINFO_INITCLASS_USE_HELPER | CorInfoInitClassResult.CORINFO_INITCLASS_DONT_INLINE; + } + + // + // Try to prove that the initialization is not necessary because of nesting + // + + if (fd == null) + { + // Handled above + Debug.Assert(!typeToInit.IsBeforeFieldInit); + + // Note that jit has both methods the same if asking whether to emit cctor + // for a given method's code (as opposed to inlining codegen). + MethodDesc contextMethod = methodFromContext(context); + if (contextMethod != MethodBeingCompiled && typeToInit == MethodBeingCompiled.OwningType) + { + // If we're inling a call to a method in our own type, then we should already + // have triggered the .cctor when caller was itself called. + return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; + } + } + else + { + // This optimization may cause static fields in reference types to be accessed without cctor being triggered + // for NULL "this" object. It does not conform with what the spec says. However, we have been historically + // doing it for perf reasons. + if (!typeToInit.IsValueType && !typeToInit.IsBeforeFieldInit) + { + if (typeToInit == typeFromContext(context) || typeToInit == MethodBeingCompiled.OwningType) + { + // The class will be initialized by the time we access the field. + return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; + } + } + + // If we are currently compiling the class constructor for this static field access then we can skip the initClass + if (MethodBeingCompiled.OwningType == typeToInit && MethodBeingCompiled.IsStaticConstructor) + { + // The class will be initialized by the time we access the field. + return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; + } + } + + return CorInfoInitClassResult.CORINFO_INITCLASS_USE_HELPER; + } + + private void classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_STRUCT_* cls) + { + } + + private CORINFO_CLASS_STRUCT_* getBuiltinClass(CorInfoClassId classId) + { + switch (classId) + { + case CorInfoClassId.CLASSID_SYSTEM_OBJECT: + return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Object)); + + case CorInfoClassId.CLASSID_TYPED_BYREF: + return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.TypedReference)); + + case CorInfoClassId.CLASSID_TYPE_HANDLE: + return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.RuntimeTypeHandle)); + + case CorInfoClassId.CLASSID_FIELD_HANDLE: + return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.RuntimeFieldHandle)); + + case CorInfoClassId.CLASSID_METHOD_HANDLE: + return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.RuntimeMethodHandle)); + + case CorInfoClassId.CLASSID_ARGUMENT_HANDLE: + ThrowHelper.ThrowTypeLoadException("System", "RuntimeArgumentHandle", _compilation.TypeSystemContext.SystemModule); + return null; + + case CorInfoClassId.CLASSID_STRING: + return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String)); + + case CorInfoClassId.CLASSID_RUNTIME_TYPE: + TypeDesc typeOfRuntimeType = _compilation.GetTypeOfRuntimeType(); + return typeOfRuntimeType != null ? ObjectToHandle(typeOfRuntimeType) : null; + + default: + throw new NotImplementedException(); + } + } + + private CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls) + { + var type = HandleToObject(cls); + + if (!type.IsPrimitive && !type.IsEnum) + return CorInfoType.CORINFO_TYPE_UNDEF; + + return asCorInfoType(type); + } + + private CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) + { + var type = HandleToObject(cls); + + switch (type.Category) + { + case TypeFlags.Byte: + case TypeFlags.SByte: + case TypeFlags.UInt16: + case TypeFlags.Int16: + case TypeFlags.UInt32: + case TypeFlags.Int32: + case TypeFlags.UInt64: + case TypeFlags.Int64: + case TypeFlags.Single: + case TypeFlags.Double: + return asCorInfoType(type); + + default: + return CorInfoType.CORINFO_TYPE_UNDEF; + } + } + + private bool canCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) + { throw new NotImplementedException("canCast"); } + private bool areTypesEquivalent(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { throw new NotImplementedException("areTypesEquivalent"); } + + private TypeCompareState compareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) + { + TypeDesc fromType = HandleToObject(fromClass); + TypeDesc toType = HandleToObject(toClass); + + TypeCompareState result = TypeCompareState.May; + + if (toType.IsNullable) + { + // If casting to Nullable, don't try to optimize + result = TypeCompareState.May; + } + else if (!fromType.IsCanonicalSubtype(CanonicalFormKind.Any) && !toType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + // If the types are not shared, we can check directly. + if (fromType.CanCastTo(toType)) + result = TypeCompareState.Must; + else + result = TypeCompareState.MustNot; + } + else if (fromType.IsCanonicalSubtype(CanonicalFormKind.Any) && !toType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + // Casting from a shared type to an unshared type. + // Only handle casts to interface types for now + if (toType.IsInterface) + { + // Do a preliminary check. + bool canCast = fromType.CanCastTo(toType); + + // Pass back positive results unfiltered. The unknown type + // parameters in fromClass did not come into play. + if (canCast) + { + result = TypeCompareState.Must; + } + // For negative results, the unknown type parameter in + // fromClass might match some instantiated interface, + // either directly or via variance. + // + // However, CanCastTo will report failure in such cases since + // __Canon won't match the instantiated type on the + // interface (which can't be __Canon since we screened out + // canonical subtypes for toClass above). So only report + // failure if the interface is not instantiated. + else if (!toType.HasInstantiation) + { + result = TypeCompareState.MustNot; + } + } + } + +#if READYTORUN + // In R2R it is a breaking change for a previously positive + // cast to become negative, but not for a previously negative + // cast to become positive. So in R2R a negative result is + // always reported back as May. + if (result == TypeCompareState.MustNot) + { + result = TypeCompareState.May; + } +#endif + + return result; + } + + private TypeCompareState compareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + TypeCompareState result = TypeCompareState.May; + + TypeDesc type1 = HandleToObject(cls1); + TypeDesc type2 = HandleToObject(cls2); + + // If neither type is a canonical subtype, type handle comparison suffices + if (!type1.IsCanonicalSubtype(CanonicalFormKind.Any) && !type2.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + result = (type1 == type2 ? TypeCompareState.Must : TypeCompareState.MustNot); + } + // If either or both types are canonical subtypes, we can sometimes prove inequality. + else + { + // If either is a value type then the types cannot + // be equal unless the type defs are the same. + if (type1.IsValueType || type2.IsValueType) + { + if (!type1.IsCanonicalDefinitionType(CanonicalFormKind.Universal) && !type2.IsCanonicalDefinitionType(CanonicalFormKind.Universal)) + { + if (!type1.HasSameTypeDefinition(type2)) + { + result = TypeCompareState.MustNot; + } + } + } + // If we have two ref types that are not __Canon, then the + // types cannot be equal unless the type defs are the same. + else + { + if (!type1.IsCanonicalDefinitionType(CanonicalFormKind.Any) && !type2.IsCanonicalDefinitionType(CanonicalFormKind.Any)) + { + if (!type1.HasSameTypeDefinition(type2)) + { + result = TypeCompareState.MustNot; + } + } + } + } + + return result; + } + + private CORINFO_CLASS_STRUCT_* mergeClasses(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + TypeDesc type1 = HandleToObject(cls1); + TypeDesc type2 = HandleToObject(cls2); + + TypeDesc merged = TypeExtensions.MergeTypesToCommonParent(type1, type2); + +#if DEBUG + // Make sure the merge is reflexive in the cases we "support". + TypeDesc reflexive = TypeExtensions.MergeTypesToCommonParent(type2, type1); + + // If both sides are classes than either they have a common non-interface parent (in which case it is + // reflexive) + // OR they share a common interface, and it can be order dependent (if they share multiple interfaces + // in common) + if (!type1.IsInterface && !type2.IsInterface) + { + if (merged.IsInterface) + { + Debug.Assert(reflexive.IsInterface); + } + else + { + Debug.Assert(merged == reflexive); + } + } + // Both results must either be interfaces or classes. They cannot be mixed. + Debug.Assert(merged.IsInterface == reflexive.IsInterface); + + // If the result of the merge was a class, then the result of the reflexive merge was the same class. + if (!merged.IsInterface) + { + Debug.Assert(merged == reflexive); + } + + // If both sides are arrays, then the result is either an array or g_pArrayClass. The above is + // actually true about the element type for references types, but I think that that is a little + // excessive for sanity. + if (type1.IsArray && type2.IsArray) + { + TypeDesc arrayClass = _compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Array); + Debug.Assert((merged.IsArray && reflexive.IsArray) + || ((merged == arrayClass) && (reflexive == arrayClass))); + } + + // The results must always be assignable + Debug.Assert(type1.CanCastTo(merged) && type2.CanCastTo(merged) && type1.CanCastTo(reflexive) + && type2.CanCastTo(reflexive)); +#endif + + return ObjectToHandle(merged); + } + + private bool isMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + TypeDesc type1 = HandleToObject(cls1); + TypeDesc type2 = HandleToObject(cls2); + + // If we have a mixture of shared and unshared types, + // consider the unshared type as more specific. + bool isType1CanonSubtype = type1.IsCanonicalSubtype(CanonicalFormKind.Any); + bool isType2CanonSubtype = type2.IsCanonicalSubtype(CanonicalFormKind.Any); + if (isType1CanonSubtype != isType2CanonSubtype) + { + // Only one of type1 and type2 is shared. + // type2 is more specific if type1 is the shared type. + return isType1CanonSubtype; + } + + // Otherwise both types are either shared or not shared. + // Look for a common parent type. + TypeDesc merged = TypeExtensions.MergeTypesToCommonParent(type1, type2); + + // If the common parent is type1, then type2 is more specific. + return merged == type1; + } + + private CORINFO_CLASS_STRUCT_* getParentType(CORINFO_CLASS_STRUCT_* cls) + { throw new NotImplementedException("getParentType"); } + + private CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) + { + CorInfoType result = CorInfoType.CORINFO_TYPE_UNDEF; + + var td = HandleToObject(clsHnd); + if (td.IsArray || td.IsByRef) + { + TypeDesc returnType = ((ParameterizedType)td).ParameterType; + result = asCorInfoType(returnType, clsRet); + } + else + clsRet = null; + + return result; + } + + private bool satisfiesClassConstraints(CORINFO_CLASS_STRUCT_* cls) + { throw new NotImplementedException("satisfiesClassConstraints"); } + + private bool isSDArray(CORINFO_CLASS_STRUCT_* cls) + { + var td = HandleToObject(cls); + return td.IsSzArray; + } + + private uint getArrayRank(CORINFO_CLASS_STRUCT_* cls) + { + var td = HandleToObject(cls) as ArrayType; + Debug.Assert(td != null); + return (uint) td.Rank; + } + + private void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size) + { + var fd = HandleToObject(field); + + // Check for invalid arguments passed to InitializeArray intrinsic + if (!fd.HasRva || + size > fd.FieldType.GetElementSize().AsInt) + { + return null; + } + + return (void*)ObjectToHandle(_compilation.GetFieldRvaData(fd)); + } + + private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) + { + // TODO: Access check + return CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED; + } + + private byte* getFieldName(CORINFO_FIELD_STRUCT_* ftn, byte** moduleName) + { + var field = HandleToObject(ftn); + if (moduleName != null) + { + MetadataType typeDef = field.OwningType.GetTypeDefinition() as MetadataType; + if (typeDef != null) + *moduleName = (byte*)GetPin(StringToUTF8(typeDef.GetFullName())); + else + *moduleName = (byte*)GetPin(StringToUTF8("unknown")); + } + + return (byte*)GetPin(StringToUTF8(field.Name)); + } + + private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) + { + var fieldDesc = HandleToObject(field); + return ObjectToHandle(fieldDesc.OwningType); + } + + private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent) + { + FieldDesc fieldDesc = HandleToObject(field); + TypeDesc fieldType = fieldDesc.FieldType; + + CorInfoType type; + if (structType != null) + { + type = asCorInfoType(fieldType, structType); + } + else + { + type = asCorInfoType(fieldType); + } + + Debug.Assert(!fieldDesc.OwningType.IsByReferenceOfT || + fieldDesc.OwningType.GetKnownField("_value").FieldType.Category == TypeFlags.IntPtr); + if (type == CorInfoType.CORINFO_TYPE_NATIVEINT && fieldDesc.OwningType.IsByReferenceOfT) + { + Debug.Assert(structType == null || *structType == null); + Debug.Assert(fieldDesc.Offset.AsInt == 0); + type = CorInfoType.CORINFO_TYPE_BYREF; + } + + return type; + } + + private uint getFieldOffset(CORINFO_FIELD_STRUCT_* field) + { + var fieldDesc = HandleToObject(field); + + Debug.Assert(fieldDesc.Offset != FieldAndOffset.InvalidOffset); + + return (uint)fieldDesc.Offset.AsInt; + } + + private bool isWriteBarrierHelperRequired(CORINFO_FIELD_STRUCT_* field) + { throw new NotImplementedException("isWriteBarrierHelperRequired"); } + + private CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc field) + { + Debug.Assert(field.IsIntrinsic); + + var owningType = field.OwningType; + if ((owningType.IsWellKnownType(WellKnownType.IntPtr) || + owningType.IsWellKnownType(WellKnownType.UIntPtr)) && + field.Name == "Zero") + { + return CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INTRINSIC_ZERO; + } + else if (owningType.IsString && field.Name == "Empty") + { + return CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INTRINSIC_EMPTY_STRING; + } + else if (owningType.Name == "BitConverter" && owningType.Namespace == "System" && + field.Name == "IsLittleEndian") + { + return CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN; + } + + return (CORINFO_FIELD_ACCESSOR)(-1); + } + + private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + { +#if DEBUG + // In debug, write some bogus data to the struct to ensure we have filled everything + // properly. + MemoryHelper.FillMemory((byte*)pResult, 0xcc, Marshal.SizeOf()); +#endif + + Debug.Assert(((int)flags & ((int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET | + (int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_SET | + (int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_ADDRESS | + (int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_INIT_ARRAY)) != 0); + + var field = HandleToObject(pResolvedToken.hField); +#if READYTORUN + MethodDesc callerMethod = HandleToObject(callerHandle); + + if (field.Offset.IsIndeterminate) + throw new RequiresRuntimeJitException(field); +#endif + + CORINFO_FIELD_ACCESSOR fieldAccessor; + CORINFO_FIELD_FLAGS fieldFlags = (CORINFO_FIELD_FLAGS)0; + uint fieldOffset = (field.IsStatic && field.HasRva ? 0xBAADF00D : (uint)field.Offset.AsInt); + + if (field.IsStatic) + { + fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC; + +#if READYTORUN + if (field.FieldType.IsValueType && field.HasGCStaticBase && !field.HasRva) + { + // statics of struct types are stored as implicitly boxed in CoreCLR i.e. + // we need to modify field access flags appropriately + fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC_IN_HEAP; + } +#endif + + if (field.HasRva) + { + fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_UNMANAGED; + + // TODO: Handle the case when the RVA is in the TLS range + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_RVA_ADDRESS; + + // We are not going through a helper. The constructor has to be triggered explicitly. +#if READYTORUN + if (!IsClassPreInited(field.OwningType)) +#else + if (_compilation.HasLazyStaticConstructor(field.OwningType)) +#endif + { + fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_INITCLASS; + } + } + else if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + // The JIT wants to know how to access a static field on a generic type. We need a runtime lookup. +#if READYTORUN + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER; + if (field.IsThreadStatic) + { + pResult->helper = (field.HasGCStaticBase ? + CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE: + CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE); + } + else + { + pResult->helper = (field.HasGCStaticBase ? + CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: + CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE); + } +#else + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_READYTORUN_HELPER; + pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE; + + // Don't try to compute the runtime lookup if we're inlining. The JIT is going to abort the inlining + // attempt anyway. + MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); + if (contextMethod == MethodBeingCompiled) + { + FieldDesc runtimeDeterminedField = (FieldDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken); + + ReadyToRunHelperId helperId; + + // Find out what kind of base do we need to look up. + if (field.IsThreadStatic) + { + helperId = ReadyToRunHelperId.GetThreadStaticBase; + } + else if (field.HasGCStaticBase) + { + helperId = ReadyToRunHelperId.GetGCStaticBase; + } + else + { + helperId = ReadyToRunHelperId.GetNonGCStaticBase; + } + + // What generic context do we look up the base from. + ISymbolNode helper; + if (contextMethod.AcquiresInstMethodTableFromThis() || contextMethod.RequiresInstMethodTableArg()) + { + helper = _compilation.NodeFactory.ReadyToRunHelperFromTypeLookup( + helperId, runtimeDeterminedField.OwningType, contextMethod.OwningType); + } + else + { + Debug.Assert(contextMethod.RequiresInstMethodDescArg()); + helper = _compilation.NodeFactory.ReadyToRunHelperFromDictionaryLookup( + helperId, runtimeDeterminedField.OwningType, contextMethod); + } + + pResult->fieldLookup = CreateConstLookupToSymbol(helper); + } +#endif // READYTORUN + } + else + { + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; + pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE; + + ReadyToRunHelperId helperId = ReadyToRunHelperId.Invalid; + CORINFO_FIELD_ACCESSOR intrinsicAccessor; + if (field.IsIntrinsic && + (flags & CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET) != 0 && + (intrinsicAccessor = getFieldIntrinsic(field)) != (CORINFO_FIELD_ACCESSOR)(-1)) + { + fieldAccessor = intrinsicAccessor; + } + else if (field.IsThreadStatic) + { +#if READYTORUN + if (field.HasGCStaticBase) + { + helperId = ReadyToRunHelperId.GetThreadStaticBase; + } + else + { + helperId = ReadyToRunHelperId.GetThreadNonGcStaticBase; + } +#else + helperId = ReadyToRunHelperId.GetThreadStaticBase; +#endif + } + else if (field.HasGCStaticBase) + { + helperId = ReadyToRunHelperId.GetGCStaticBase; + } + else + { + helperId = ReadyToRunHelperId.GetNonGCStaticBase; + } + +#if READYTORUN + if (!_compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(field.OwningType) && + fieldAccessor == CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER) + { + PreventRecursiveFieldInlinesOutsideVersionBubble(field, callerMethod); + + // Static fields outside of the version bubble need to be accessed using the ENCODE_FIELD_ADDRESS + // helper in accordance with ZapInfo::getFieldInfo in CoreCLR. + pResult->fieldLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.FieldAddress(field, GetSignatureContext())); + + pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE; + + fieldFlags &= ~CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC_IN_HEAP; // The dynamic helper takes care of the unboxing + fieldOffset = 0; + } + else +#endif + + if (helperId != ReadyToRunHelperId.Invalid) + { + pResult->fieldLookup = CreateConstLookupToSymbol( +#if READYTORUN + _compilation.SymbolNodeFactory.CreateReadyToRunHelper(helperId, field.OwningType, GetSignatureContext()) +#else + _compilation.NodeFactory.ReadyToRunHelper(helperId, field.OwningType) +#endif + ); + } + } + } + else + { + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INSTANCE; + } + + if (field.IsInitOnly) + fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_FINAL; + + pResult->fieldAccessor = fieldAccessor; + pResult->fieldFlags = fieldFlags; + pResult->fieldType = getFieldType(pResolvedToken.hField, &pResult->structType, pResolvedToken.hClass); + pResult->accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED; + pResult->offset = fieldOffset; + +#if READYTORUN + EncodeFieldBaseOffset(field, pResult, callerMethod); +#endif + + // TODO: We need to implement access checks for fields and methods. See JitInterface.cpp in mrtjit + // and STS::AccessCheck::CanAccess. + } + + private bool isFieldStatic(CORINFO_FIELD_STRUCT_* fldHnd) + { + return HandleToObject(fldHnd).IsStatic; + } + + private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) + { + // TODO: Debugging + cILOffsets = 0; + pILOffsets = null; + *implicitBoundaries = BoundaryTypes.DEFAULT_BOUNDARIES; + } + + private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, ref bool extendOthers) + { + // TODO: Debugging + + cVars = 0; + *vars = null; + + // Just tell the JIT to extend everything. + extendOthers = true; + } + + private void* allocateArray(uint cBytes) + { + return (void*)Marshal.AllocCoTaskMem((int)cBytes); + } + + private void freeArray(void* array) + { + Marshal.FreeCoTaskMem((IntPtr)array); + } + + private CORINFO_ARG_LIST_STRUCT_* getArgNext(CORINFO_ARG_LIST_STRUCT_* args) + { + return (CORINFO_ARG_LIST_STRUCT_*)((int)args + 1); + } + + private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet) + { + int index = (int)args; + Object sigObj = HandleToObject((IntPtr)sig->pSig); + + MethodSignature methodSig = sigObj as MethodSignature; + + if (methodSig != null) + { + TypeDesc type = methodSig[index]; + + CorInfoType corInfoType = asCorInfoType(type, vcTypeRet); + return (CorInfoTypeWithMod)corInfoType; + } + else + { + LocalVariableDefinition[] locals = (LocalVariableDefinition[])sigObj; + TypeDesc type = locals[index].Type; + + CorInfoType corInfoType = asCorInfoType(type, vcTypeRet); + + return (CorInfoTypeWithMod)corInfoType | (locals[index].IsPinned ? CorInfoTypeWithMod.CORINFO_TYPE_MOD_PINNED : 0); + } + } + + private CORINFO_CLASS_STRUCT_* getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) + { + int index = (int)args; + Object sigObj = HandleToObject((IntPtr)sig->pSig); + + MethodSignature methodSig = sigObj as MethodSignature; + if (methodSig != null) + { + TypeDesc type = methodSig[index]; + return ObjectToHandle(type); + } + else + { + LocalVariableDefinition[] locals = (LocalVariableDefinition[])sigObj; + TypeDesc type = locals[index].Type; + return ObjectToHandle(type); + } + } + + private CorInfoType getHFAType(CORINFO_CLASS_STRUCT_* hClass) + { + var type = (DefType)HandleToObject(hClass); + return type.IsHfa ? asCorInfoType(type.HfaElementType) : CorInfoType.CORINFO_TYPE_UNDEF; + } + + private HRESULT GetErrorHRESULT(_EXCEPTION_POINTERS* pExceptionPointers) + { throw new NotImplementedException("GetErrorHRESULT"); } + private uint GetErrorMessage(short* buffer, uint bufferLength) + { throw new NotImplementedException("GetErrorMessage"); } + + private int FilterException(_EXCEPTION_POINTERS* pExceptionPointers) + { + // This method is completely handled by the C++ wrapper to the JIT-EE interface, + // and should never reach the managed implementation. + Debug.Fail("CorInfoImpl.FilterException should not be called"); + throw new NotSupportedException("FilterException"); + } + + private void HandleException(_EXCEPTION_POINTERS* pExceptionPointers) + { + // This method is completely handled by the C++ wrapper to the JIT-EE interface, + // and should never reach the managed implementation. + Debug.Fail("CorInfoImpl.HandleException should not be called"); + throw new NotSupportedException("HandleException"); + } + + private bool runWithErrorTrap(void* function, void* parameter) + { + // This method is completely handled by the C++ wrapper to the JIT-EE interface, + // and should never reach the managed implementation. + Debug.Fail("CorInfoImpl.runWithErrorTrap should not be called"); + throw new NotSupportedException("runWithErrorTrap"); + } + + private void ThrowExceptionForJitResult(HRESULT result) + { throw new NotImplementedException("ThrowExceptionForJitResult"); } + private void ThrowExceptionForHelper(ref CORINFO_HELPER_DESC throwHelper) + { throw new NotImplementedException("ThrowExceptionForHelper"); } + + private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) + { + pEEInfoOut = new CORINFO_EE_INFO(); + +#if DEBUG + // In debug, write some bogus data to the struct to ensure we have filled everything + // properly. + fixed (CORINFO_EE_INFO* tmp = &pEEInfoOut) + MemoryHelper.FillMemory((byte*)tmp, 0xcc, Marshal.SizeOf()); +#endif + + int pointerSize = this.PointerSize; + + pEEInfoOut.inlinedCallFrameInfo.size = (uint)SizeOfPInvokeTransitionFrame; + + pEEInfoOut.offsetOfDelegateInstance = (uint)pointerSize; // Delegate::m_firstParameter + pEEInfoOut.offsetOfDelegateFirstTarget = OffsetOfDelegateFirstTarget; + + pEEInfoOut.offsetOfObjArrayData = (uint)(2 * pointerSize); + + pEEInfoOut.sizeOfReversePInvokeFrame = (uint)(2 * pointerSize); + + pEEInfoOut.osPageSize = new UIntPtr(0x1000); + + pEEInfoOut.maxUncheckedOffsetForNullObject = (_compilation.NodeFactory.Target.IsWindows) ? + new UIntPtr(32 * 1024 - 1) : new UIntPtr((uint)pEEInfoOut.osPageSize / 2 - 1); + + pEEInfoOut.targetAbi = TargetABI; + } + + private string getJitTimeLogFilename() + { + return null; + } + + private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) + { + MethodDesc method = HandleToObject(hMethod); +#if READYTORUN + if (method is UnboxingMethodDesc unboxingMethodDesc) + { + method = unboxingMethodDesc.Target; + } +#endif + MethodDesc methodDefinition = method.GetTypicalMethodDefinition(); + + // Need to cast down to EcmaMethod. Do not use this as a precedent that casting to Ecma* + // within the JitInterface is fine. We might want to consider moving this to Compilation. + TypeSystem.Ecma.EcmaMethod ecmaMethodDefinition = methodDefinition as TypeSystem.Ecma.EcmaMethod; + if (ecmaMethodDefinition != null) + { + return (mdToken)System.Reflection.Metadata.Ecma335.MetadataTokens.GetToken(ecmaMethodDefinition.Handle); + } + + return 0; + } + + private static byte[] StringToUTF8(string s) + { + int byteCount = Encoding.UTF8.GetByteCount(s); + byte[] bytes = new byte[byteCount + 1]; + Encoding.UTF8.GetBytes(s, 0, s.Length, bytes, 0); + return bytes; + } + + private byte* getMethodName(CORINFO_METHOD_STRUCT_* ftn, byte** moduleName) + { + MethodDesc method = HandleToObject(ftn); + + if (moduleName != null) + { + MetadataType typeDef = method.OwningType.GetTypeDefinition() as MetadataType; + if (typeDef != null) + *moduleName = (byte*)GetPin(StringToUTF8(typeDef.GetFullName())); + else + *moduleName = (byte*)GetPin(StringToUTF8("unknown")); + } + + return (byte*)GetPin(StringToUTF8(method.Name)); + } + + private String getMethodNameFromMetadataImpl(MethodDesc method, out string className, out string namespaceName, out string enclosingClassName) + { + string result = null; + className = null; + namespaceName = null; + enclosingClassName = null; + + result = method.Name; + + MetadataType owningType = method.OwningType as MetadataType; + if (owningType != null) + { + className = owningType.Name; + namespaceName = owningType.Namespace; + + // Query enclosingClassName when the method is in a nested class + // and get the namespace of enclosing classes (nested class's namespace is empty) + var containingType = owningType.ContainingType; + if (containingType != null) + { + enclosingClassName = containingType.Name; + namespaceName = containingType.Namespace; + } + } + + return result; + } + + private byte* getMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassName) + { + MethodDesc method = HandleToObject(ftn); + + string result; + string classResult; + string namespaceResult; + string enclosingResult; + + result = getMethodNameFromMetadataImpl(method, out classResult, out namespaceResult, out enclosingResult); + + if (className != null) + *className = classResult != null ? (byte*)GetPin(StringToUTF8(classResult)) : null; + if (namespaceName != null) + *namespaceName = namespaceResult != null ? (byte*)GetPin(StringToUTF8(namespaceResult)) : null; + if (enclosingClassName != null) + *enclosingClassName = enclosingResult != null ? (byte*)GetPin(StringToUTF8(enclosingResult)) : null; + + return result != null ? (byte*)GetPin(StringToUTF8(result)) : null; + } + + private uint getMethodHash(CORINFO_METHOD_STRUCT_* ftn) + { + return (uint)HandleToObject(ftn).GetHashCode(); + } + + private byte* findNameOfToken(CORINFO_MODULE_STRUCT_* moduleHandle, mdToken token, byte* szFQName, UIntPtr FQNameCapacity) + { throw new NotImplementedException("findNameOfToken"); } + + SystemVStructClassificator _systemVStructClassificator = new SystemVStructClassificator(); + + private bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) + { + TypeDesc typeDesc = HandleToObject(structHnd); + + return _systemVStructClassificator.getSystemVAmd64PassStructInRegisterDescriptor(typeDesc, structPassInRegDescPtr); + } + + private uint getThreadTLSIndex(ref void* ppIndirection) + { throw new NotImplementedException("getThreadTLSIndex"); } + private void* getInlinedCallFrameVptr(ref void* ppIndirection) + { throw new NotImplementedException("getInlinedCallFrameVptr"); } + private int* getAddrOfCaptureThreadGlobal(ref void* ppIndirection) + { throw new NotImplementedException("getAddrOfCaptureThreadGlobal"); } + + private Dictionary _helperCache = new Dictionary(); + private void* getHelperFtn(CorInfoHelpFunc ftnNum, ref void* ppIndirection) + { + ISymbolNode entryPoint; + if (!_helperCache.TryGetValue(ftnNum, out entryPoint)) + { + entryPoint = GetHelperFtnUncached(ftnNum); + _helperCache.Add(ftnNum, entryPoint); + } + if (entryPoint.RepresentsIndirectionCell) + { + ppIndirection = (void*)ObjectToHandle(entryPoint); + return null; + } + else + { + ppIndirection = null; + return (void*)ObjectToHandle(entryPoint); + } + } + + private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult) + { throw new NotImplementedException("getFunctionFixedEntryPoint"); } + + private CorInfoHelpFunc getLazyStringLiteralHelper(CORINFO_MODULE_STRUCT_* handle) + { + // TODO: Lazy string literal helper + return CorInfoHelpFunc.CORINFO_HELP_UNDEF; + } + + private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) + { throw new NotImplementedException("embedModuleHandle"); } + private CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) + { throw new NotImplementedException("embedClassHandle"); } + + private CORINFO_FIELD_STRUCT_* embedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) + { throw new NotImplementedException("embedFieldHandle"); } + + private CORINFO_RUNTIME_LOOKUP_KIND GetGenericRuntimeLookupKind(MethodDesc method) + { + if (method.RequiresInstMethodDescArg()) + return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM; + else if (method.RequiresInstMethodTableArg()) + return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM; + else + { + Debug.Assert(method.AcquiresInstMethodTableFromThis()); + return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ; + } + } + + private void getLocationOfThisType(out CORINFO_LOOKUP_KIND result, CORINFO_METHOD_STRUCT_* context) + { + result = new CORINFO_LOOKUP_KIND(); + + MethodDesc method = HandleToObject(context); + + if (method.IsSharedByGenericInstantiations) + { + result.needsRuntimeLookup = true; + result.runtimeLookupKind = GetGenericRuntimeLookupKind(method); + } + else + { + result.needsRuntimeLookup = false; + result.runtimeLookupKind = CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ; + } + } + + private void* getPInvokeUnmanagedTarget(CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection) + { throw new NotImplementedException("getPInvokeUnmanagedTarget"); } + private void* getAddressOfPInvokeFixup(CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection) + { throw new NotImplementedException("getAddressOfPInvokeFixup"); } + private void* GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, ref void* ppIndirection) + { throw new NotImplementedException("GetCookieForPInvokeCalliSig"); } + private CORINFO_JUST_MY_CODE_HANDLE_* getJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) + { + ppIndirection = null; + return null; + } + private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) + { throw new NotImplementedException("GetProfilingHandle"); } + + /// + /// Create a CORINFO_CONST_LOOKUP to a symbol and put the address into the addr field + /// + private CORINFO_CONST_LOOKUP CreateConstLookupToSymbol(ISymbolNode symbol) + { + CORINFO_CONST_LOOKUP constLookup = new CORINFO_CONST_LOOKUP(); + constLookup.addr = (void*)ObjectToHandle(symbol); + constLookup.accessType = symbol.RepresentsIndirectionCell ? InfoAccessType.IAT_PVALUE : InfoAccessType.IAT_VALUE; + return constLookup; + } + + private bool canAccessFamily(CORINFO_METHOD_STRUCT_* hCaller, CORINFO_CLASS_STRUCT_* hInstanceType) + { throw new NotImplementedException("canAccessFamily"); } + private bool isRIDClassDomainID(CORINFO_CLASS_STRUCT_* cls) + { throw new NotImplementedException("isRIDClassDomainID"); } + private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection) + { throw new NotImplementedException("getClassDomainID"); } + + private void* getFieldAddress(CORINFO_FIELD_STRUCT_* field, void** ppIndirection) + { + FieldDesc fieldDesc = HandleToObject(field); + Debug.Assert(fieldDesc.HasRva); + ISymbolNode node = _compilation.GetFieldRvaData(fieldDesc); + void *handle = (void *)ObjectToHandle(node); + if (node.RepresentsIndirectionCell) + { + *ppIndirection = handle; + return null; + } + else + { + if (ppIndirection != null) + *ppIndirection = null; + return handle; + } + } + + private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + if (pIsSpeculative != null) + *pIsSpeculative = 1; + + return null; + } + + private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, ref void* ppIndirection) + { throw new NotImplementedException("getVarArgsHandle"); } + private bool canGetVarArgsHandle(CORINFO_SIG_INFO* pSig) + { throw new NotImplementedException("canGetVarArgsHandle"); } + + private InfoAccessType emptyStringLiteral(ref void* ppValue) + { + return constructStringLiteral(_methodScope, (mdToken)CorTokenType.mdtString, ref ppValue); + } + + private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) + { throw new NotImplementedException("getFieldThreadLocalStoreID"); } + private void setOverride(IntPtr pOverride, CORINFO_METHOD_STRUCT_* currentMethod) + { throw new NotImplementedException("setOverride"); } + private void addActiveDependency(CORINFO_MODULE_STRUCT_* moduleFrom, CORINFO_MODULE_STRUCT_* moduleTo) + { throw new NotImplementedException("addActiveDependency"); } + private CORINFO_METHOD_STRUCT_* GetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) + { throw new NotImplementedException("GetDelegateCtor"); } + private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) + { throw new NotImplementedException("MethodCompileComplete"); } + + private void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) + { + // Slow tailcalls are not supported yet + // https://github.com/dotnet/corert/issues/1683 + return null; + } + + private void* getMemoryManager() + { + // This method is completely handled by the C++ wrapper to the JIT-EE interface, + // and should never reach the managed implementation. + Debug.Fail("CorInfoImpl.getMemoryManager should not be called"); + throw new NotSupportedException("getMemoryManager"); + } + + private byte[] _code; + private byte[] _coldCode; + + private byte[] _roData; + + private BlobNode _roDataBlob; + + private int _numFrameInfos; + private int _usedFrameInfos; + private FrameInfo[] _frameInfos; + + private byte[] _gcInfo; + private CORINFO_EH_CLAUSE[] _ehClauses; + + private void allocMem(uint hotCodeSize, uint coldCodeSize, uint roDataSize, uint xcptnsCount, CorJitAllocMemFlag flag, ref void* hotCodeBlock, ref void* coldCodeBlock, ref void* roDataBlock) + { + hotCodeBlock = (void*)GetPin(_code = new byte[hotCodeSize]); + + if (coldCodeSize != 0) + coldCodeBlock = (void*)GetPin(_coldCode = new byte[coldCodeSize]); + + if (roDataSize != 0) + { + int alignment = 8; + + if ((flag & CorJitAllocMemFlag.CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN) != 0) + { + alignment = 16; + } + else if (roDataSize < 8) + { + alignment = PointerSize; + } + + _roData = new byte[roDataSize]; + + _roDataBlob = _compilation.NodeFactory.ReadOnlyDataBlob( + "__readonlydata_" + _compilation.NameMangler.GetMangledMethodName(MethodBeingCompiled), + _roData, alignment); + + roDataBlock = (void*)GetPin(_roData); + } + + if (_numFrameInfos > 0) + { + _frameInfos = new FrameInfo[_numFrameInfos]; + } + } + + private void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize) + { + _numFrameInfos++; + } + + private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) + { + Debug.Assert(FrameInfoFlags.Filter == (FrameInfoFlags)CorJitFuncKind.CORJIT_FUNC_FILTER); + Debug.Assert(FrameInfoFlags.Handler == (FrameInfoFlags)CorJitFuncKind.CORJIT_FUNC_HANDLER); + + FrameInfoFlags flags = (FrameInfoFlags)funcKind; + + if (funcKind == CorJitFuncKind.CORJIT_FUNC_ROOT) + { + if (this.MethodBeingCompiled.IsNativeCallable) + flags |= FrameInfoFlags.ReversePInvoke; + } + + byte[] blobData = new byte[unwindSize]; + + for (uint i = 0; i < unwindSize; i++) + { + blobData[i] = pUnwindBlock[i]; + } + + _frameInfos[_usedFrameInfos++] = new FrameInfo(flags, (int)startOffset, (int)endOffset, blobData); + } + + private void* allocGCInfo(UIntPtr size) + { + _gcInfo = new byte[(int)size]; + return (void*)GetPin(_gcInfo); + } + + private void yieldExecution() + { + // Nothing to do + } + + private void setEHcount(uint cEH) + { + _ehClauses = new CORINFO_EH_CLAUSE[cEH]; + } + + private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + _ehClauses[EHnumber] = clause; + } + + private bool logMsg(uint level, byte* fmt, IntPtr args) + { + // Console.WriteLine(Marshal.PtrToStringAnsi((IntPtr)fmt)); + return false; + } + + private int doAssert(byte* szFile, int iLine, byte* szExpr) + { + Log.WriteLine(Marshal.PtrToStringAnsi((IntPtr)szFile) + ":" + iLine); + Log.WriteLine(Marshal.PtrToStringAnsi((IntPtr)szExpr)); + + return 1; + } + + private void reportFatalError(CorJitResult result) + { + // We could add some logging here, but for now it's unnecessary. + // CompileMethod is going to fail with this CorJitResult anyway. + } + + private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) + { + } + + private ArrayBuilder _relocs; + + /// + /// Various type of block. + /// + public enum BlockType : sbyte + { + /// Not a generated block. + Unknown = -1, + /// Represent code. + Code = 0, + /// Represent cold code (i.e. code not called frequently). + ColdCode = 1, + /// Read-only data. + ROData = 2, + /// Instrumented Block Count Data + BBCounts = 3 + } + + private BlockType findKnownBlock(void* location, out int offset) + { + fixed (byte* pCode = _code) + { + if (pCode <= (byte*)location && (byte*)location < pCode + _code.Length) + { + offset = (int)((byte*)location - pCode); + return BlockType.Code; + } + } + + if (_coldCode != null) + { + fixed (byte* pColdCode = _coldCode) + { + if (pColdCode <= (byte*)location && (byte*)location < pColdCode + _coldCode.Length) + { + offset = (int)((byte*)location - pColdCode); + return BlockType.ColdCode; + } + } + } + + if (_roData != null) + { + fixed (byte* pROData = _roData) + { + if (pROData <= (byte*)location && (byte*)location < pROData + _roData.Length) + { + offset = (int)((byte*)location - pROData); + return BlockType.ROData; + } + } + } + + { + BlockType retBlockType = BlockType.Unknown; + offset = 0; + findKnownBBCountBlock(ref retBlockType, location, ref offset); + if (retBlockType == BlockType.BBCounts) + return retBlockType; + } + + offset = 0; + return BlockType.Unknown; + } + + partial void findKnownBBCountBlock(ref BlockType blockType, void* location, ref int offset); + + private void recordRelocation(void* location, void* target, ushort fRelocType, ushort slotNum, int addlDelta) + { + // slotNum is not unused + Debug.Assert(slotNum == 0); + + int relocOffset; + BlockType locationBlock = findKnownBlock(location, out relocOffset); + Debug.Assert(locationBlock != BlockType.Unknown, "BlockType.Unknown not expected"); + + if (locationBlock != BlockType.Code) + { + // TODO: https://github.com/dotnet/corert/issues/3877 + TargetArchitecture targetArchitecture = _compilation.TypeSystemContext.Target.Architecture; + if (targetArchitecture == TargetArchitecture.ARM) + return; + throw new NotImplementedException("Arbitrary relocs"); + } + + int relocDelta; + BlockType targetBlock = findKnownBlock(target, out relocDelta); + + ISymbolNode relocTarget; + switch (targetBlock) + { + case BlockType.Code: + relocTarget = _methodCodeNode; + break; + + case BlockType.ColdCode: + // TODO: Arbitrary relocs + throw new NotImplementedException("ColdCode relocs"); + + case BlockType.ROData: + relocTarget = _roDataBlob; + break; + +#if READYTORUN + case BlockType.BBCounts: + relocTarget = _profileDataNode; + break; +#endif + + default: + // Reloc points to something outside of the generated blocks + var targetObject = HandleToObject((IntPtr)target); + relocTarget = (ISymbolNode)targetObject; + break; + } + + relocDelta += addlDelta; + + // relocDelta is stored as the value + Relocation.WriteValue((RelocType)fRelocType, location, relocDelta); + + if (_relocs.Count == 0) + _relocs.EnsureCapacity(_code.Length / 32 + 1); + _relocs.Add(new Relocation((RelocType)fRelocType, relocOffset, relocTarget)); + } + + private ushort getRelocTypeHint(void* target) + { + switch (_compilation.TypeSystemContext.Target.Architecture) + { + case TargetArchitecture.X64: + return (ushort)ILCompiler.DependencyAnalysis.RelocType.IMAGE_REL_BASED_REL32; + + case TargetArchitecture.ARM: + return (ushort)ILCompiler.DependencyAnalysis.RelocType.IMAGE_REL_BASED_THUMB_BRANCH24; + + default: + return UInt16.MaxValue; + } + } + + private void getModuleNativeEntryPointRange(ref void* pStart, ref void* pEnd) + { throw new NotImplementedException("getModuleNativeEntryPointRange"); } + + private uint getExpectedTargetArchitecture() + { + TargetArchitecture arch = _compilation.TypeSystemContext.Target.Architecture; + + switch (arch) + { + case TargetArchitecture.X86: + return (uint)ImageFileMachine.I386; + case TargetArchitecture.X64: + return (uint)ImageFileMachine.AMD64; + case TargetArchitecture.ARM: + return (uint)ImageFileMachine.ARM; + case TargetArchitecture.ARM64: + return (uint)ImageFileMachine.ARM; + default: + throw new NotImplementedException("Expected target architecture is not supported"); + } + } + + private bool isMethodDefinedInCoreLib() + { + TypeDesc owningType = MethodBeingCompiled.OwningType; + MetadataType owningMetadataType = owningType as MetadataType; + if (owningMetadataType == null) + { + return false; + } + return owningMetadataType.Module == _compilation.TypeSystemContext.SystemModule; + } + + private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) + { + // Read the user-defined configuration options. + foreach (var flag in _jitConfig.Flags) + flags.Set(flag); + + // Set the rest of the flags that don't make sense to expose publically. + flags.Set(CorJitFlag.CORJIT_FLAG_SKIP_VERIFICATION); + flags.Set(CorJitFlag.CORJIT_FLAG_READYTORUN); + flags.Set(CorJitFlag.CORJIT_FLAG_RELOC); + flags.Set(CorJitFlag.CORJIT_FLAG_PREJIT); + flags.Set(CorJitFlag.CORJIT_FLAG_USE_PINVOKE_HELPERS); + + if ((_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.X86 + || _compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.X64) +#if READYTORUN + && isMethodDefinedInCoreLib() +#endif + ) + { + // This list needs to match the list of intrinsics we can generate detection code for + // in HardwareIntrinsicHelpers.EmitIsSupportedIL. + flags.Set(CorJitFlag.CORJIT_FLAG_USE_AES); + flags.Set(CorJitFlag.CORJIT_FLAG_USE_PCLMULQDQ); + flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSE3); + flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSSE3); + flags.Set(CorJitFlag.CORJIT_FLAG_USE_LZCNT); + } + + if (this.MethodBeingCompiled.IsNativeCallable) + flags.Set(CorJitFlag.CORJIT_FLAG_REVERSE_PINVOKE); + + if (this.MethodBeingCompiled.IsPInvoke) + { + flags.Set(CorJitFlag.CORJIT_FLAG_IL_STUB); + } + + if (this.MethodBeingCompiled.IsNoOptimization) + flags.Set(CorJitFlag.CORJIT_FLAG_MIN_OPT); + + return (uint)sizeof(CORJIT_FLAGS); + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.VarInfo.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.VarInfo.cs new file mode 100644 index 00000000000..671b9dd408b --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.VarInfo.cs @@ -0,0 +1,183 @@ +// 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 System.Runtime.InteropServices; + +// +// The types in this file are referenced directly from ILCompiler.Compiler +// so cannot be easily factored out into ILCompiler.RyuJit until we build +// some sort of abstraction. +// + +namespace Internal.JitInterface +{ + public enum VarLocType : uint + { + VLT_REG, // variable is in a register + VLT_REG_BYREF, // address of the variable is in a register + VLT_REG_FP, // variable is in an fp register + VLT_STK, // variable is on the stack (memory addressed relative to the frame-pointer) + VLT_STK_BYREF, // address of the variable is on the stack (memory addressed relative to the frame-pointer) + VLT_REG_REG, // variable lives in two registers + VLT_REG_STK, // variable lives partly in a register and partly on the stack + VLT_STK_REG, // reverse of VLT_REG_STK + VLT_STK2, // variable lives in two slots on the stack + VLT_FPSTK, // variable lives on the floating-point stack + VLT_FIXED_VA, // variable is a fixed argument in a varargs function (relative to VARARGS_HANDLE) + + VLT_COUNT, + VLT_INVALID + }; + + public struct NativeVarInfo + { + public uint startOffset; + public uint endOffset; + public uint varNumber; + public VarLoc varLoc; + }; + + // The following 16 bytes come from coreclr types. See comment below. + [StructLayout(LayoutKind.Sequential)] + public struct VarLoc + { + public IntPtr A; // vlType + padding + public int B; + public int C; + public int D; + + public VarLocType LocationType => (VarLocType)(A.ToInt64() & 0xFFFFFFFF); + + /* + Changes to the following types may require revisiting the above layout. + + In coreclr\src\inc\cordebuginfo.h + + enum VarLocType + { + VLT_REG, // variable is in a register + VLT_REG_BYREF, // address of the variable is in a register + VLT_REG_FP, // variable is in an fp register + VLT_STK, // variable is on the stack (memory addressed relative to the frame-pointer) + VLT_STK_BYREF, // address of the variable is on the stack (memory addressed relative to the frame-pointer) + VLT_REG_REG, // variable lives in two registers + VLT_REG_STK, // variable lives partly in a register and partly on the stack + VLT_STK_REG, // reverse of VLT_REG_STK + VLT_STK2, // variable lives in two slots on the stack + VLT_FPSTK, // variable lives on the floating-point stack + VLT_FIXED_VA, // variable is a fixed argument in a varargs function (relative to VARARGS_HANDLE) + + VLT_COUNT, + VLT_INVALID, + #ifdef MDIL + VLT_MDIL_SYMBOLIC = 0x20 + #endif + + }; + + struct VarLoc + { + VarLocType vlType; + + union + { + // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc) + // eg. EAX + // VLT_REG_BYREF -- the specified register contains the address of the variable + // eg. [EAX] + + struct + { + RegNum vlrReg; + } vlReg; + + // VLT_STK -- Any 32 bit value which is on the stack + // eg. [ESP+0x20], or [EBP-0x28] + // VLT_STK_BYREF -- the specified stack location contains the address of the variable + // eg. mov EAX, [ESP+0x20]; [EAX] + + struct + { + RegNum vlsBaseReg; + signed vlsOffset; + } vlStk; + + // VLT_REG_REG -- TYP_LONG with both DWords enregistred + // eg. RBM_EAXEDX + + struct + { + RegNum vlrrReg1; + RegNum vlrrReg2; + } vlRegReg; + + // VLT_REG_STK -- Partly enregistered TYP_LONG + // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] } + + struct + { + RegNum vlrsReg; + struct + { + RegNum vlrssBaseReg; + signed vlrssOffset; + } vlrsStk; + } vlRegStk; + + // VLT_STK_REG -- Partly enregistered TYP_LONG + // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX } + + struct + { + struct + { + RegNum vlsrsBaseReg; + signed vlsrsOffset; + } vlsrStk; + RegNum vlsrReg; + } vlStkReg; + + // VLT_STK2 -- Any 64 bit value which is on the stack, + // in 2 successsive DWords. + // eg 2 DWords at [ESP+0x10] + + struct + { + RegNum vls2BaseReg; + signed vls2Offset; + } vlStk2; + + // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack) + // eg. ST(3). Actually it is ST("FPstkHeigth - vpFpStk") + + struct + { + unsigned vlfReg; + } vlFPstk; + + // VLT_FIXED_VA -- fixed argument of a varargs function. + // The argument location depends on the size of the variable + // arguments (...). Inspecting the VARARGS_HANDLE indicates the + // location of the first arg. This argument can then be accessed + // relative to the position of the first arg + + struct + { + unsigned vlfvOffset; + } vlFixedVarArg; + + // VLT_MEMORY + + struct + { + void *rpValue; // pointer to the in-process + // location of the value. + } vlMemory; + }; + }; + */ + }; +} diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs new file mode 100644 index 00000000000..170a93b6a41 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs @@ -0,0 +1,1438 @@ +// 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 System.Runtime.InteropServices; + +namespace Internal.JitInterface +{ + public static class CORINFO + { + // CORINFO_MAXINDIRECTIONS is the maximum number of + // indirections used by runtime lookups. + // This accounts for up to 2 indirections to get at a dictionary followed by a possible spill slot + public const uint MAXINDIRECTIONS = 4; + public const ushort USEHELPER = 0xffff; + } + + public struct CORINFO_METHOD_STRUCT_ + { + internal static unsafe CORINFO_METHOD_STRUCT_* Construct(int i) + { + return (CORINFO_METHOD_STRUCT_*)((i + 1) << 4); + } + + internal static unsafe int GetValue(CORINFO_METHOD_STRUCT_* val) + { + return ((int)val - 1) >> 4; + } + } + + public struct CORINFO_FIELD_STRUCT_ + { + internal static unsafe CORINFO_FIELD_STRUCT_* Construct(int i) + { + return (CORINFO_FIELD_STRUCT_*)((i + 1) << 4); + } + internal static unsafe int GetValue(CORINFO_FIELD_STRUCT_* val) + { + return ((int)val - 1) >> 4; + } + } + + public struct CORINFO_CLASS_STRUCT_ + { + internal static unsafe CORINFO_CLASS_STRUCT_* Construct(int i) + { + return (CORINFO_CLASS_STRUCT_*)((i + 1) << 4); + } + + internal static unsafe int GetValue(CORINFO_CLASS_STRUCT_* val) + { + return ((int)val - 1) >> 4; + } + } + + public struct CORINFO_ARG_LIST_STRUCT_ + { + } + + public struct CORINFO_MODULE_STRUCT_ + { + internal static unsafe CORINFO_MODULE_STRUCT_* Construct(int i) + { + return (CORINFO_MODULE_STRUCT_*)((i + 1) << 4); + } + internal static unsafe int GetValue(CORINFO_MODULE_STRUCT_* val) + { + return ((int)val - 1) >> 4; + } + } + + public struct CORINFO_ASSEMBLY_STRUCT_ + { + } + + public struct CORINFO_CONTEXT_STRUCT + { + } + + public struct CORINFO_GENERIC_STRUCT_ + { + } + + public struct CORINFO_JUST_MY_CODE_HANDLE_ + { + } + + public struct CORINFO_VarArgInfo + { + } + + public enum _EXCEPTION_POINTERS + { } + + public unsafe struct CORINFO_SIG_INST + { + public uint classInstCount; + public CORINFO_CLASS_STRUCT_** classInst; // (representative, not exact) instantiation for class type variables in signature + public uint methInstCount; + public CORINFO_CLASS_STRUCT_** methInst; // (representative, not exact) instantiation for method type variables in signature + } + + public enum mdToken : uint + { } + + public enum HRESULT { + E_NOTIMPL = -2147467263 + } + + public unsafe struct CORINFO_SIG_INFO + { + public CorInfoCallConv callConv; + public CORINFO_CLASS_STRUCT_* retTypeClass; // if the return type is a value class, this is its handle (enums are normalized) + public CORINFO_CLASS_STRUCT_* retTypeSigClass;// returns the value class as it is in the sig (enums are not converted to primitives) + public byte _retType; + public byte flags; // used by IL stubs code + public ushort numArgs; + public CORINFO_SIG_INST sigInst; // information about how type variables are being instantiated in generic code + public CORINFO_ARG_LIST_STRUCT_* args; + public byte* pSig; + public uint cbSig; + public CORINFO_MODULE_STRUCT_* scope; // passed to getArgClass + public mdToken token; + + public CorInfoType retType { get { return (CorInfoType)_retType; } set { _retType = (byte)value; } } + private CorInfoCallConv getCallConv() { return (CorInfoCallConv)((callConv & CorInfoCallConv.CORINFO_CALLCONV_MASK)); } + private bool hasThis() { return ((callConv & CorInfoCallConv.CORINFO_CALLCONV_HASTHIS) != 0); } + private bool hasExplicitThis() { return ((callConv & CorInfoCallConv.CORINFO_CALLCONV_EXPLICITTHIS) != 0); } + private uint totalILArgs() { return (uint)(numArgs + (hasThis() ? 1 : 0)); } + private bool isVarArg() { return ((getCallConv() == CorInfoCallConv.CORINFO_CALLCONV_VARARG) || (getCallConv() == CorInfoCallConv.CORINFO_CALLCONV_NATIVEVARARG)); } + internal bool hasTypeArg() { return ((callConv & CorInfoCallConv.CORINFO_CALLCONV_PARAMTYPE) != 0); } + }; + + //---------------------------------------------------------------------------- + // Looking up handles and addresses. + // + // When the JIT requests a handle, the EE may direct the JIT that it must + // access the handle in a variety of ways. These are packed as + // CORINFO_CONST_LOOKUP + // or CORINFO_LOOKUP (contains either a CORINFO_CONST_LOOKUP or a CORINFO_RUNTIME_LOOKUP) + // + // Constant Lookups v. Runtime Lookups (i.e. when will Runtime Lookups be generated?) + // ----------------------------------------------------------------------------------- + // + // CORINFO_LOOKUP_KIND is part of the result type of embedGenericHandle, + // getVirtualCallInfo and any other functions that may require a + // runtime lookup when compiling shared generic code. + // + // CORINFO_LOOKUP_KIND indicates whether a particular token in the instruction stream can be: + // (a) Mapped to a handle (type, field or method) at compile-time (!needsRuntimeLookup) + // (b) Must be looked up at run-time, and if so which runtime lookup technique should be used (see below) + // + // If the JIT or EE does not support code sharing for generic code, then + // all CORINFO_LOOKUP results will be "constant lookups", i.e. + // the needsRuntimeLookup of CORINFO_LOOKUP.lookupKind.needsRuntimeLookup + // will be false. + // + // Constant Lookups + // ---------------- + // + // Constant Lookups are either: + // IAT_VALUE: immediate (relocatable) values, + // IAT_PVALUE: immediate values access via an indirection through an immediate (relocatable) address + // IAT_RELPVALUE: immediate values access via a relative indirection through an immediate offset + // IAT_PPVALUE: immediate values access via a double indirection through an immediate (relocatable) address + // + // Runtime Lookups + // --------------- + // + // CORINFO_LOOKUP_KIND is part of the result type of embedGenericHandle, + // getVirtualCallInfo and any other functions that may require a + // runtime lookup when compiling shared generic code. + // + // CORINFO_LOOKUP_KIND indicates whether a particular token in the instruction stream can be: + // (a) Mapped to a handle (type, field or method) at compile-time (!needsRuntimeLookup) + // (b) Must be looked up at run-time using the class dictionary + // stored in the vtable of the this pointer (needsRuntimeLookup && THISOBJ) + // (c) Must be looked up at run-time using the method dictionary + // stored in the method descriptor parameter passed to a generic + // method (needsRuntimeLookup && METHODPARAM) + // (d) Must be looked up at run-time using the class dictionary stored + // in the vtable parameter passed to a method in a generic + // struct (needsRuntimeLookup && CLASSPARAM) + + public unsafe struct CORINFO_CONST_LOOKUP + { + // If the handle is obtained at compile-time, then this handle is the "exact" handle (class, method, or field) + // Otherwise, it's a representative... + // If accessType is + // IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address + // IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle + // IAT_RELPVALUE --> "addr" stores a relative pointer to a location which will hold the real handle + // IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle + + public InfoAccessType accessType; + + // _value represent the union of handle and addr + private IntPtr _value; + public CORINFO_GENERIC_STRUCT_* handle { get { return (CORINFO_GENERIC_STRUCT_*)_value; } set { _value = (IntPtr)value; } } + public void* addr { get { return (void*)_value; } set { _value = (IntPtr)value; } } + }; + + public enum CORINFO_RUNTIME_LOOKUP_KIND + { + CORINFO_LOOKUP_THISOBJ, + CORINFO_LOOKUP_METHODPARAM, + CORINFO_LOOKUP_CLASSPARAM, + } + + public unsafe struct CORINFO_LOOKUP_KIND + { + private byte _needsRuntimeLookup; + public bool needsRuntimeLookup { get { return _needsRuntimeLookup != 0; } set { _needsRuntimeLookup = value ? (byte)1 : (byte)0; } } + public CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind; + + // The 'runtimeLookupFlags' and 'runtimeLookupArgs' fields + // are just for internal VM / ZAP communication, not to be used by the JIT. + public ushort runtimeLookupFlags; + public void* runtimeLookupArgs; + } + + // CORINFO_RUNTIME_LOOKUP indicates the details of the runtime lookup + // operation to be performed. + // + + public unsafe struct CORINFO_RUNTIME_LOOKUP + { + // This is signature you must pass back to the runtime lookup helper + public void* signature; + + // Here is the helper you must call. It is one of CORINFO_HELP_RUNTIMEHANDLE_* helpers. + public CorInfoHelpFunc helper; + + // Number of indirections to get there + // CORINFO_USEHELPER = don't know how to get it, so use helper function at run-time instead + // 0 = use the this pointer itself (e.g. token is C inside code in sealed class C) + // or method desc itself (e.g. token is method void M::mymeth() inside code in M::mymeth) + // Otherwise, follow each byte-offset stored in the "offsets[]" array (may be negative) + public ushort indirections; + + // If set, test for null and branch to helper if null + public byte _testForNull; + public bool testForNull { get { return _testForNull != 0; } set { _testForNull = value ? (byte)1 : (byte)0; } } + + // If set, test the lowest bit and dereference if set (see code:FixupPointer) + public byte _testForFixup; + public bool testForFixup { get { return _testForFixup != 0; } set { _testForFixup = value ? (byte)1 : (byte)0; } } + + public IntPtr offset0; + 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; } } + + public byte _indirectSecondOffset; + public bool indirectSecondOffset { get { return _indirectSecondOffset != 0; } set { _indirectSecondOffset = value ? (byte)1 : (byte)0; } } + + } + + // Result of calling embedGenericHandle + public unsafe struct CORINFO_LOOKUP + { + public CORINFO_LOOKUP_KIND lookupKind; + + // If kind.needsRuntimeLookup then this indicates how to do the lookup + public CORINFO_RUNTIME_LOOKUP runtimeLookup; + + // If the handle is obtained at compile-time, then this handle is the "exact" handle (class, method, or field) + // Otherwise, it's a representative... If accessType is + // IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address + // IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle + // IAT_RELPVALUE --> "addr" stores a relative pointer to a location which will hold the real handle + // IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle + public ref CORINFO_CONST_LOOKUP constLookup + { + get + { + // constLookup is union with runtimeLookup + Debug.Assert(sizeof(CORINFO_RUNTIME_LOOKUP) >= sizeof(CORINFO_CONST_LOOKUP)); + fixed (CORINFO_RUNTIME_LOOKUP * p = &runtimeLookup) + return ref *(CORINFO_CONST_LOOKUP *)p; + } + } + } + + public unsafe struct CORINFO_RESOLVED_TOKEN + { + // + // [In] arguments of resolveToken + // + public CORINFO_CONTEXT_STRUCT* tokenContext; //Context for resolution of generic arguments + public CORINFO_MODULE_STRUCT_* tokenScope; + public mdToken token; //The source token + public CorInfoTokenKind tokenType; + + // + // [Out] arguments of resolveToken. + // - Type handle is always non-NULL. + // - At most one of method and field handles is non-NULL (according to the token type). + // - Method handle is an instantiating stub only for generic methods. Type handle + // is required to provide the full context for methods in generic types. + // + public CORINFO_CLASS_STRUCT_* hClass; + public CORINFO_METHOD_STRUCT_* hMethod; + public CORINFO_FIELD_STRUCT_* hField; + + // + // [Out] TypeSpec and MethodSpec signatures for generics. NULL otherwise. + // + public byte* pTypeSpec; + public uint cbTypeSpec; + public byte* pMethodSpec; + public uint cbMethodSpec; + } + + + // Flags computed by a runtime compiler + public enum CorInfoMethodRuntimeFlags + { + CORINFO_FLG_BAD_INLINEE = 0x00000001, // The method is not suitable for inlining + CORINFO_FLG_VERIFIABLE = 0x00000002, // The method has verifiable code + CORINFO_FLG_UNVERIFIABLE = 0x00000004, // The method has unverifiable code + CORINFO_FLG_SWITCHED_TO_MIN_OPT = 0x00000008, // The JIT decided to switch to MinOpt for this method, when it was not requested + CORINFO_FLG_SWITCHED_TO_OPTIMIZED = 0x00000010, // The JIT decided to switch to tier 1 for this method, when a different tier was requested + }; + + // The enumeration is returned in 'getSig' + + public enum CorInfoCallConv + { + // These correspond to CorCallingConvention + + CORINFO_CALLCONV_DEFAULT = 0x0, + CORINFO_CALLCONV_C = 0x1, + CORINFO_CALLCONV_STDCALL = 0x2, + CORINFO_CALLCONV_THISCALL = 0x3, + CORINFO_CALLCONV_FASTCALL = 0x4, + CORINFO_CALLCONV_VARARG = 0x5, + CORINFO_CALLCONV_FIELD = 0x6, + CORINFO_CALLCONV_LOCAL_SIG = 0x7, + CORINFO_CALLCONV_PROPERTY = 0x8, + CORINFO_CALLCONV_NATIVEVARARG = 0xb, // used ONLY for IL stub PInvoke vararg calls + + CORINFO_CALLCONV_MASK = 0x0f, // Calling convention is bottom 4 bits + CORINFO_CALLCONV_GENERIC = 0x10, + CORINFO_CALLCONV_HASTHIS = 0x20, + CORINFO_CALLCONV_EXPLICITTHIS = 0x40, + CORINFO_CALLCONV_PARAMTYPE = 0x80, // Passed last. Same as CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG + } + + public enum CorInfoUnmanagedCallConv + { + // These correspond to CorUnmanagedCallingConvention + + CORINFO_UNMANAGED_CALLCONV_UNKNOWN, + CORINFO_UNMANAGED_CALLCONV_C, + CORINFO_UNMANAGED_CALLCONV_STDCALL, + CORINFO_UNMANAGED_CALLCONV_THISCALL, + CORINFO_UNMANAGED_CALLCONV_FASTCALL + } + + public enum CORINFO_CALLINFO_FLAGS + { + CORINFO_CALLINFO_NONE = 0x0000, + CORINFO_CALLINFO_ALLOWINSTPARAM = 0x0001, // Can the compiler generate code to pass an instantiation parameters? Simple compilers should not use this flag + CORINFO_CALLINFO_CALLVIRT = 0x0002, // Is it a virtual call? + CORINFO_CALLINFO_KINDONLY = 0x0004, // This is set to only query the kind of call to perform, without getting any other information + CORINFO_CALLINFO_VERIFICATION = 0x0008, // Gets extra verification information. + CORINFO_CALLINFO_SECURITYCHECKS = 0x0010, // Perform security checks. + CORINFO_CALLINFO_LDFTN = 0x0020, // Resolving target of LDFTN + CORINFO_CALLINFO_ATYPICAL_CALLSITE = 0x0040, // Atypical callsite that cannot be disassembled by delay loading helper + } + + // Bit-twiddling of contexts assumes word-alignment of method handles and type handles + // If this ever changes, some other encoding will be needed + public enum CorInfoContextFlags + { + CORINFO_CONTEXTFLAGS_METHOD = 0x00, // CORINFO_CONTEXT_HANDLE is really a CORINFO_METHOD_HANDLE + CORINFO_CONTEXTFLAGS_CLASS = 0x01, // CORINFO_CONTEXT_HANDLE is really a CORINFO_CLASS_HANDLE + CORINFO_CONTEXTFLAGS_MASK = 0x01 + }; + + public enum CorInfoSigInfoFlags + { + CORINFO_SIGFLAG_IS_LOCAL_SIG = 0x01, + CORINFO_SIGFLAG_IL_STUB = 0x02, + }; + + // These are returned from getMethodOptions + public enum CorInfoOptions + { + CORINFO_OPT_INIT_LOCALS = 0x00000010, // zero initialize all variables + + CORINFO_GENERICS_CTXT_FROM_THIS = 0x00000020, // is this shared generic code that access the generic context from the this pointer? If so, then if the method has SEH then the 'this' pointer must always be reported and kept alive. + CORINFO_GENERICS_CTXT_FROM_METHODDESC = 0x00000040, // is this shared generic code that access the generic context from the ParamTypeArg(that is a MethodDesc)? If so, then if the method has SEH then the 'ParamTypeArg' must always be reported and kept alive. Same as CORINFO_CALLCONV_PARAMTYPE + CORINFO_GENERICS_CTXT_FROM_METHODTABLE = 0x00000080, // is this shared generic code that access the generic context from the ParamTypeArg(that is a MethodTable)? If so, then if the method has SEH then the 'ParamTypeArg' must always be reported and kept alive. Same as CORINFO_CALLCONV_PARAMTYPE + CORINFO_GENERICS_CTXT_MASK = (CORINFO_GENERICS_CTXT_FROM_THIS | + CORINFO_GENERICS_CTXT_FROM_METHODDESC | + CORINFO_GENERICS_CTXT_FROM_METHODTABLE), + CORINFO_GENERICS_CTXT_KEEP_ALIVE = 0x00000100, // Keep the generics context alive throughout the method even if there is no explicit use, and report its location to the CLR + } + + public enum CorInfoIntrinsics + { + CORINFO_INTRINSIC_Sin, + CORINFO_INTRINSIC_Cos, + CORINFO_INTRINSIC_Cbrt, + CORINFO_INTRINSIC_Sqrt, + CORINFO_INTRINSIC_Abs, + CORINFO_INTRINSIC_Round, + CORINFO_INTRINSIC_Cosh, + CORINFO_INTRINSIC_Sinh, + CORINFO_INTRINSIC_Tan, + CORINFO_INTRINSIC_Tanh, + CORINFO_INTRINSIC_Asin, + CORINFO_INTRINSIC_Asinh, + CORINFO_INTRINSIC_Acos, + CORINFO_INTRINSIC_Acosh, + CORINFO_INTRINSIC_Atan, + CORINFO_INTRINSIC_Atan2, + CORINFO_INTRINSIC_Atanh, + CORINFO_INTRINSIC_Log10, + CORINFO_INTRINSIC_Pow, + CORINFO_INTRINSIC_Exp, + CORINFO_INTRINSIC_Ceiling, + CORINFO_INTRINSIC_Floor, + CORINFO_INTRINSIC_GetChar, // fetch character out of string + CORINFO_INTRINSIC_Array_GetDimLength, // Get number of elements in a given dimension of an array + CORINFO_INTRINSIC_Array_Get, // Get the value of an element in an array + CORINFO_INTRINSIC_Array_Address, // Get the address of an element in an array + CORINFO_INTRINSIC_Array_Set, // Set the value of an element in an array + CORINFO_INTRINSIC_StringGetChar, // fetch character out of string + CORINFO_INTRINSIC_StringLength, // get the length + CORINFO_INTRINSIC_InitializeArray, // initialize an array from static data + CORINFO_INTRINSIC_GetTypeFromHandle, + CORINFO_INTRINSIC_RTH_GetValueInternal, + CORINFO_INTRINSIC_TypeEQ, + CORINFO_INTRINSIC_TypeNEQ, + CORINFO_INTRINSIC_Object_GetType, + CORINFO_INTRINSIC_StubHelpers_GetStubContext, + CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr, + CORINFO_INTRINSIC_StubHelpers_GetNDirectTarget, + CORINFO_INTRINSIC_InterlockedAdd32, + CORINFO_INTRINSIC_InterlockedAdd64, + CORINFO_INTRINSIC_InterlockedXAdd32, + CORINFO_INTRINSIC_InterlockedXAdd64, + CORINFO_INTRINSIC_InterlockedXchg32, + CORINFO_INTRINSIC_InterlockedXchg64, + CORINFO_INTRINSIC_InterlockedCmpXchg32, + CORINFO_INTRINSIC_InterlockedCmpXchg64, + CORINFO_INTRINSIC_MemoryBarrier, + CORINFO_INTRINSIC_GetCurrentManagedThread, + CORINFO_INTRINSIC_GetManagedThreadId, + CORINFO_INTRINSIC_ByReference_Ctor, + 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, + } + + // Can a value be accessed directly from JITed code. + public enum InfoAccessType + { + IAT_VALUE, // The info value is directly available + IAT_PVALUE, // The value needs to be accessed via an indirection + IAT_PPVALUE, // The value needs to be accessed via a double indirection + IAT_RELPVALUE // The value needs to be accessed via a relative indirection + } + + public enum CorInfoGCType + { + TYPE_GC_NONE, // no embedded objectrefs + TYPE_GC_REF, // Is an object ref + TYPE_GC_BYREF, // Is an interior pointer - promote it but don't scan it + TYPE_GC_OTHER // requires type-specific treatment + } + + public enum CorInfoClassId + { + CLASSID_SYSTEM_OBJECT, + CLASSID_TYPED_BYREF, + CLASSID_TYPE_HANDLE, + CLASSID_FIELD_HANDLE, + CLASSID_METHOD_HANDLE, + CLASSID_STRING, + CLASSID_ARGUMENT_HANDLE, + CLASSID_RUNTIME_TYPE, + } + public enum CorInfoInline + { + INLINE_PASS = 0, // Inlining OK + + // failures are negative + INLINE_FAIL = -1, // Inlining not OK for this case only + INLINE_NEVER = -2, // This method should never be inlined, regardless of context + } + + public enum CorInfoInlineTypeCheck + { + CORINFO_INLINE_TYPECHECK_NONE = 0x00000000, // It's not okay to compare type's vtable with a native type handle + CORINFO_INLINE_TYPECHECK_PASS = 0x00000001, // It's okay to compare type's vtable with a native type handle + CORINFO_INLINE_TYPECHECK_USE_HELPER = 0x00000002, // Use a specialized helper to compare type's vtable with native type handle + } + + public enum CorInfoInlineTypeCheckSource + { + CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE = 0x00000000, // Type handle comes from the vtable + CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN = 0x00000001, // Type handle comes from an ldtoken + } + + public enum CorInfoInlineRestrictions + { + INLINE_RESPECT_BOUNDARY = 0x00000001, // You can inline if there are no calls from the method being inlined + INLINE_NO_CALLEE_LDSTR = 0x00000002, // You can inline only if you guarantee that if inlinee does an ldstr + // inlinee's module will never see that string (by any means). + // This is due to how we implement the NoStringInterningAttribute + // (by reusing the fixup table). + INLINE_SAME_THIS = 0x00000004, // You can inline only if the callee is on the same this reference as caller + } + + // If you add more values here, keep it in sync with TailCallTypeMap in ..\vm\ClrEtwAll.man + // and the string enum in CEEInfo::reportTailCallDecision in ..\vm\JITInterface.cpp + public enum CorInfoTailCall + { + TAILCALL_OPTIMIZED = 0, // Optimized tail call (epilog + jmp) + TAILCALL_RECURSIVE = 1, // Optimized into a loop (only when a method tail calls itself) + TAILCALL_HELPER = 2, // Helper assisted tail call (call to JIT_TailCall) + + // failures are negative + TAILCALL_FAIL = -1, // Couldn't do a tail call + } + + public enum CorInfoCanSkipVerificationResult + { + CORINFO_VERIFICATION_CANNOT_SKIP = 0, // Cannot skip verification during jit time. + CORINFO_VERIFICATION_CAN_SKIP = 1, // Can skip verification during jit time. + CORINFO_VERIFICATION_RUNTIME_CHECK = 2, // Cannot skip verification during jit time, + // but need to insert a callout to the VM to ask during runtime + // whether to raise a verification or not (if the method is unverifiable). + CORINFO_VERIFICATION_DONT_JIT = 3, // Cannot skip verification during jit time, + // but do not jit the method if is is unverifiable. + } + + public enum CorInfoInitClassResult + { + CORINFO_INITCLASS_NOT_REQUIRED = 0x00, // No class initialization required, but the class is not actually initialized yet + // (e.g. we are guaranteed to run the static constructor in method prolog) + CORINFO_INITCLASS_INITIALIZED = 0x01, // Class initialized + CORINFO_INITCLASS_SPECULATIVE = 0x02, // Class may be initialized speculatively + CORINFO_INITCLASS_USE_HELPER = 0x04, // The JIT must insert class initialization helper call. + CORINFO_INITCLASS_DONT_INLINE = 0x08, // The JIT should not inline the method requesting the class initialization. The class + // initialization requires helper class now, but will not require initialization + // if the method is compiled standalone. Or the method cannot be inlined due to some + // requirement around class initialization such as shared generics. + } + + public enum CORINFO_ACCESS_FLAGS + { + CORINFO_ACCESS_ANY = 0x0000, // Normal access + CORINFO_ACCESS_THIS = 0x0001, // Accessed via the this reference + CORINFO_ACCESS_UNWRAP = 0x0002, // Accessed via an unwrap reference + + CORINFO_ACCESS_NONNULL = 0x0004, // Instance is guaranteed non-null + + CORINFO_ACCESS_LDFTN = 0x0010, // Accessed via ldftn + + // Field access flags + CORINFO_ACCESS_GET = 0x0100, // Field get (ldfld) + CORINFO_ACCESS_SET = 0x0200, // Field set (stfld) + CORINFO_ACCESS_ADDRESS = 0x0400, // Field address (ldflda) + CORINFO_ACCESS_INIT_ARRAY = 0x0800, // Field use for InitializeArray + CORINFO_ACCESS_ATYPICAL_CALLSITE = 0x4000, // Atypical callsite that cannot be disassembled by delay loading helper + CORINFO_ACCESS_INLINECHECK = 0x8000, // Return fieldFlags and fieldAccessor only. Used by JIT64 during inlining. + } + + + // these are the attribute flags for fields and methods (getMethodAttribs) + [Flags] + public enum CorInfoFlag : uint + { + // CORINFO_FLG_UNUSED = 0x00000001, + // CORINFO_FLG_UNUSED = 0x00000002, + CORINFO_FLG_PROTECTED = 0x00000004, + CORINFO_FLG_STATIC = 0x00000008, + CORINFO_FLG_FINAL = 0x00000010, + CORINFO_FLG_SYNCH = 0x00000020, + CORINFO_FLG_VIRTUAL = 0x00000040, + // CORINFO_FLG_UNUSED = 0x00000080, + CORINFO_FLG_NATIVE = 0x00000100, + CORINFO_FLG_INTRINSIC_TYPE = 0x00000200, // This type is marked by [Intrinsic] + CORINFO_FLG_ABSTRACT = 0x00000400, + + CORINFO_FLG_EnC = 0x00000800, // member was added by Edit'n'Continue + + // These are internal flags that can only be on methods + CORINFO_FLG_FORCEINLINE = 0x00010000, // The method should be inlined if possible. + CORINFO_FLG_SHAREDINST = 0x00020000, // the code for this method is shared between different generic instantiations (also set on classes/types) + CORINFO_FLG_DELEGATE_INVOKE = 0x00040000, // "Delegate + CORINFO_FLG_PINVOKE = 0x00080000, // Is a P/Invoke call + CORINFO_FLG_SECURITYCHECK = 0x00100000, // Is one of the security routines that does a stackwalk (e.g. Assert, Demand) + CORINFO_FLG_NOGCCHECK = 0x00200000, // This method is FCALL that has no GC check. Don't put alone in loops + CORINFO_FLG_INTRINSIC = 0x00400000, // This method MAY have an intrinsic ID + CORINFO_FLG_CONSTRUCTOR = 0x00800000, // This method is an instance or type initializer + CORINFO_FLG_AGGRESSIVE_OPT = 0x01000000, // The method may contain hot code and should be aggressively optimized if possible + CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS = 0x02000000, // Indicates that tier 0 JIT should not be used for a method that contains a loop + CORINFO_FLG_NOSECURITYWRAP = 0x04000000, // The method requires no security checks + CORINFO_FLG_DONT_INLINE = 0x10000000, // The method should not be inlined + CORINFO_FLG_DONT_INLINE_CALLER = 0x20000000, // The method should not be inlined, nor should its callers. It cannot be tail called. + CORINFO_FLG_JIT_INTRINSIC = 0x40000000, // Method is a potential jit intrinsic; verify identity by name check + + // These are internal flags that can only be on Classes + CORINFO_FLG_VALUECLASS = 0x00010000, // is the class a value class + // This flag is define din the Methods section, but is also valid on classes. + // CORINFO_FLG_SHAREDINST = 0x00020000, // This class is satisfies TypeHandle::IsCanonicalSubtype + CORINFO_FLG_VAROBJSIZE = 0x00040000, // the object size varies depending of constructor args + CORINFO_FLG_ARRAY = 0x00080000, // class is an array class (initialized differently) + CORINFO_FLG_OVERLAPPING_FIELDS = 0x00100000, // struct or class has fields that overlap (aka union) + CORINFO_FLG_INTERFACE = 0x00200000, // it is an interface + CORINFO_FLG_CONTEXTFUL = 0x00400000, // is this a contextful class? + CORINFO_FLG_CUSTOMLAYOUT = 0x00800000, // does this struct have custom layout? + CORINFO_FLG_CONTAINS_GC_PTR = 0x01000000, // does the class contain a gc ptr ? + CORINFO_FLG_DELEGATE = 0x02000000, // is this a subclass of delegate or multicast delegate ? + CORINFO_FLG_MARSHAL_BYREF = 0x04000000, // is this a subclass of MarshalByRef ? + CORINFO_FLG_CONTAINS_STACK_PTR = 0x08000000, // This class has a stack pointer inside it + CORINFO_FLG_VARIANCE = 0x10000000, // MethodTable::HasVariance (sealed does *not* mean uncast-able) + CORINFO_FLG_BEFOREFIELDINIT = 0x20000000, // Additional flexibility for when to run .cctor (see code:#ClassConstructionFlags) + CORINFO_FLG_GENERIC_TYPE_VARIABLE = 0x40000000, // This is really a handle for a variable type + CORINFO_FLG_UNSAFE_VALUECLASS = 0x80000000, // Unsafe (C++'s /GS) value type + } + + + //---------------------------------------------------------------------------- + // Exception handling + + // These are the flags set on an CORINFO_EH_CLAUSE + public enum CORINFO_EH_CLAUSE_FLAGS + { + CORINFO_EH_CLAUSE_NONE = 0, + CORINFO_EH_CLAUSE_FILTER = 0x0001, // If this bit is on, then this EH entry is for a filter + CORINFO_EH_CLAUSE_FINALLY = 0x0002, // This clause is a finally clause + CORINFO_EH_CLAUSE_FAULT = 0x0004, // This clause is a fault clause + CORINFO_EH_CLAUSE_DUPLICATED = 0x0008, // Duplicated clause. This clause was duplicated to a funclet which was pulled out of line + CORINFO_EH_CLAUSE_SAMETRY = 0x0010, // This clause covers same try block as the previous one. (Used by CoreRT ABI.) + }; + + public struct CORINFO_EH_CLAUSE + { + public CORINFO_EH_CLAUSE_FLAGS Flags; + public uint TryOffset; + public uint TryLength; + public uint HandlerOffset; + public uint HandlerLength; + public uint ClassTokenOrOffset; + /* union + { + DWORD ClassToken; // use for type-based exception handlers + DWORD FilterOffset; // use for filter-based exception handlers (COR_ILEXCEPTION_FILTER is set) + };*/ + } + + public struct BlockCounts // Also defined here: code:CORBBTPROF_BLOCK_DATA + { + public uint ILOffset; + public uint ExecutionCount; + } + + // The enumeration is returned in 'getSig','getType', getArgType methods + public enum CorInfoType + { + CORINFO_TYPE_UNDEF = 0x0, + CORINFO_TYPE_VOID = 0x1, + CORINFO_TYPE_BOOL = 0x2, + CORINFO_TYPE_CHAR = 0x3, + CORINFO_TYPE_BYTE = 0x4, + CORINFO_TYPE_UBYTE = 0x5, + CORINFO_TYPE_SHORT = 0x6, + CORINFO_TYPE_USHORT = 0x7, + CORINFO_TYPE_INT = 0x8, + CORINFO_TYPE_UINT = 0x9, + CORINFO_TYPE_LONG = 0xa, + CORINFO_TYPE_ULONG = 0xb, + CORINFO_TYPE_NATIVEINT = 0xc, + CORINFO_TYPE_NATIVEUINT = 0xd, + CORINFO_TYPE_FLOAT = 0xe, + CORINFO_TYPE_DOUBLE = 0xf, + CORINFO_TYPE_STRING = 0x10, // Not used, should remove + CORINFO_TYPE_PTR = 0x11, + CORINFO_TYPE_BYREF = 0x12, + CORINFO_TYPE_VALUECLASS = 0x13, + CORINFO_TYPE_CLASS = 0x14, + CORINFO_TYPE_REFANY = 0x15, + + // CORINFO_TYPE_VAR is for a generic type variable. + // Generic type variables only appear when the JIT is doing + // verification (not NOT compilation) of generic code + // for the EE, in which case we're running + // the JIT in "import only" mode. + + CORINFO_TYPE_VAR = 0x16, + CORINFO_TYPE_COUNT, // number of jit types + } + + public enum CorInfoIsAccessAllowedResult + { + CORINFO_ACCESS_ALLOWED = 0, // Call allowed + CORINFO_ACCESS_ILLEGAL = 1, // Call not allowed + CORINFO_ACCESS_RUNTIME_CHECK = 2, // Ask at runtime whether to allow the call or not + } + + //---------------------------------------------------------------------------- + // Embedding type, method and field handles (for "ldtoken" or to pass back to helpers) + + // Result of calling embedGenericHandle + public unsafe struct CORINFO_GENERICHANDLE_RESULT + { + public CORINFO_LOOKUP lookup; + + // compileTimeHandle is guaranteed to be either NULL or a handle that is usable during compile time. + // It must not be embedded in the code because it might not be valid at run-time. + public CORINFO_GENERIC_STRUCT_* compileTimeHandle; + + // Type of the result + public CorInfoGenericHandleType handleType; + } + + public enum CorInfoGenericHandleType + { + CORINFO_HANDLETYPE_UNKNOWN, + CORINFO_HANDLETYPE_CLASS, + CORINFO_HANDLETYPE_METHOD, + CORINFO_HANDLETYPE_FIELD + } + + /* data to optimize delegate construction */ + public unsafe struct DelegateCtorArgs + { + public void* pMethod; + public void* pArg3; + public void* pArg4; + public void* pArg5; + } + + // When using CORINFO_HELPER_TAILCALL, the JIT needs to pass certain special + // calling convention/argument passing/handling details to the helper + public enum CorInfoHelperTailCallSpecialHandling + { + CORINFO_TAILCALL_NORMAL = 0x00000000, + CORINFO_TAILCALL_STUB_DISPATCH_ARG = 0x00000001, + } + + /*****************************************************************************/ + // These are flags passed to ICorJitInfo::allocMem + // to guide the memory allocation for the code, readonly data, and read-write data + public enum CorJitAllocMemFlag + { + CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN = 0x00000000, // The code will be use the normal alignment + CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN = 0x00000001, // The code will be 16-byte aligned + CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN = 0x00000002, // The read-only data will be 16-byte aligned + } + + public enum CorJitFuncKind + { + CORJIT_FUNC_ROOT, // The main/root function (always id==0) + CORJIT_FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler) + CORJIT_FUNC_FILTER // a funclet associated with an EH filter + } + + + public unsafe struct CORINFO_METHOD_INFO + { + public CORINFO_METHOD_STRUCT_* ftn; + public CORINFO_MODULE_STRUCT_* scope; + public byte* ILCode; + public uint ILCodeSize; + public uint maxStack; + public uint EHcount; + public CorInfoOptions options; + public CorInfoRegionKind regionKind; + public CORINFO_SIG_INFO args; + public CORINFO_SIG_INFO locals; + } + // + // what type of code region we are in + // + public enum CorInfoRegionKind + { + CORINFO_REGION_NONE, + CORINFO_REGION_HOT, + CORINFO_REGION_COLD, + CORINFO_REGION_JIT, + } + + // This is for use when the JIT is compiling an instantiation + // of generic code. The JIT needs to know if the generic code itself + // (which can be verified once and for all independently of the + // instantiations) passed verification. + public enum CorInfoInstantiationVerification + { + // The method is NOT a concrete instantiation (eg. List.Add()) of a method + // in a generic class or a generic method. It is either the typical instantiation + // (eg. List.Add()) or entirely non-generic. + INSTVER_NOT_INSTANTIATION = 0, + + // The method is an instantiation of a method in a generic class or a generic method, + // and the generic class was successfully verified + INSTVER_GENERIC_PASSED_VERIFICATION = 1, + + // The method is an instantiation of a method in a generic class or a generic method, + // and the generic class failed verification + INSTVER_GENERIC_FAILED_VERIFICATION = 2, + }; + + public enum CorInfoTypeWithMod + { + CORINFO_TYPE_MASK = 0x3F, // lower 6 bits are type mask + CORINFO_TYPE_MOD_PINNED = 0x40, // can be applied to CLASS, or BYREF to indiate pinned + }; + + public struct CORINFO_HELPER_ARG + { + public IntPtr argHandle; + public CorInfoAccessAllowedHelperArgType argType; + } + + public enum CorInfoAccessAllowedHelperArgType + { + CORINFO_HELPER_ARG_TYPE_Invalid = 0, + CORINFO_HELPER_ARG_TYPE_Field = 1, + CORINFO_HELPER_ARG_TYPE_Method = 2, + CORINFO_HELPER_ARG_TYPE_Class = 3, + CORINFO_HELPER_ARG_TYPE_Module = 4, + CORINFO_HELPER_ARG_TYPE_Const = 5, + } + + public struct CORINFO_HELPER_DESC + { + public CorInfoHelpFunc helperNum; + public uint numArgs; + public CORINFO_HELPER_ARG args0; + public CORINFO_HELPER_ARG args1; + public CORINFO_HELPER_ARG args2; + public CORINFO_HELPER_ARG args3; + } + + + public enum CORINFO_OS + { + CORINFO_WINNT, + CORINFO_PAL, + } + + public enum CORINFO_RUNTIME_ABI + { + CORINFO_DESKTOP_ABI = 0x100, + CORINFO_CORECLR_ABI = 0x200, + CORINFO_CORERT_ABI = 0x300, + } + + // For some highly optimized paths, the JIT must generate code that directly + // manipulates internal EE data structures. The getEEInfo() helper returns + // this structure containing the needed offsets and values. + public struct CORINFO_EE_INFO + { + // Information about the InlinedCallFrame structure layout + public struct InlinedCallFrameInfo + { + // Size of the Frame structure + public uint size; + + public uint offsetOfGSCookie; + public uint offsetOfFrameVptr; + public uint offsetOfFrameLink; + public uint offsetOfCallSiteSP; + public uint offsetOfCalleeSavedFP; + public uint offsetOfCallTarget; + public uint offsetOfReturnAddress; + public uint offsetOfSPAfterProlog; + } + public InlinedCallFrameInfo inlinedCallFrameInfo; + + // Offsets into the Thread structure + public uint offsetOfThreadFrame; // offset of the current Frame + public uint offsetOfGCState; // offset of the preemptive/cooperative state of the Thread + + // Delegate offsets + public uint offsetOfDelegateInstance; + public uint offsetOfDelegateFirstTarget; + + // Wrapper delegate offsets + public uint offsetOfWrapperDelegateIndirectCell; + + // Remoting offsets + public uint offsetOfTransparentProxyRP; + public uint offsetOfRealProxyServer; + + // Array offsets + public uint offsetOfObjArrayData; + + // Reverse PInvoke offsets + public uint sizeOfReversePInvokeFrame; + + // OS Page size + public UIntPtr osPageSize; + + // Null object offset + public UIntPtr maxUncheckedOffsetForNullObject; + + // Target ABI. Combined with target architecture and OS to determine + // GC, EH, and unwind styles. + public CORINFO_RUNTIME_ABI targetAbi; + + public CORINFO_OS osType; + public uint osMajor; + public uint osMinor; + public uint osBuild; + } + + public enum CORINFO_THIS_TRANSFORM + { + CORINFO_NO_THIS_TRANSFORM, + CORINFO_BOX_THIS, + CORINFO_DEREF_THIS + }; + + //---------------------------------------------------------------------------- + // getCallInfo and CORINFO_CALL_INFO: The EE instructs the JIT about how to make a call + // + // callKind + // -------- + // + // CORINFO_CALL : + // Indicates that the JIT can use getFunctionEntryPoint to make a call, + // i.e. there is nothing abnormal about the call. The JITs know what to do if they get this. + // Except in the case of constraint calls (see below), [targetMethodHandle] will hold + // the CORINFO_METHOD_HANDLE that a call to findMethod would + // have returned. + // This flag may be combined with nullInstanceCheck=TRUE for uses of callvirt on methods that can + // be resolved at compile-time (non-virtual, final or sealed). + // + // CORINFO_CALL_CODE_POINTER (shared generic code only) : + // Indicates that the JIT should do an indirect call to the entrypoint given by address, which may be specified + // as a runtime lookup by CORINFO_CALL_INFO::codePointerLookup. + // [targetMethodHandle] will not hold a valid value. + // This flag may be combined with nullInstanceCheck=TRUE for uses of callvirt on methods whose target method can + // be resolved at compile-time but whose instantiation can be resolved only through runtime lookup. + // + // CORINFO_VIRTUALCALL_STUB (interface calls) : + // Indicates that the EE supports "stub dispatch" and request the JIT to make a + // "stub dispatch" call (an indirect call through CORINFO_CALL_INFO::stubLookup, + // similar to CORINFO_CALL_CODE_POINTER). + // "Stub dispatch" is a specialized calling sequence (that may require use of NOPs) + // which allow the runtime to determine the call-site after the call has been dispatched. + // If the call is too complex for the JIT (e.g. because + // fetching the dispatch stub requires a runtime lookup, i.e. lookupKind.needsRuntimeLookup + // is set) then the JIT is allowed to implement the call as if it were CORINFO_VIRTUALCALL_LDVIRTFTN + // [targetMethodHandle] will hold the CORINFO_METHOD_HANDLE that a call to findMethod would + // have returned. + // This flag is always accompanied by nullInstanceCheck=TRUE. + // + // CORINFO_VIRTUALCALL_LDVIRTFTN (virtual generic methods) : + // Indicates that the EE provides no way to implement the call directly and + // that the JIT should use a LDVIRTFTN sequence (as implemented by CORINFO_HELP_VIRTUAL_FUNC_PTR) + // followed by an indirect call. + // [targetMethodHandle] will hold the CORINFO_METHOD_HANDLE that a call to findMethod would + // have returned. + // This flag is always accompanied by nullInstanceCheck=TRUE though typically the null check will + // be implicit in the access through the instance pointer. + // + // CORINFO_VIRTUALCALL_VTABLE (regular virtual methods) : + // Indicates that the EE supports vtable dispatch and that the JIT should use getVTableOffset etc. + // to implement the call. + // [targetMethodHandle] will hold the CORINFO_METHOD_HANDLE that a call to findMethod would + // have returned. + // This flag is always accompanied by nullInstanceCheck=TRUE though typically the null check will + // be implicit in the access through the instance pointer. + // + // thisTransform and constraint calls + // ---------------------------------- + // + // For evertyhing besides "constrained." calls "thisTransform" is set to + // CORINFO_NO_THIS_TRANSFORM. + // + // For "constrained." calls the EE attempts to resolve the call at compile + // time to a more specific method, or (shared generic code only) to a runtime lookup + // for a code pointer for the more specific method. + // + // In order to permit this, the "this" pointer supplied for a "constrained." call + // is a byref to an arbitrary type (see the IL spec). The "thisTransform" field + // will indicate how the JIT must transform the "this" pointer in order + // to be able to call the resolved method: + // + // CORINFO_NO_THIS_TRANSFORM --> Leave it as a byref to an unboxed value type + // CORINFO_BOX_THIS --> Box it to produce an object + // CORINFO_DEREF_THIS --> Deref the byref to get an object reference + // + // In addition, the "kind" field will be set as follows for constraint calls: + + // CORINFO_CALL --> the call was resolved at compile time, and + // can be compiled like a normal call. + // CORINFO_CALL_CODE_POINTER --> the call was resolved, but the target address will be + // computed at runtime. Only returned for shared generic code. + // CORINFO_VIRTUALCALL_STUB, + // CORINFO_VIRTUALCALL_LDVIRTFTN, + // CORINFO_VIRTUALCALL_VTABLE --> usual values indicating that a virtual call must be made + + public enum CORINFO_CALL_KIND + { + CORINFO_CALL, + CORINFO_CALL_CODE_POINTER, + CORINFO_VIRTUALCALL_STUB, + CORINFO_VIRTUALCALL_LDVIRTFTN, + CORINFO_VIRTUALCALL_VTABLE + }; + + public enum CORINFO_VIRTUALCALL_NO_CHUNK : uint + { + Value = 0xFFFFFFFF, + } + + public unsafe struct CORINFO_CALL_INFO + { + public CORINFO_METHOD_STRUCT_* hMethod; //target method handle + public uint methodFlags; //flags for the target method + + public uint classFlags; //flags for CORINFO_RESOLVED_TOKEN::hClass + + public CORINFO_SIG_INFO sig; + + //Verification information + public uint verMethodFlags; // flags for CORINFO_RESOLVED_TOKEN::hMethod + public CORINFO_SIG_INFO verSig; + //All of the regular method data is the same... hMethod might not be the same as CORINFO_RESOLVED_TOKEN::hMethod + + + //If set to: + // - CORINFO_ACCESS_ALLOWED - The access is allowed. + // - CORINFO_ACCESS_ILLEGAL - This access cannot be allowed (i.e. it is public calling private). The + // JIT may either insert the callsiteCalloutHelper into the code (as per a verification error) or + // call throwExceptionFromHelper on the callsiteCalloutHelper. In this case callsiteCalloutHelper + // is guaranteed not to return. + // - CORINFO_ACCESS_RUNTIME_CHECK - The jit must insert the callsiteCalloutHelper at the call site. + // the helper may return + public CorInfoIsAccessAllowedResult accessAllowed; + public CORINFO_HELPER_DESC callsiteCalloutHelper; + + // See above section on constraintCalls to understand when these are set to unusual values. + public CORINFO_THIS_TRANSFORM thisTransform; + + public CORINFO_CALL_KIND kind; + + public uint _nullInstanceCheck; + public bool nullInstanceCheck { get { return _nullInstanceCheck != 0; } set { _nullInstanceCheck = value ? (byte)1 : (byte)0; } } + + // Context for inlining and hidden arg + public CORINFO_CONTEXT_STRUCT* contextHandle; + + public uint _exactContextNeedsRuntimeLookup; // Set if contextHandle is approx handle. Runtime lookup is required to get the exact handle. + public bool exactContextNeedsRuntimeLookup { get { return _exactContextNeedsRuntimeLookup != 0; } set { _exactContextNeedsRuntimeLookup = value ? (byte)1 : (byte)0; } } + + // If kind.CORINFO_VIRTUALCALL_STUB then stubLookup will be set. + // If kind.CORINFO_CALL_CODE_POINTER then entryPointLookup will be set. + public CORINFO_LOOKUP codePointerOrStubLookup; + + // Used by Ready-to-Run + public CORINFO_CONST_LOOKUP instParamLookup; + + public uint _wrapperDelegateInvoke; + public bool wrapperDelegateInvoke { get { return _wrapperDelegateInvoke != 0; } set { _wrapperDelegateInvoke = value ? (byte)1 : (byte)0; } } + } + + + //---------------------------------------------------------------------------- + // getFieldInfo and CORINFO_FIELD_INFO: The EE instructs the JIT about how to access a field + + public enum CORINFO_FIELD_ACCESSOR + { + CORINFO_FIELD_INSTANCE, // regular instance field at given offset from this-ptr + CORINFO_FIELD_INSTANCE_WITH_BASE, // instance field with base offset (used by Ready-to-Run) + CORINFO_FIELD_INSTANCE_HELPER, // instance field accessed using helper (arguments are this, FieldDesc * and the value) + CORINFO_FIELD_INSTANCE_ADDR_HELPER, // instance field accessed using address-of helper (arguments are this and FieldDesc *) + + CORINFO_FIELD_STATIC_ADDRESS, // field at given address + CORINFO_FIELD_STATIC_RVA_ADDRESS, // RVA field at given address + CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER, // static field accessed using the "shared static" helper (arguments are ModuleID + ClassID) + CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER, // static field access using the "generic static" helper (argument is MethodTable *) + CORINFO_FIELD_STATIC_ADDR_HELPER, // static field accessed using address-of helper (argument is FieldDesc *) + CORINFO_FIELD_STATIC_TLS, // unmanaged TLS access + CORINFO_FIELD_STATIC_READYTORUN_HELPER, // static field access using a runtime lookup helper + + CORINFO_FIELD_INTRINSIC_ZERO, // intrinsic zero (IntPtr.Zero, UIntPtr.Zero) + CORINFO_FIELD_INTRINSIC_EMPTY_STRING, // intrinsic emptry string (String.Empty) + CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN, // intrinsic BitConverter.IsLittleEndian + } + + // Set of flags returned in CORINFO_FIELD_INFO::fieldFlags + public enum CORINFO_FIELD_FLAGS + { + CORINFO_FLG_FIELD_STATIC = 0x00000001, + CORINFO_FLG_FIELD_UNMANAGED = 0x00000002, // RVA field + CORINFO_FLG_FIELD_FINAL = 0x00000004, + CORINFO_FLG_FIELD_STATIC_IN_HEAP = 0x00000008, // See code:#StaticFields. This static field is in the GC heap as a boxed object + CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN = 0x00000010, // Field can be returned safely (has GC heap lifetime) + CORINFO_FLG_FIELD_INITCLASS = 0x00000020, // initClass has to be called before accessing the field + CORINFO_FLG_FIELD_PROTECTED = 0x00000040, + } + + public unsafe struct CORINFO_FIELD_INFO + { + public CORINFO_FIELD_ACCESSOR fieldAccessor; + public CORINFO_FIELD_FLAGS fieldFlags; + + // Helper to use if the field access requires it + public CorInfoHelpFunc helper; + + // Field offset if there is one + public uint offset; + + public CorInfoType fieldType; + public CORINFO_CLASS_STRUCT_* structType; //possibly null + + //See CORINFO_CALL_INFO.accessAllowed + public CorInfoIsAccessAllowedResult accessAllowed; + public CORINFO_HELPER_DESC accessCalloutHelper; + + // Used by Ready-to-Run + public CORINFO_CONST_LOOKUP fieldLookup; + }; + + // System V struct passing + // The Classification types are described in the ABI spec at http://www.x86-64.org/documentation/abi.pdf + public enum SystemVClassificationType : byte + { + SystemVClassificationTypeUnknown = 0, + SystemVClassificationTypeStruct = 1, + SystemVClassificationTypeNoClass = 2, + SystemVClassificationTypeMemory = 3, + SystemVClassificationTypeInteger = 4, + SystemVClassificationTypeIntegerReference = 5, + SystemVClassificationTypeIntegerByRef = 6, + SystemVClassificationTypeSSE = 7, + // SystemVClassificationTypeSSEUp = Unused, // Not supported by the CLR. + // SystemVClassificationTypeX87 = Unused, // Not supported by the CLR. + // SystemVClassificationTypeX87Up = Unused, // Not supported by the CLR. + // SystemVClassificationTypeComplexX87 = Unused, // Not supported by the CLR. + + // Internal flags - never returned outside of the classification implementation. + + // This value represents a very special type with two eightbytes. + // First ByRef, second Integer (platform int). + // The VM has a special Elem type for this type - ELEMENT_TYPE_TYPEDBYREF. + // This is the classification counterpart for that element type. It is used to detect + // the special TypedReference type and specialize its classification. + // This type is represented as a struct with two fields. The classification needs to do + // special handling of it since the source/methadata type of the fieds is IntPtr. + // The VM changes the first to ByRef. The second is left as IntPtr (TYP_I_IMPL really). The classification needs to match this and + // special handling is warranted (similar thing is done in the getGCLayout function for this type). + SystemVClassificationTypeTypedReference = 8, + SystemVClassificationTypeMAX = 9 + }; + + public struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR + { + public const int CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS = 2; + public const int CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS = 16; + + public const int SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES = 8; // Size of an eightbyte in bytes. + public const int SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT = 16; // Maximum number of fields in struct passed in registers + + public byte _passedInRegisters; + // Whether the struct is passable/passed (this includes struct returning) in registers. + public bool passedInRegisters { get { return _passedInRegisters != 0; } set { _passedInRegisters = value ? (byte)1 : (byte)0; } } + + // Number of eightbytes for this struct. + public byte eightByteCount; + + // The eightbytes type classification. + public SystemVClassificationType eightByteClassifications0; + public SystemVClassificationType eightByteClassifications1; + + // The size of the eightbytes (an eightbyte could include padding. This represents the no padding size of the eightbyte). + public byte eightByteSizes0; + public byte eightByteSizes1; + + // The start offset of the eightbytes (in bytes). + public byte eightByteOffsets0; + public byte eightByteOffsets1; + }; + + // DEBUGGER DATA + public enum MappingTypes + { + NO_MAPPING = -1, // -- The IL offset corresponds to no source code (such as EH step blocks). + PROLOG = -2, // -- The IL offset indicates a prolog + EPILOG = -3 // -- The IL offset indicates an epilog + } + + public enum BoundaryTypes + { + NO_BOUNDARIES = 0x00, // No implicit boundaries + STACK_EMPTY_BOUNDARIES = 0x01, // Boundary whenever the IL evaluation stack is empty + NOP_BOUNDARIES = 0x02, // Before every CEE_NOP instruction + CALL_SITE_BOUNDARIES = 0x04, // Before every CEE_CALL, CEE_CALLVIRT, etc instruction + + // Set of boundaries that debugger should always reasonably ask the JIT for. + DEFAULT_BOUNDARIES = STACK_EMPTY_BOUNDARIES | NOP_BOUNDARIES | CALL_SITE_BOUNDARIES + } + + // Note that SourceTypes can be OR'd together - it's possible that + // a sequence point will also be a stack_empty point, and/or a call site. + // The debugger will check to see if a boundary offset's source field & + // SEQUENCE_POINT is true to determine if the boundary is a sequence point. + [Flags] + public enum SourceTypes + { + SOURCE_TYPE_INVALID = 0x00, // To indicate that nothing else applies + SEQUENCE_POINT = 0x01, // The debugger asked for it. + STACK_EMPTY = 0x02, // The stack is empty here + CALL_SITE = 0x04, // This is a call site. + NATIVE_END_OFFSET_UNKNOWN = 0x08, // Indicates a epilog endpoint + CALL_INSTRUCTION = 0x10 // The actual instruction of a call. + }; + + public struct OffsetMapping + { + public uint nativeOffset; + public uint ilOffset; + public SourceTypes source; // The debugger needs this so that + // we don't put Edit and Continue breakpoints where + // the stack isn't empty. We can put regular breakpoints + // there, though, so we need a way to discriminate + // between offsets. + }; + + public enum ILNum + { + VARARGS_HND_ILNUM = -1, // Value for the CORINFO_VARARGS_HANDLE varNumber + RETBUF_ILNUM = -2, // Pointer to the return-buffer + TYPECTXT_ILNUM = -3, // ParamTypeArg for CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG + + UNKNOWN_ILNUM = -4, // Unknown variable + + MAX_ILNUM = -4 // Sentinal value. This should be set to the largest magnitude value in the enum + // so that the compression routines know the enum's range. + }; + + public struct ILVarInfo + { + public uint startOffset; + public uint endOffset; + public uint varNumber; + }; + + // This enum is used for JIT to tell EE where this token comes from. + // E.g. Depending on different opcodes, we might allow/disallow certain types of tokens or + // return different types of handles (e.g. boxed vs. regular entrypoints) + public enum CorInfoTokenKind + { + CORINFO_TOKENKIND_Class = 0x01, + CORINFO_TOKENKIND_Method = 0x02, + CORINFO_TOKENKIND_Field = 0x04, + CORINFO_TOKENKIND_Mask = 0x07, + + // token comes from CEE_LDTOKEN + CORINFO_TOKENKIND_Ldtoken = 0x10 | CORINFO_TOKENKIND_Class | CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field, + + // token comes from CEE_CASTCLASS or CEE_ISINST + CORINFO_TOKENKIND_Casting = 0x20 | CORINFO_TOKENKIND_Class, + + // token comes from CEE_NEWARR + CORINFO_TOKENKIND_Newarr = 0x40 | CORINFO_TOKENKIND_Class, + + // token comes from CEE_BOX + CORINFO_TOKENKIND_Box = 0x80 | CORINFO_TOKENKIND_Class, + + // token comes from CEE_CONSTRAINED + CORINFO_TOKENKIND_Constrained = 0x100 | CORINFO_TOKENKIND_Class, + + // token comes from CEE_NEWOBJ + CORINFO_TOKENKIND_NewObj = 0x200 | CORINFO_TOKENKIND_Method, + + // token comes from CEE_LDVIRTFTN + CORINFO_TOKENKIND_Ldvirtftn = 0x400 | CORINFO_TOKENKIND_Method, + }; + + // These are error codes returned by CompileMethod + public enum CorJitResult + { + // Note that I dont use FACILITY_NULL for the facility number, + // we may want to get a 'real' facility number + CORJIT_OK = 0 /*NO_ERROR*/, + CORJIT_BADCODE = unchecked((int)0x80000001)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 1)*/, + CORJIT_OUTOFMEM = unchecked((int)0x80000002)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 2)*/, + CORJIT_INTERNALERROR = unchecked((int)0x80000003)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 3)*/, + CORJIT_SKIPPED = unchecked((int)0x80000004)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 4)*/, + CORJIT_RECOVERABLEERROR = unchecked((int)0x80000005)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 5)*/ + }; + + public enum TypeCompareState + { + MustNot = -1, // types are not equal + May = 0, // types may be equal (must test at runtime) + Must = 1, // type are equal + } + + public enum CorJitFlag : uint + { + CORJIT_FLAG_CALL_GETJITFLAGS = 0xffffffff, // Indicates that the JIT should retrieve flags in the form of a + // pointer to a CORJIT_FLAGS value via ICorJitInfo::getJitFlags(). + CORJIT_FLAG_SPEED_OPT = 0, + CORJIT_FLAG_SIZE_OPT = 1, + CORJIT_FLAG_DEBUG_CODE = 2, // generate "debuggable" code (no code-mangling optimizations) + CORJIT_FLAG_DEBUG_EnC = 3, // We are in Edit-n-Continue mode + CORJIT_FLAG_DEBUG_INFO = 4, // generate line and local-var info + CORJIT_FLAG_MIN_OPT = 5, // disable all jit optimizations (not necesarily debuggable code) + CORJIT_FLAG_GCPOLL_CALLS = 6, // Emit calls to JIT_POLLGC for thread suspension. + CORJIT_FLAG_MCJIT_BACKGROUND = 7, // Calling from multicore JIT background thread, do not call JitComplete + CORJIT_FLAG_UNUSED1 = 8, + CORJIT_FLAG_UNUSED2 = 9, + CORJIT_FLAG_UNUSED3 = 10, + CORJIT_FLAG_UNUSED4 = 11, + CORJIT_FLAG_UNUSED5 = 12, + CORJIT_FLAG_UNUSED6 = 13, + CORJIT_FLAG_USE_AVX = 14, + CORJIT_FLAG_USE_AVX2 = 15, + CORJIT_FLAG_USE_AVX_512 = 16, + CORJIT_FLAG_FEATURE_SIMD = 17, + CORJIT_FLAG_MAKEFINALCODE = 18, // Use the final code generator, i.e., not the interpreter. + CORJIT_FLAG_READYTORUN = 19, // Use version-resilient code generation + CORJIT_FLAG_PROF_ENTERLEAVE = 20, // Instrument prologues/epilogues + CORJIT_FLAG_PROF_REJIT_NOPS = 21, // Insert NOPs to ensure code is re-jitable + CORJIT_FLAG_PROF_NO_PINVOKE_INLINE = 22, // Disables PInvoke inlining + CORJIT_FLAG_SKIP_VERIFICATION = 23, // (lazy) skip verification - determined without doing a full resolve. See comment below + CORJIT_FLAG_PREJIT = 24, // jit or prejit is the execution engine. + CORJIT_FLAG_RELOC = 25, // Generate relocatable code + CORJIT_FLAG_IMPORT_ONLY = 26, // Only import the function + CORJIT_FLAG_IL_STUB = 27, // method is an IL stub + CORJIT_FLAG_PROCSPLIT = 28, // JIT should separate code into hot and cold sections + CORJIT_FLAG_BBINSTR = 29, // Collect basic block profile information + CORJIT_FLAG_BBOPT = 30, // Optimize method based on profile information + CORJIT_FLAG_FRAMED = 31, // All methods have an EBP frame + CORJIT_FLAG_ALIGN_LOOPS = 32, // add NOPs before loops to align them at 16 byte boundaries + CORJIT_FLAG_PUBLISH_SECRET_PARAM = 33, // JIT must place stub secret param into local 0. (used by IL stubs) + CORJIT_FLAG_GCPOLL_INLINE = 34, // JIT must inline calls to GCPoll when possible + CORJIT_FLAG_SAMPLING_JIT_BACKGROUND = 35, // JIT is being invoked as a result of stack sampling for hot methods in the background + CORJIT_FLAG_USE_PINVOKE_HELPERS = 36, // The JIT should use the PINVOKE_{BEGIN,END} helpers instead of emitting inline transitions + CORJIT_FLAG_REVERSE_PINVOKE = 37, // The JIT should insert REVERSE_PINVOKE_{ENTER,EXIT} helpers into method prolog/epilog + CORJIT_FLAG_DESKTOP_QUIRKS = 38, // The JIT should generate desktop-quirk-compatible code + CORJIT_FLAG_TIER0 = 39, // This is the initial tier for tiered compilation which should generate code as quickly as possible + CORJIT_FLAG_TIER1 = 40, // This is the final tier (for now) for tiered compilation which should generate high quality code + CORJIT_FLAG_RELATIVE_CODE_RELOCS = 41, // JIT should generate PC-relative address computations instead of EE relocation records + CORJIT_FLAG_NO_INLINING = 42, // JIT should not inline any called method into this method + +#region ARM64 + CORJIT_FLAG_HAS_ARM64_AES = 43, // ID_AA64ISAR0_EL1.AES is 1 or better + CORJIT_FLAG_HAS_ARM64_ATOMICS = 44, // ID_AA64ISAR0_EL1.Atomic is 2 or better + CORJIT_FLAG_HAS_ARM64_CRC32 = 45, // ID_AA64ISAR0_EL1.CRC32 is 1 or better + CORJIT_FLAG_HAS_ARM64_DCPOP = 46, // ID_AA64ISAR1_EL1.DPB is 1 or better + CORJIT_FLAG_HAS_ARM64_DP = 47, // ID_AA64ISAR0_EL1.DP is 1 or better + CORJIT_FLAG_HAS_ARM64_FCMA = 48, // ID_AA64ISAR1_EL1.FCMA is 1 or better + CORJIT_FLAG_HAS_ARM64_FP = 49, // ID_AA64PFR0_EL1.FP is 0 or better + CORJIT_FLAG_HAS_ARM64_FP16 = 50, // ID_AA64PFR0_EL1.FP is 1 or better + CORJIT_FLAG_HAS_ARM64_JSCVT = 51, // ID_AA64ISAR1_EL1.JSCVT is 1 or better + CORJIT_FLAG_HAS_ARM64_LRCPC = 52, // ID_AA64ISAR1_EL1.LRCPC is 1 or better + CORJIT_FLAG_HAS_ARM64_PMULL = 53, // ID_AA64ISAR0_EL1.AES is 2 or better + CORJIT_FLAG_HAS_ARM64_SHA1 = 54, // ID_AA64ISAR0_EL1.SHA1 is 1 or better + CORJIT_FLAG_HAS_ARM64_SHA256 = 55, // ID_AA64ISAR0_EL1.SHA2 is 1 or better + CORJIT_FLAG_HAS_ARM64_SHA512 = 56, // ID_AA64ISAR0_EL1.SHA2 is 2 or better + CORJIT_FLAG_HAS_ARM64_SHA3 = 57, // ID_AA64ISAR0_EL1.SHA3 is 1 or better + CORJIT_FLAG_HAS_ARM64_SIMD = 58, // ID_AA64PFR0_EL1.AdvSIMD is 0 or better + CORJIT_FLAG_HAS_ARM64_SIMD_V81 = 59, // ID_AA64ISAR0_EL1.RDM is 1 or better + CORJIT_FLAG_HAS_ARM64_SIMD_FP16 = 60, // ID_AA64PFR0_EL1.AdvSIMD is 1 or better + CORJIT_FLAG_HAS_ARM64_SM3 = 61, // ID_AA64ISAR0_EL1.SM3 is 1 or better + CORJIT_FLAG_HAS_ARM64_SM4 = 62, // ID_AA64ISAR0_EL1.SM4 is 1 or better + CORJIT_FLAG_HAS_ARM64_SVE = 63, // ID_AA64PFR0_EL1.SVE is 1 or better +#endregion + +#region x86/x64 + CORJIT_FLAG_USE_SSE3 = 43, + CORJIT_FLAG_USE_SSSE3 = 44, + CORJIT_FLAG_USE_SSE41 = 45, + CORJIT_FLAG_USE_SSE42 = 46, + CORJIT_FLAG_USE_AES = 47, + CORJIT_FLAG_USE_BMI1 = 48, + CORJIT_FLAG_USE_BMI2 = 49, + CORJIT_FLAG_USE_FMA = 50, + CORJIT_FLAG_USE_LZCNT = 51, + CORJIT_FLAG_USE_PCLMULQDQ = 52, + CORJIT_FLAG_USE_POPCNT = 53, +#endregion + } + + public struct CORJIT_FLAGS + { + private UInt64 _corJitFlags; + + public void Reset() + { + _corJitFlags = 0; + } + + public void Set(CorJitFlag flag) + { + _corJitFlags |= 1UL << (int)flag; + } + + public void Clear(CorJitFlag flag) + { + _corJitFlags &= ~(1UL << (int)flag); + } + + public bool IsSet(CorJitFlag flag) + { + return (_corJitFlags & (1UL << (int)flag)) != 0; + } + + public void Add(ref CORJIT_FLAGS other) + { + _corJitFlags |= other._corJitFlags; + } + + public void Remove(ref CORJIT_FLAGS other) + { + _corJitFlags &= ~other._corJitFlags; + } + + public bool IsEmpty() + { + return _corJitFlags == 0; + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/JitConfigProvider.cs b/src/coreclr/src/tools/Common/JitInterface/JitConfigProvider.cs new file mode 100644 index 00000000000..0e73be8bf6a --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/JitConfigProvider.cs @@ -0,0 +1,137 @@ +// 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.Collections.Generic; +using System.Runtime.InteropServices; + +using NumberStyles = System.Globalization.NumberStyles; + +namespace Internal.JitInterface +{ + public sealed class JitConfigProvider + { + private CorJitFlag[] _jitFlags; + private Dictionary _config = new Dictionary(StringComparer.OrdinalIgnoreCase); + private object _keepAlive; // Keeps callback delegates alive + + public IntPtr UnmanagedInstance + { + get; + } + + public string JitPath + { + get; + } + + public IEnumerable Flags => _jitFlags; + + /// + /// Creates a new instance of . + /// + /// A collection of JIT compiler flags. + /// A collection of parameter name/value pairs. + /// A path to the JIT library to be used (may be null). + public JitConfigProvider(IEnumerable jitFlags, IEnumerable> parameters, string jitPath = null) + { + ArrayBuilder jitFlagBuilder = new ArrayBuilder(); + foreach (CorJitFlag jitFlag in jitFlags) + { + jitFlagBuilder.Add(jitFlag); + } + _jitFlags = jitFlagBuilder.ToArray(); + + foreach (var param in parameters) + { + _config[param.Key] = param.Value; + } + + JitPath = jitPath; + UnmanagedInstance = CreateUnmanagedInstance(); + } + + public bool HasFlag(CorJitFlag flag) + { + foreach (CorJitFlag definedFlag in _jitFlags) + if (definedFlag == flag) + return true; + + return false; + } + + public int GetIntConfigValue(string name, int defaultValue) + { + // Note: Parse the string as hex + string stringValue; + int intValue; + if (_config.TryGetValue(name, out stringValue) && + Int32.TryParse(stringValue, NumberStyles.AllowHexSpecifier, null, out intValue)) + { + return intValue; + } + + return defaultValue; + } + + public string GetStringConfigValue(string name) + { + string stringValue; + if (_config.TryGetValue(name, out stringValue)) + { + return stringValue; + } + + return String.Empty; + } + + #region Unmanaged instance + + private unsafe IntPtr CreateUnmanagedInstance() + { + // TODO: this potentially leaks memory, but since we only expect to have one per compilation, + // it shouldn't matter... + + const int numCallbacks = 2; + + IntPtr* callbacks = (IntPtr*)Marshal.AllocCoTaskMem(sizeof(IntPtr) * numCallbacks); + object[] delegates = new object[numCallbacks]; + + var d0 = new __getIntConfigValue(getIntConfigValue); + callbacks[0] = Marshal.GetFunctionPointerForDelegate(d0); + delegates[0] = d0; + + var d1 = new __getStringConfigValue(getStringConfigValue); + callbacks[1] = Marshal.GetFunctionPointerForDelegate(d1); + delegates[1] = d1; + + _keepAlive = delegates; + IntPtr instance = Marshal.AllocCoTaskMem(sizeof(IntPtr)); + *(IntPtr**)instance = callbacks; + + return instance; + } + + [UnmanagedFunctionPointer(default(CallingConvention))] + private unsafe delegate int __getIntConfigValue(IntPtr thisHandle, [MarshalAs(UnmanagedType.LPWStr)] string name, int defaultValue); + private unsafe int getIntConfigValue(IntPtr thisHandle, string name, int defaultValue) + { + return GetIntConfigValue(name, defaultValue); + } + + [UnmanagedFunctionPointer(default(CallingConvention))] + private unsafe delegate int __getStringConfigValue(IntPtr thisHandle, [MarshalAs(UnmanagedType.LPWStr)] string name, char* retBuffer, int retBufferLength); + private unsafe int getStringConfigValue(IntPtr thisHandle, string name, char* retBuffer, int retBufferLength) + { + string result = GetStringConfigValue(name); + + for (int i = 0; i < Math.Min(retBufferLength, result.Length); i++) + retBuffer[i] = result[i]; + + return result.Length; + } + + #endregion + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/MemoryHelper.cs b/src/coreclr/src/tools/Common/JitInterface/MemoryHelper.cs new file mode 100644 index 00000000000..a9647f37fa7 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/MemoryHelper.cs @@ -0,0 +1,20 @@ +// 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; + +namespace Internal.JitInterface +{ + internal static unsafe class MemoryHelper + { + public static void FillMemory(byte* dest, byte fill, int count) + { + for (; count > 0; count--) + { + *dest = fill; + dest++; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/SystemVStructClassificator.cs b/src/coreclr/src/tools/Common/JitInterface/SystemVStructClassificator.cs new file mode 100644 index 00000000000..fe7f13deaef --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/SystemVStructClassificator.cs @@ -0,0 +1,607 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using ILCompiler; +using Internal.TypeSystem; + +namespace Internal.JitInterface +{ + using static SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR; + using static SystemVClassificationType; + + internal class SystemVStructClassificator + { + private Dictionary _classificationCache = new Dictionary(); + + private struct SystemVStructRegisterPassingHelper + { + internal SystemVStructRegisterPassingHelper(int totalStructSize) + { + StructSize = totalStructSize; + EightByteCount = 0; + InEmbeddedStruct = false; + CurrentUniqueOffsetField = 0; + LargestFieldOffset = -1; + + EightByteClassifications = new SystemVClassificationType[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; + EightByteSizes = new int[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; + EightByteOffsets = new int[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; + + FieldClassifications = new SystemVClassificationType[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; + FieldSizes = new int[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; + FieldOffsets = new int[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; + + for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++) + { + EightByteClassifications[i] = SystemVClassificationTypeNoClass; + EightByteSizes[i] = 0; + EightByteOffsets[i] = 0; + } + + // Initialize the work arrays + for (int i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++) + { + FieldClassifications[i] = SystemVClassificationTypeNoClass; + FieldSizes[i] = 0; + FieldOffsets[i] = 0; + } + } + + // Input state. + public int StructSize; + + // These fields are the output; these are what is computed by the classification algorithm. + public int EightByteCount; + public SystemVClassificationType[] EightByteClassifications; + public int[] EightByteSizes; + public int[] EightByteOffsets; + + // Helper members to track state. + public bool InEmbeddedStruct; + public int CurrentUniqueOffsetField; // A virtual field that could encompass many overlapping fields. + public int LargestFieldOffset; + public SystemVClassificationType[] FieldClassifications; + public int[] FieldSizes; + public int[] FieldOffsets; + }; + + private class FieldEnumerator + { + internal static IEnumerable GetInstanceFields(TypeDesc typeDesc, bool isFixedBuffer, int numIntroducedFields) + { + foreach (FieldDesc field in typeDesc.GetFields()) + { + if (field.IsStatic) + continue; + + if (isFixedBuffer) + { + for (int i = 0; i < numIntroducedFields; i++) + { + yield return field; + } + break; + } + else + { + yield return field; + } + } + } + } + + public unsafe bool getSystemVAmd64PassStructInRegisterDescriptor(TypeDesc typeDesc, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) + { + structPassInRegDescPtr->passedInRegisters = false; + + int typeSize = typeDesc.GetElementSize().AsInt; + if (typeDesc.IsValueType && (typeSize <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)) + { + Debug.Assert((TypeDef2SystemVClassification(typeDesc) == SystemVClassificationTypeStruct) || + (TypeDef2SystemVClassification(typeDesc) == SystemVClassificationTypeTypedReference)); + + if (_classificationCache.TryGetValue(typeDesc, out SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR descriptor)) + { + *structPassInRegDescPtr = descriptor; + } + else + { + SystemVStructRegisterPassingHelper helper = new SystemVStructRegisterPassingHelper(typeSize); + bool canPassInRegisters = ClassifyEightBytes(typeDesc, ref helper, 0); + if (canPassInRegisters) + { + structPassInRegDescPtr->passedInRegisters = canPassInRegisters; + structPassInRegDescPtr->eightByteCount = (byte)helper.EightByteCount; + Debug.Assert(structPassInRegDescPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS); + + structPassInRegDescPtr->eightByteClassifications0 = helper.EightByteClassifications[0]; + structPassInRegDescPtr->eightByteSizes0 = (byte)helper.EightByteSizes[0]; + structPassInRegDescPtr->eightByteOffsets0 = (byte)helper.EightByteOffsets[0]; + + structPassInRegDescPtr->eightByteClassifications1 = helper.EightByteClassifications[1]; + structPassInRegDescPtr->eightByteSizes1 = (byte)helper.EightByteSizes[1]; + structPassInRegDescPtr->eightByteOffsets1 = (byte)helper.EightByteOffsets[1]; + } + + _classificationCache.Add(typeDesc, *structPassInRegDescPtr); + } + } + + return true; + } + + private static SystemVClassificationType TypeDef2SystemVClassification(TypeDesc typeDesc) + { + if (typeDesc.IsWellKnownType(WellKnownType.TypedReference)) + { + // There is no category representing typed reference + return SystemVClassificationTypeTypedReference; + } + + switch (typeDesc.Category) + { + case TypeFlags.Boolean: + case TypeFlags.Char: + case TypeFlags.SByte: + case TypeFlags.Byte: + case TypeFlags.Int16: + case TypeFlags.UInt16: + case TypeFlags.Int32: + case TypeFlags.UInt32: + case TypeFlags.Int64: + case TypeFlags.UInt64: + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + case TypeFlags.Enum: + case TypeFlags.Pointer: + case TypeFlags.FunctionPointer: + return SystemVClassificationTypeInteger; + case TypeFlags.Single: + case TypeFlags.Double: + return SystemVClassificationTypeSSE; + case TypeFlags.ValueType: + case TypeFlags.Nullable: + return SystemVClassificationTypeStruct; + case TypeFlags.Class: + case TypeFlags.Interface: + case TypeFlags.Array: + case TypeFlags.SzArray: + return SystemVClassificationTypeIntegerReference; + case TypeFlags.ByRef: + return SystemVClassificationTypeIntegerByRef; + case TypeFlags.GenericParameter: + case TypeFlags.SignatureTypeVariable: + case TypeFlags.SignatureMethodVariable: + Debug.Assert(false, $"Type {typeDesc} with unexpected category {typeDesc.Category}"); + return SystemVClassificationTypeUnknown; + default: + return SystemVClassificationTypeUnknown; + } + } + + // If we have a field classification already, but there is a union, we must merge the classification type of the field. Returns the + // new, merged classification type. + static SystemVClassificationType ReClassifyField(SystemVClassificationType originalClassification, SystemVClassificationType newFieldClassification) + { + Debug.Assert((newFieldClassification == SystemVClassificationTypeInteger) || + (newFieldClassification == SystemVClassificationTypeIntegerReference) || + (newFieldClassification == SystemVClassificationTypeIntegerByRef) || + (newFieldClassification == SystemVClassificationTypeSSE)); + + switch (newFieldClassification) + { + case SystemVClassificationTypeInteger: + // Integer overrides everything; the resulting classification is Integer. Can't merge Integer and IntegerReference. + Debug.Assert((originalClassification == SystemVClassificationTypeInteger) || + (originalClassification == SystemVClassificationTypeSSE)); + + return SystemVClassificationTypeInteger; + + case SystemVClassificationTypeSSE: + // If the old and new classifications are both SSE, then the merge is SSE, otherwise it will be integer. Can't merge SSE and IntegerReference. + Debug.Assert((originalClassification == SystemVClassificationTypeInteger) || + (originalClassification == SystemVClassificationTypeSSE)); + + if (originalClassification == SystemVClassificationTypeSSE) + { + return SystemVClassificationTypeSSE; + } + else + { + return SystemVClassificationTypeInteger; + } + + case SystemVClassificationTypeIntegerReference: + // IntegerReference can only merge with IntegerReference. + Debug.Assert(originalClassification == SystemVClassificationTypeIntegerReference); + return SystemVClassificationTypeIntegerReference; + + case SystemVClassificationTypeIntegerByRef: + // IntegerByReference can only merge with IntegerByReference. + Debug.Assert(originalClassification == SystemVClassificationTypeIntegerByRef); + return SystemVClassificationTypeIntegerByRef; + + default: + Debug.Assert(false); // Unexpected type. + return SystemVClassificationTypeUnknown; + } + } + + /// + /// Returns 'true' if the struct is passed in registers, 'false' otherwise. + /// + private static bool ClassifyEightBytes(TypeDesc typeDesc, + ref SystemVStructRegisterPassingHelper helper, + int startOffsetOfStruct) + { + FieldDesc firstField = null; + int numIntroducedFields = 0; + foreach (FieldDesc field in typeDesc.GetFields()) + { + if (!field.IsStatic) + { + if (firstField == null) + { + firstField = field; + } + numIntroducedFields++; + } + } + + if (numIntroducedFields == 0) + { + return false; + } + + // The SIMD Intrinsic types are meant to be handled specially and should not be passed as struct registers + if (typeDesc.IsIntrinsic) + { + InstantiatedType instantiatedType = typeDesc as InstantiatedType; + if (instantiatedType != null) + { + if (VectorFieldLayoutAlgorithm.IsVectorType(instantiatedType) || + VectorFieldLayoutAlgorithm.IsVectorOfTType(instantiatedType)) + { + return false; + } + } + } + + MetadataType mdType = typeDesc as MetadataType; + Debug.Assert(mdType != null); + + TypeDesc firstFieldElementType = firstField.FieldType; + int firstFieldSize = firstFieldElementType.GetElementSize().AsInt; + + // A fixed buffer type is always a value type that has exactly one value type field at offset 0 + // and who's size is an exact multiple of the size of the field. + // It is possible that we catch a false positive with this check, but that chance is extremely slim + // and the user can always change their structure to something more descriptive of what they want + // instead of adding additional padding at the end of a one-field structure. + // We do this check here to save looking up the FixedBufferAttribute when loading the field + // from metadata. + bool isFixedBuffer = numIntroducedFields == 1 + && firstFieldElementType.IsValueType + && firstField.Offset.AsInt == 0 + && mdType.HasLayout() + && ((typeDesc.GetElementSize().AsInt % firstFieldSize) == 0); + + if (isFixedBuffer) + { + numIntroducedFields = typeDesc.GetElementSize().AsInt / firstFieldSize; + } + + int fieldIndex = 0; + foreach (FieldDesc field in FieldEnumerator.GetInstanceFields(typeDesc, isFixedBuffer, numIntroducedFields)) + { + Debug.Assert(fieldIndex < numIntroducedFields); + + int fieldOffset = isFixedBuffer ? fieldIndex * firstFieldSize : field.Offset.AsInt; + int normalizedFieldOffset = fieldOffset + startOffsetOfStruct; + + int fieldSize = field.FieldType.GetElementSize().AsInt; + + // The field can't span past the end of the struct. + if ((normalizedFieldOffset + fieldSize) > helper.StructSize) + { + Debug.Assert(false, "Invalid struct size. The size of fields and overall size don't agree"); + return false; + } + + SystemVClassificationType fieldClassificationType; + if (typeDesc.IsByReferenceOfT) + { + // ByReference is a special type whose single IntPtr field holds a by-ref potentially interior pointer to GC + // memory, so classify its field as such + Debug.Assert(numIntroducedFields == 1); + Debug.Assert(field.FieldType.IsWellKnownType(WellKnownType.IntPtr)); + + fieldClassificationType = SystemVClassificationTypeIntegerByRef; + } + else + { + fieldClassificationType = TypeDef2SystemVClassification(field.FieldType); + } + + if (fieldClassificationType == SystemVClassificationTypeStruct) + { + bool inEmbeddedStructPrev = helper.InEmbeddedStruct; + helper.InEmbeddedStruct = true; + + bool structRet = false; + structRet = ClassifyEightBytes(field.FieldType, ref helper, normalizedFieldOffset); + + helper.InEmbeddedStruct = inEmbeddedStructPrev; + + if (!structRet) + { + // If the nested struct says not to enregister, there's no need to continue analyzing at this level. Just return do not enregister. + return false; + } + + continue; + } + + if (fieldClassificationType == SystemVClassificationTypeTypedReference || + TypeDef2SystemVClassification(typeDesc) == SystemVClassificationTypeTypedReference) + { + // The TypedReference is a very special type. + // In source/metadata it has two fields - Type and Value and both are defined of type IntPtr. + // When the VM creates a layout of the type it changes the type of the Value to ByRef type and the + // type of the Type field is left to IntPtr (TYPE_I internally - native int type.) + // This requires a special treatment of this type. The code below handles the both fields (and this entire type). + + for (int i = 0; i < 2; i++) + { + fieldSize = 8; + fieldOffset = (i == 0 ? 0 : 8); + normalizedFieldOffset = fieldOffset + startOffsetOfStruct; + fieldClassificationType = (i == 0 ? SystemVClassificationTypeIntegerByRef : SystemVClassificationTypeInteger); + if ((normalizedFieldOffset % fieldSize) != 0) + { + // The spec requires that struct values on the stack from register passed fields expects + // those fields to be at their natural alignment. + return false; + } + + helper.LargestFieldOffset = (int)normalizedFieldOffset; + + // Set the data for a new field. + + // The new field classification must not have been initialized yet. + Debug.Assert(helper.FieldClassifications[helper.CurrentUniqueOffsetField] == SystemVClassificationTypeNoClass); + + helper.FieldClassifications[helper.CurrentUniqueOffsetField] = fieldClassificationType; + helper.FieldSizes[helper.CurrentUniqueOffsetField] = fieldSize; + helper.FieldOffsets[helper.CurrentUniqueOffsetField] = normalizedFieldOffset; + + helper.CurrentUniqueOffsetField++; + } + + // Both fields of the special TypedReference struct are handled. + // Done classifying the System.TypedReference struct fields. + break; + } + + if ((normalizedFieldOffset % fieldSize) != 0) + { + // The spec requires that struct values on the stack from register passed fields expects + // those fields to be at their natural alignment. + return false; + } + + if (normalizedFieldOffset <= helper.LargestFieldOffset) + { + // Find the field corresponding to this offset and update the size if needed. + // If the offset matches a previously encountered offset, update the classification and field size. + int i; + for (i = helper.CurrentUniqueOffsetField - 1; i >= 0; i--) + { + if (helper.FieldOffsets[i] == normalizedFieldOffset) + { + if (fieldSize > helper.FieldSizes[i]) + { + helper.FieldSizes[i] = fieldSize; + } + + helper.FieldClassifications[i] = ReClassifyField(helper.FieldClassifications[i], fieldClassificationType); + + break; + } + } + + if (i >= 0) + { + // The proper size of the union set of fields has been set above; continue to the next field. + continue; + } + } + else + { + helper.LargestFieldOffset = (int)normalizedFieldOffset; + } + + // Set the data for a new field. + + // The new field classification must not have been initialized yet. + Debug.Assert(helper.FieldClassifications[helper.CurrentUniqueOffsetField] == SystemVClassificationTypeNoClass); + + // There are only a few field classifications that are allowed. + Debug.Assert((fieldClassificationType == SystemVClassificationTypeInteger) || + (fieldClassificationType == SystemVClassificationTypeIntegerReference) || + (fieldClassificationType == SystemVClassificationTypeIntegerByRef) || + (fieldClassificationType == SystemVClassificationTypeSSE)); + + helper.FieldClassifications[helper.CurrentUniqueOffsetField] = fieldClassificationType; + helper.FieldSizes[helper.CurrentUniqueOffsetField] = fieldSize; + helper.FieldOffsets[helper.CurrentUniqueOffsetField] = normalizedFieldOffset; + + Debug.Assert(helper.CurrentUniqueOffsetField < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT); + helper.CurrentUniqueOffsetField++; + + fieldIndex++; + } + + AssignClassifiedEightByteTypes(ref helper); + + return true; + } + + // Assigns the classification types to the array with eightbyte types. + private static void AssignClassifiedEightByteTypes(ref SystemVStructRegisterPassingHelper helper) + { + const int CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS = CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS * SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; + Debug.Assert(CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS == SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT); + + if (!helper.InEmbeddedStruct) + { + int largestFieldOffset = helper.LargestFieldOffset; + Debug.Assert(largestFieldOffset != -1); + + // We're at the top level of the recursion, and we're done looking at the fields. + // Now sort the fields by offset and set the output data. + + int[] sortedFieldOrder = new int[CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS]; + for (int i = 0; i < CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS; i++) + { + sortedFieldOrder[i] = -1; + } + + int numFields = helper.CurrentUniqueOffsetField; + for (int i = 0; i < numFields; i++) + { + Debug.Assert(helper.FieldOffsets[i] < CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS); + Debug.Assert(sortedFieldOrder[helper.FieldOffsets[i]] == -1); // we haven't seen this field offset yet. + sortedFieldOrder[helper.FieldOffsets[i]] = i; + } + + // Calculate the eightbytes and their types. + + int lastFieldOrdinal = sortedFieldOrder[largestFieldOffset]; + int offsetAfterLastFieldByte = largestFieldOffset + helper.FieldSizes[lastFieldOrdinal]; + SystemVClassificationType lastFieldClassification = helper.FieldClassifications[lastFieldOrdinal]; + + int usedEightBytes = 0; + int accumulatedSizeForEightBytes = 0; + bool foundFieldInEightByte = false; + for (int offset = 0; offset < helper.StructSize; offset++) + { + SystemVClassificationType fieldClassificationType; + int fieldSize = 0; + + int ordinal = sortedFieldOrder[offset]; + if (ordinal == -1) + { + if (offset < accumulatedSizeForEightBytes) + { + // We're within a field and there is not an overlapping field that starts here. + // There's no work we need to do, so go to the next loop iteration. + continue; + } + + // If there is no field that starts as this offset and we are not within another field, + // treat its contents as padding. + // Any padding that follows the last field receives the same classification as the + // last field; padding between fields receives the NO_CLASS classification as per + // the SysV ABI spec. + fieldSize = 1; + fieldClassificationType = offset < offsetAfterLastFieldByte ? SystemVClassificationTypeNoClass : lastFieldClassification; + } + else + { + foundFieldInEightByte = true; + fieldSize = helper.FieldSizes[ordinal]; + Debug.Assert(fieldSize > 0); + + fieldClassificationType = helper.FieldClassifications[ordinal]; + Debug.Assert(fieldClassificationType != SystemVClassificationTypeMemory && fieldClassificationType != SystemVClassificationTypeUnknown); + } + + int fieldStartEightByte = offset / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; + int fieldEndEightByte = (offset + fieldSize - 1) / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; + + Debug.Assert(fieldEndEightByte < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS); + + usedEightBytes = Math.Max(usedEightBytes, fieldEndEightByte + 1); + + for (int currentFieldEightByte = fieldStartEightByte; currentFieldEightByte <= fieldEndEightByte; currentFieldEightByte++) + { + if (helper.EightByteClassifications[currentFieldEightByte] == fieldClassificationType) + { + // Do nothing. The eight-byte already has this classification. + } + else if (helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeNoClass) + { + helper.EightByteClassifications[currentFieldEightByte] = fieldClassificationType; + } + else if ((helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeInteger) || + (fieldClassificationType == SystemVClassificationTypeInteger)) + { + Debug.Assert((fieldClassificationType != SystemVClassificationTypeIntegerReference) && + (fieldClassificationType != SystemVClassificationTypeIntegerByRef)); + + helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeInteger; + } + else if ((helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeIntegerReference) || + (fieldClassificationType == SystemVClassificationTypeIntegerReference)) + { + helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeIntegerReference; + } + else if ((helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeIntegerByRef) || + (fieldClassificationType == SystemVClassificationTypeIntegerByRef)) + { + helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeIntegerByRef; + } + else + { + helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeSSE; + } + } + + if ((offset + 1) % SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES == 0) // If we just finished checking the last byte of an eightbyte + { + if (!foundFieldInEightByte) + { + // If we didn't find a field in an eight-byte (i.e. there are no explicit offsets that start a field in this eightbyte) + // then the classification of this eightbyte might be NoClass. We can't hand a classification of NoClass to the JIT + // so set the class to Integer (as though the struct has a char[8] padding) if the class is NoClass. + if (helper.EightByteClassifications[offset / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES] == SystemVClassificationTypeNoClass) + { + helper.EightByteClassifications[offset / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES] = SystemVClassificationTypeInteger; + } + } + + foundFieldInEightByte = false; + } + + accumulatedSizeForEightBytes = Math.Max(accumulatedSizeForEightBytes, offset + fieldSize); + } + + for (int currentEightByte = 0; currentEightByte < usedEightBytes; currentEightByte++) + { + int eightByteSize = accumulatedSizeForEightBytes < (SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES * (currentEightByte + 1)) + ? accumulatedSizeForEightBytes % SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES + : SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; + + // Save data for this eightbyte. + helper.EightByteSizes[currentEightByte] = eightByteSize; + helper.EightByteOffsets[currentEightByte] = currentEightByte * SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; + } + + helper.EightByteCount = usedEightBytes; + + Debug.Assert(helper.EightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS); + +#if DEBUG + for (int i = 0; i < helper.EightByteCount; i++) + { + Debug.Assert(helper.EightByteClassifications[i] != SystemVClassificationTypeNoClass); + } +#endif // DEBUG + } + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/Program.cs b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/Program.cs new file mode 100644 index 00000000000..499014b2337 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/Program.cs @@ -0,0 +1,509 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using System.Diagnostics; + +namespace Thunkerator +{ + // Parse type replacement section for normal types + // Parse type replacement section for return value types + + public static class StringExtensions + { + public static string Canonicalize(this string current) + { + string untrimmed = ""; + while (untrimmed != current) + { + untrimmed = current; + current = current.Replace(" *", "*"); + current = current.Replace("* ", "*"); + current = current.Replace(" ,", ","); + current = current.Replace(", ", ","); + current = current.Replace(" ", " "); + current = current.Replace("\t", " "); + } + + return current.Trim(); + } + } + + class TypeReplacement + { + public TypeReplacement(string line) + { + string[] typenames = line.Split(','); + if ((typenames.Length < 1) || (typenames.Length > 3)) + { + throw new Exception("Wrong number of type name entries"); + } + ThunkTypeName = typenames[0].Canonicalize(); + + if (typenames.Length > 1 && !string.IsNullOrWhiteSpace(typenames[1])) + { + ManagedTypeName = typenames[1].Canonicalize(); + } + else + { + ManagedTypeName = ThunkTypeName; + } + + if (typenames.Length > 2) + { + NativeTypeName = typenames[2].Canonicalize(); + } + else + { + NativeTypeName = ThunkTypeName; + } + } + public readonly string ThunkTypeName; + public readonly string NativeTypeName; + public readonly string ManagedTypeName; + } + + class Parameter + { + public Parameter(string name, TypeReplacement type) + { + Type = type; + Name = name; + if (name.StartsWith("*")) + throw new Exception("Names not allowed to start with *"); + } + + public readonly string Name; + public readonly TypeReplacement Type; + } + + class FunctionDecl + { + public FunctionDecl(string line, Dictionary ThunkReturnTypes, Dictionary ThunkTypes) + { + if (line.Contains("[ManualNativeWrapper]")) + { + ManualNativeWrapper = true; + line = line.Replace("[ManualNativeWrapper]", string.Empty); + } + + if (line.Contains("[ReturnAsParm]")) + { + ReturnAsParm = true; + line = line.Replace("[ReturnAsParm]", string.Empty); + } + + int indexOfOpenParen = line.IndexOf('('); + int indexOfCloseParen = line.IndexOf(')'); + string returnTypeAndFunctionName = line.Substring(0, indexOfOpenParen).Canonicalize(); + int indexOfLastWhitespaceInReturnTypeAndFunctionName = returnTypeAndFunctionName.LastIndexOfAny(new char[] { ' ', '*' }); + FunctionName = returnTypeAndFunctionName.Substring(indexOfLastWhitespaceInReturnTypeAndFunctionName + 1).Canonicalize(); + if (FunctionName.StartsWith("*")) + throw new Exception("Names not allowed to start with *"); + string returnType = returnTypeAndFunctionName.Substring(0, indexOfLastWhitespaceInReturnTypeAndFunctionName + 1).Canonicalize(); + + if (!ThunkReturnTypes.TryGetValue(returnType, out ReturnType)) + { + throw new Exception(String.Format("Type {0} unknown", returnType)); + } + + string parameterList = line.Substring(indexOfOpenParen + 1, indexOfCloseParen - indexOfOpenParen - 1).Canonicalize(); + string[] parametersString = parameterList.Length == 0 ? new string[0] : parameterList.Split(','); + List parameters = new List(); + + foreach (string parameterString in parametersString) + { + int indexOfLastWhitespaceInParameter = parameterString.LastIndexOfAny(new char[] { ' ', '*' }); + string paramName = parameterString.Substring(indexOfLastWhitespaceInParameter + 1).Canonicalize(); + string paramType = parameterString.Substring(0, indexOfLastWhitespaceInParameter + 1).Canonicalize(); + TypeReplacement tr; + if (!ThunkTypes.TryGetValue(paramType, out tr)) + { + throw new Exception(String.Format("Type {0} unknown", paramType)); + } + parameters.Add(new Parameter(paramName, tr)); + } + + Parameters = parameters.ToArray(); + } + + public readonly string FunctionName; + public readonly TypeReplacement ReturnType; + public readonly Parameter[] Parameters; + public readonly bool ManualNativeWrapper = false; + public readonly bool ReturnAsParm = false; + } + + class Program + { + enum ParseMode + { + RETURNTYPES, + NORMALTYPES, + FUNCTIONS, + IFDEFING + } + static IEnumerable ParseInput(TextReader tr) + { + Dictionary ThunkReturnTypes = new Dictionary(); + Dictionary ThunkTypes = new Dictionary(); + ParseMode currentParseMode = ParseMode.FUNCTIONS; + ParseMode oldParseMode = ParseMode.FUNCTIONS; + List functions = new List(); + int currentLineIndex = 1; + for (string currentLine = tr.ReadLine(); currentLine != null; currentLine = tr.ReadLine(), currentLineIndex++) + { + try + { + if (currentLine.Length == 0) + { + continue; // Its an empty line, ignore + } + + if (currentLine[0] == ';') + { + continue; // Its a comment + } + + if (currentLine == "RETURNTYPES") + { + currentParseMode = ParseMode.RETURNTYPES; + continue; + } + if (currentLine == "NORMALTYPES") + { + currentParseMode = ParseMode.NORMALTYPES; + continue; + } + if (currentLine == "FUNCTIONS") + { + currentParseMode = ParseMode.FUNCTIONS; + continue; + } + + if (currentLine == "#endif") + { + currentParseMode = oldParseMode; + continue; + } + + if (currentLine.StartsWith("#if")) + { + oldParseMode = currentParseMode; + currentParseMode = ParseMode.IFDEFING; + } + + if (currentParseMode == ParseMode.IFDEFING) + { + continue; + } + + switch (currentParseMode) + { + case ParseMode.NORMALTYPES: + case ParseMode.RETURNTYPES: + TypeReplacement t = new TypeReplacement(currentLine); + if (currentParseMode == ParseMode.NORMALTYPES) + { + ThunkTypes.Add(t.ThunkTypeName, t); + ThunkReturnTypes.Add(t.ThunkTypeName, t); + } + if (currentParseMode == ParseMode.RETURNTYPES) + { + ThunkReturnTypes[t.ThunkTypeName] = t; + } + break; + + case ParseMode.FUNCTIONS: + functions.Add(new FunctionDecl(currentLine, ThunkReturnTypes, ThunkTypes)); + break; + } + } + catch (Exception e) + { + Console.Error.WriteLine("Error parsing line {0} : {1}", currentLineIndex, e.Message); + } + } + + return functions.AsReadOnly(); + } + + static void WriteManagedThunkInterface(TextWriter tr, IEnumerable functionData) + { + // Write header + tr.Write(@" +// 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. + +// DO NOT EDIT THIS FILE! It IS AUTOGENERATED +using System; +using System.Runtime.InteropServices; + +namespace Internal.JitInterface +{ + unsafe partial class CorInfoImpl + { +"); + +#if false + foreach (FunctionDecl decl in functionData) + { + string returnType = decl.ReturnType.ManagedTypeName; + + tr.Write(" " + returnType + " " + decl.FunctionName + "("); + tr.Write("IntPtr thisHandle"); + foreach (Parameter param in decl.Parameters) + { + tr.Write(", "); + tr.Write(param.Type.ManagedTypeName + " " + param.Name); + } + tr.WriteLine(")"); + tr.WriteLine(" { throw new NotImplementedException(); }"); + } + tr.WriteLine(); +#endif + + foreach (FunctionDecl decl in functionData) + { + tr.WriteLine(" [UnmanagedFunctionPointerAttribute(default(CallingConvention))]"); + + string returnType = decl.ReturnAsParm ? "void" : decl.ReturnType.ManagedTypeName; + int marshalAs = returnType.LastIndexOf(']'); + string returnTypeWithDelegate = returnType.Insert((marshalAs != -1) ? (marshalAs + 1) : 0, "delegate "); + + tr.Write(" " + returnTypeWithDelegate + " " + "__" + decl.FunctionName + "("); + tr.Write("IntPtr _this"); + tr.Write(", IntPtr* ppException"); + if (decl.ReturnAsParm) + { + tr.Write(", out " + decl.ReturnType.ManagedTypeName + " _return"); + } + foreach (Parameter param in decl.Parameters) + { + tr.Write(", "); + tr.Write(param.Type.ManagedTypeName + " " + param.Name); + } + tr.WriteLine(");"); + } + tr.WriteLine(); + + foreach (FunctionDecl decl in functionData) + { + string returnType = decl.ReturnAsParm ? "void" : decl.ReturnType.ManagedTypeName; + int marshalAs = returnType.LastIndexOf(']'); + string returnTypeWithStatic = returnType.Insert((marshalAs != -1) ? (marshalAs + 1) : 0, "static "); + + tr.Write(" " + returnTypeWithStatic + " " + "_" + decl.FunctionName + "("); + tr.Write("IntPtr thisHandle"); + tr.Write(", IntPtr* ppException"); + if (decl.ReturnAsParm) + { + tr.Write(", out " + decl.ReturnType.ManagedTypeName + " _return"); + } + foreach (Parameter param in decl.Parameters) + { + tr.Write(", "); + tr.Write(param.Type.ManagedTypeName + " " + param.Name); + } + tr.Write(@") + { + var _this = GetThis(thisHandle); + try + { +"); + bool isVoid = decl.ReturnAsParm || decl.ReturnType.ManagedTypeName == "void"; + tr.Write(" " + (isVoid ? "" : "return ") + "_this." + decl.FunctionName + "("); + bool isFirst = true; + if (decl.ReturnAsParm) + { + tr.Write("out _return"); + isFirst = false; + } + foreach (Parameter param in decl.Parameters) + { + if (isFirst) + { + isFirst = false; + } + else + { + tr.Write(", "); + } + + if (param.Type.ManagedTypeName.Contains("ref ")) + { + tr.Write("ref "); + } + tr.Write(param.Name); + } + tr.Write(");"); + tr.Write(@" + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); +"); + if (!isVoid) + { + string retunTypeWithoutMarshalAs = marshalAs == -1 ? returnType : returnType.Substring(marshalAs + 1); + tr.WriteLine(" return default(" + retunTypeWithoutMarshalAs + ");"); + } + else if (decl.ReturnAsParm) + { + tr.WriteLine(" _return = default(" + decl.ReturnType.ManagedTypeName + ");"); + } + tr.WriteLine(@" }"); + tr.WriteLine(" }"); + tr.WriteLine(); + } + + int total = functionData.Count(); + tr.WriteLine(@" + static IntPtr GetUnmanagedCallbacks(out Object keepAlive) + { + IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * " + total + @"); + Object[] delegates = new Object[" + total + @"]; +"); + + int index = 0; + foreach (FunctionDecl decl in functionData) + { + tr.WriteLine(" var d" + index + " = new " + "__" + decl.FunctionName + "(" + "_" + decl.FunctionName + ");"); + tr.WriteLine(" callbacks[" + index + "] = Marshal.GetFunctionPointerForDelegate(d" + index + ");"); + tr.WriteLine(" delegates[" + index + "] = d" + index + ";"); + index++; + } + + tr.WriteLine(@" + keepAlive = delegates; + return (IntPtr)callbacks; + } + } +} +"); + } + + static void WriteNativeWrapperInterface(TextWriter tw, IEnumerable functionData) + { + tw.Write(@" +// 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. + +// DO NOT EDIT THIS FILE! It IS AUTOGENERATED +#include ""corinfoexception.h"" + +struct CORINFO_LOOKUP_KIND; + +struct JitInterfaceCallbacks +{ +"); + + foreach (FunctionDecl decl in functionData) + { + string returnType = decl.ReturnAsParm ? "void" : decl.ReturnType.NativeTypeName; + tw.Write(" " + returnType + " (* " + decl.FunctionName + ")("); + tw.Write("void * thisHandle"); + tw.Write(", CorInfoException** ppException"); + if (decl.ReturnAsParm) + { + tw.Write(", " + decl.ReturnType.NativeTypeName + "* _return"); + } + foreach (Parameter param in decl.Parameters) + { + tw.Write(", "); + tw.Write(param.Type.NativeTypeName + " " + param.Name); + } + tw.WriteLine(");"); + } + + tw.Write(@" +}; + +class JitInterfaceWrapper +{ + void * _thisHandle; + JitInterfaceCallbacks * _callbacks; + +public: + JitInterfaceWrapper(void * thisHandle, void ** callbacks) + : _thisHandle(thisHandle), _callbacks((JitInterfaceCallbacks *)callbacks) + { + } + +"); + + foreach (FunctionDecl decl in functionData) + { + tw.Write(" virtual " + decl.ReturnType.NativeTypeName + " " + decl.FunctionName + "("); + bool isFirst = true; + foreach (Parameter param in decl.Parameters) + { + if (isFirst) + { + isFirst = false; + } + else + { + tw.Write(", "); + } + tw.Write(param.Type.NativeTypeName + " " + param.Name); + } + tw.Write(')'); + + if (decl.ManualNativeWrapper) + { + tw.WriteLine(';'); + continue; + } + tw.Write(@" + { + CorInfoException* pException = nullptr; + "); + if (decl.ReturnType.NativeTypeName != "void") + { + tw.Write(decl.ReturnType.NativeTypeName + " _ret = "); + } + tw.Write("_callbacks->" + decl.FunctionName + "(_thisHandle, &pException"); + foreach (Parameter param in decl.Parameters) + { + tw.Write(", " + param.Name); + } + tw.Write(@"); + if (pException != nullptr) + throw pException; +"); + if (decl.ReturnType.NativeTypeName != "void") + { + tw.WriteLine(" return _ret;"); + } + tw.WriteLine(" }"); + tw.WriteLine(); + } + + tw.WriteLine("};"); + } + + static void Main(string[] args) + { + IEnumerable functions = ParseInput(new StreamReader(args[0])); + using (TextWriter tw = new StreamWriter(args[1])) + { + Console.WriteLine("Generating {0}", args[1]); + WriteManagedThunkInterface(tw, functions); + } + using (TextWriter tw = new StreamWriter(args[2])) + { + Console.WriteLine("Generating {0}", args[2]); + WriteNativeWrapperInterface(tw, functions); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj new file mode 100644 index 00000000000..958d2f1daae --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp3.0 + + + diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt new file mode 100644 index 00000000000..fffc0de16cd --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -0,0 +1,344 @@ +; 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. +; +; Thunk generator input file for generating the thunks from the C++ version of the +; jit interface to COM, into managed, and from COM to C++. +; +; The format of this file is as follows. +; There are NORMALTYPES, RETURNTYPES, and FUNCTIONS regions +; In the NORMALTYPES/RETURNTYPES region, each type is described. If a type is +; described in the NORMALTYPES section, but isn't described in the RETURNTYPES section +; then the NORMALTYPES description can be used for a return value. +; +; TYPES have three fields +; ThunkDescriptionType,ManagedType,NativeType +; If either ManagedType or NativeType are missing, then that form is replaced with ThunkDescriptionType. +; This feature allows reduction in type for enums and other types where the same type can be used in managed an native +; +; Specification of a custom native type is done to allow multiple translations of the same native type to managed. +; i.e. +; REFIntPointer,ref int *,int** +; and +; PointerToIntPointer,int**,int** +; +; Following the TYPES sections, there is the FUNCTIONS section +; Each function that is to be part of the interface is written here. The format is basically the C++ format +; without support for inline comments or sal annotations. +; +; Also, note that an empty line is ignored, and a line that begins with a ; is ignored. +; +; If the boilerplate around the individual functions needs adjustment, edit the thunk generator source code, and +; rebuild with rebuildthunkgen.cmd in the the ThunkGenerator subdir, then rebuildthunks.cmd +; If this file is editted, rebuild with rebuildthunks.cmd -- DO NOT RUN from within a razzle window. +; +NORMALTYPES +void +IEEMemoryManager*,void*,void* +LPVOID,void*,void* +void* +const void *,void* +HRESULT,,int +SIZE_T*,void*,size_t* +int +INT,int,int +INT32,int,int +UINT32,uint,unsigned int +ULONG32,uint,unsigned int +ULONG,uint,unsigned int +DWORD,uint,unsigned int +unsigned,uint +unsigned int, uint +size_t,UIntPtr +SIZE_T,UIntPtr,size_t +WORD,ushort,unsigned short +BOOL,[MarshalAs(UnmanagedType.Bool)]bool,int +bool,[MarshalAs(UnmanagedType.I1)]bool +const char *,byte* +mdMethodDef,mdToken,unsigned int +mdToken,,unsigned int +BYTE*,byte*,unsigned char* +GSCookie*,IntPtr*,void* +GSCookie**,IntPtr**,void** + +BOOL*,[MarshalAs(UnmanagedType.Bool)] ref bool,int* +bool*,[MarshalAs(UnmanagedType.U1)] ref bool +BoolStar,byte*,bool* +UINT32*,ref uint,unsigned int* +ULONG*,ref uint,unsigned long* +void **,ref void* +VOIDSTARSTAR,void **,void ** +ULONG32*,ref uint,unsigned int* +LONG*,int*,long* +char*,byte* +const char**,byte** +WCHAR**,short**,wchar_t** +LPCSTR,byte*,const char* +LPWSTR,short*,wchar_t* +LPCWSTR,short*,const wchar_t* +wchar_t*,short* +const wchar_t*,String + +DWORD**,ref uint*,unsigned int** +unsigned*,ref uint +DWORD*,ref uint,unsigned int* +CORJIT_FLAGS*,ref CORJIT_FLAGS,void* +CORINFO_CONST_LOOKUP*,ref CORINFO_CONST_LOOKUP,void* +CORINFO_LOOKUP*,ref CORINFO_LOOKUP,void* +CORINFO_LOOKUP_KIND*,ref CORINFO_LOOKUP_KIND,void* +CORINFO_EH_CLAUSE*,ref CORINFO_EH_CLAUSE,void* +const CORINFO_EH_CLAUSE*,ref CORINFO_EH_CLAUSE,void* +CORINFO_SIG_INFO*,,void* +CORINFO_RESOLVED_TOKEN*,ref CORINFO_RESOLVED_TOKEN,void* +CORINFO_RESOLVED_TOKEN_PTR,CORINFO_RESOLVED_TOKEN*,void* +CORINFO_EE_INFO*,ref CORINFO_EE_INFO,void* +CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT,void* +CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO*,void* +CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO*,void* +CORINFO_CALL_INFO*,CORINFO_CALL_INFO*,void* +DelegateCtorArgs*,ref DelegateCtorArgs,void* +ICorDynamicInfo*,IntPtr,void* +va_list,IntPtr +CORINFO_HELPER_DESC*,ref CORINFO_HELPER_DESC,void* +const CORINFO_HELPER_DESC*,ref CORINFO_HELPER_DESC,const void* +int*,ref int +unsigned int*,ref uint + +CORINFO_JUST_MY_CODE_HANDLE**,ref CORINFO_JUST_MY_CODE_HANDLE_*,void** + +ICorJitInfo::BlockCounts**,ref BlockCounts*,void** + +; Enums +CorInfoCanSkipVerificationResult,,int +CorInfoClassId,,int +CorInfoHelperTailCallSpecialHandling,,int +CorInfoHelpFunc,,int +CorInfoInitClassResult,,int +CorInfoInlineTypeCheck,,int +CorInfoInlineTypeCheckSource,,int +CorInfoInline,,int +CorInfoInstantiationVerification,,int +CorInfoIntrinsics,,int +CorInfoIsAccessAllowedResult,,int +CorInfoMethodRuntimeFlags,,int +CorInfoTailCall,,int +CorInfoType,,int +CorInfoTypeWithMod,,int +CorInfoUnmanagedCallConv,,int +InfoAccessType,,int +CORINFO_LOOKUP_KIND +CORINFO_ACCESS_FLAGS,,int +CORINFO_CALLINFO_FLAGS,,int +CorJitAllocMemFlag,,int +CorJitFuncKind,,int +CorJitResult,,int +TypeCompareState,,int + +; Handle types +CORINFO_MODULE_HANDLE,CORINFO_MODULE_STRUCT_*,void* +CORINFO_METHOD_HANDLE,CORINFO_METHOD_STRUCT_*,void* +CORINFO_FIELD_HANDLE,CORINFO_FIELD_STRUCT_*,void* +CORINFO_CLASS_HANDLE,CORINFO_CLASS_STRUCT_*,void* +CORINFO_ASSEMBLY_HANDLE,CORINFO_ASSEMBLY_STRUCT_*,void* +CORINFO_JUST_MY_CODE_HANDLE,CORINFO_JUST_MY_CODE_HANDLE_*,void* +CORINFO_MODULE_HANDLE*,CORINFO_MODULE_STRUCT_**,void* +CORINFO_CLASS_HANDLE*,CORINFO_CLASS_STRUCT_**,void* +CORINFO_ARG_LIST_HANDLE,CORINFO_ARG_LIST_STRUCT_*,void* +CORINFO_VARARGS_HANDLE,IntPtr,void* +CORINFO_CONTEXT_HANDLE,CORINFO_CONTEXT_STRUCT*,void* +SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*,SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*,void* + +ICorDebugInfo::OffsetMapping*,OffsetMapping*,void* +ICorDebugInfo::ILVarInfo**,ILVarInfo**,void* +ICorDebugInfo::NativeVarInfo*,NativeVarInfo*,void* +ICorDebugInfo::BoundaryTypes*,BoundaryTypes*,void* + +struct _EXCEPTION_POINTERS*,_EXCEPTION_POINTERS*,void* + +RETURNTYPES +BOOL,[return: MarshalAs(UnmanagedType.Bool)]bool,int +bool,[return: MarshalAs(UnmanagedType.I1)]bool +LPCWSTR,[return: MarshalAs(UnmanagedType.LPWStr)]string,const wchar_t* +; NOTE in managed SIZE_T is an enum that is 64bits in size, and returning one of those causing mcg to do the wrong thing. +size_t,byte*,size_t + +FUNCTIONS + DWORD getMethodAttribs( CORINFO_METHOD_HANDLE ftn ); + void setMethodAttribs( CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs ); + void getMethodSig( CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO *sig, CORINFO_CLASS_HANDLE memberParent ); + bool getMethodInfo( CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info ); + CorInfoInline canInline( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd, DWORD* pRestrictions ); + void reportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, CorInfoInline inlineResult, const char * reason); + bool canTailCall( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE declaredCalleeHnd, CORINFO_METHOD_HANDLE exactCalleeHnd, bool fIsTailPrefix ); + void reportTailCallDecision(CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, const char * reason); + void getEHinfo( CORINFO_METHOD_HANDLE ftn, unsigned EHnumber, CORINFO_EH_CLAUSE* clause ); + CORINFO_CLASS_HANDLE getMethodClass( CORINFO_METHOD_HANDLE method ); + CORINFO_MODULE_HANDLE getMethodModule( CORINFO_METHOD_HANDLE method ); + void getMethodVTableOffset( CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, unsigned* offsetAfterIndirection, bool* isRelative); + CORINFO_METHOD_HANDLE resolveVirtualMethod( CORINFO_METHOD_HANDLE virtualMethod, CORINFO_CLASS_HANDLE implementingClass, CORINFO_CONTEXT_HANDLE ownerType); + CORINFO_METHOD_HANDLE getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, BoolStar requiresInstMethodTableArg); + CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType); + void expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_GENERICHANDLE_RESULT * pResult); + CorInfoIntrinsics getIntrinsicID( CORINFO_METHOD_HANDLE method , BoolStar pMustExpand); + bool isIntrinsicType( 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 ); + CorInfoInstantiationVerification isInstantiationOfVerifiedGeneric( CORINFO_METHOD_HANDLE method ); + void initConstraintsForVerification( CORINFO_METHOD_HANDLE method, BOOL *pfHasCircularClassConstraints, BOOL *pfHasCircularMethodConstraint ); + CorInfoCanSkipVerificationResult canSkipMethodVerification( CORINFO_METHOD_HANDLE ftnHandle ); + void methodMustBeLoadedBeforeCodeIsRun( CORINFO_METHOD_HANDLE method ); + CORINFO_METHOD_HANDLE mapMethodDeclToMethodImpl( CORINFO_METHOD_HANDLE method ); + void getGSCookie( GSCookie * pCookieVal, GSCookie ** ppCookieVal ); + void resolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken); + void tryResolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken); + void findSig( CORINFO_MODULE_HANDLE module, unsigned sigTOK, CORINFO_CONTEXT_HANDLE context, CORINFO_SIG_INFO *sig ); + void findCallSiteSig( CORINFO_MODULE_HANDLE module,unsigned methTOK, CORINFO_CONTEXT_HANDLE context, CORINFO_SIG_INFO *sig) + CORINFO_CLASS_HANDLE getTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken) + CorInfoCanSkipVerificationResult canSkipVerification(CORINFO_MODULE_HANDLE module) + BOOL isValidToken(CORINFO_MODULE_HANDLE module, unsigned metaTOK) + BOOL isValidStringRef(CORINFO_MODULE_HANDLE module, unsigned metaTOK) + BOOL shouldEnforceCallvirtRestriction(CORINFO_MODULE_HANDLE scope) + CorInfoType asCorInfoType(CORINFO_CLASS_HANDLE cls) + const char* getClassName(CORINFO_CLASS_HANDLE cls) + const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char **namespaceName) + CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) + int appendClassName(WCHAR** ppBuf, int* pnBufLen, CORINFO_CLASS_HANDLE cls, BOOL fNamespace, BOOL fFullInst, BOOL fAssembly) + BOOL isValueClass(CORINFO_CLASS_HANDLE cls) + CorInfoInlineTypeCheck canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source) + BOOL canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls) + DWORD getClassAttribs(CORINFO_CLASS_HANDLE cls) + BOOL isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE cls) + CORINFO_MODULE_HANDLE getClassModule(CORINFO_CLASS_HANDLE cls) + CORINFO_ASSEMBLY_HANDLE getModuleAssembly(CORINFO_MODULE_HANDLE mod) + const char* getAssemblyName(CORINFO_ASSEMBLY_HANDLE assem) + void* LongLifetimeMalloc(size_t sz) + void LongLifetimeFree(void* obj) + size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection) + unsigned getClassSize(CORINFO_CLASS_HANDLE cls) + unsigned getHeapClassSize(CORINFO_CLASS_HANDLE cls) + BOOL canAllocateOnStack(CORINFO_CLASS_HANDLE cls) + unsigned getClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, BOOL fDoubleAlignHint) + unsigned getClassGClayout(CORINFO_CLASS_HANDLE cls, BYTE* gcPtrs) + unsigned getClassNumInstanceFields(CORINFO_CLASS_HANDLE cls) + CORINFO_FIELD_HANDLE getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num) + BOOL checkMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, BOOL fOptional) + CorInfoHelpFunc getNewHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, BoolStar pHasSideEffects) + CorInfoHelpFunc getNewArrHelper(CORINFO_CLASS_HANDLE arrayCls) + CorInfoHelpFunc getCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing) + CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd) + CorInfoHelpFunc getSecurityPrologHelper(CORINFO_METHOD_HANDLE ftn) + CORINFO_CLASS_HANDLE getTypeForBox(CORINFO_CLASS_HANDLE cls) + CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_HANDLE cls) + CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_HANDLE cls) + bool getReadyToRunHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pGenericLookupKind, CorInfoHelpFunc id, CORINFO_CONST_LOOKUP *pLookup) + void getReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN * pTargetMethod, CORINFO_CLASS_HANDLE delegateType, CORINFO_LOOKUP *pLookup) + const char* getHelperName(CorInfoHelpFunc helpFunc) + CorInfoInitClassResult initClass(CORINFO_FIELD_HANDLE field, CORINFO_METHOD_HANDLE method, CORINFO_CONTEXT_HANDLE context, BOOL speculative) + void classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE cls) + CORINFO_CLASS_HANDLE getBuiltinClass(CorInfoClassId classId) + CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) + CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls) + BOOL canCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent) + BOOL areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) + TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) + TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) + CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) + BOOL isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) + CORINFO_CLASS_HANDLE getParentType(CORINFO_CLASS_HANDLE cls) + CorInfoType getChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet) + BOOL satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls) + BOOL isSDArray(CORINFO_CLASS_HANDLE cls) + unsigned getArrayRank(CORINFO_CLASS_HANDLE cls) + void* getArrayInitializationData(CORINFO_FIELD_HANDLE field, DWORD size) + CorInfoIsAccessAllowedResult canAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_HELPER_DESC* pAccessHelper) + const char* getFieldName(CORINFO_FIELD_HANDLE ftn, const char** moduleName) + CORINFO_CLASS_HANDLE getFieldClass(CORINFO_FIELD_HANDLE field) + CorInfoType getFieldType(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType, CORINFO_CLASS_HANDLE memberParent) + unsigned getFieldOffset(CORINFO_FIELD_HANDLE field) + bool isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field) + void getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) + void getBoundaries(CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, DWORD** pILOffsets, ICorDebugInfo::BoundaryTypes* implictBoundaries) + void setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping* pMap) + void getVars(CORINFO_METHOD_HANDLE ftn, ULONG32* cVars, ICorDebugInfo::ILVarInfo** vars, bool* extendOthers) + void setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars) + void*allocateArray(ULONG cBytes); + void freeArray(void*array); + CORINFO_ARG_LIST_HANDLE getArgNext(CORINFO_ARG_LIST_HANDLE args); + CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args, CORINFO_CLASS_HANDLE* vcTypeRet); + CORINFO_CLASS_HANDLE getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args); + CorInfoType getHFAType(CORINFO_CLASS_HANDLE hClass); + HRESULT GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers); + ULONG GetErrorMessage(LPWSTR buffer, ULONG bufferLength); + [ManualNativeWrapper] int FilterException(struct _EXCEPTION_POINTERS* pExceptionPointers); + [ManualNativeWrapper] void HandleException(struct _EXCEPTION_POINTERS* pExceptionPointers); + void ThrowExceptionForJitResult(HRESULT result); + void ThrowExceptionForHelper(const CORINFO_HELPER_DESC* throwHelper); + [ManualNativeWrapper] bool runWithErrorTrap(void* function, void* parameter); + void getEEInfo(CORINFO_EE_INFO* pEEInfoOut); + LPCWSTR getJitTimeLogFilename(); + mdMethodDef getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod); + const char* getMethodName(CORINFO_METHOD_HANDLE ftn, const char **moduleName); + const char* getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, const char **className, const char **namespaceName, const char **enclosingClassName); + unsigned getMethodHash(CORINFO_METHOD_HANDLE ftn); + size_t findNameOfToken(CORINFO_MODULE_HANDLE moduleHandle,mdToken token, char * szFQName,size_t FQNameCapacity); + bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); + DWORD getThreadTLSIndex(void **ppIndirection); + const void * getInlinedCallFrameVptr(void **ppIndirection); + LONG * getAddrOfCaptureThreadGlobal(void **ppIndirection); + 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); + void* getMethodSync(CORINFO_METHOD_HANDLE ftn, void **ppIndirection); + CorInfoHelpFunc getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle); + CORINFO_MODULE_HANDLE embedModuleHandle(CORINFO_MODULE_HANDLE handle, void **ppIndirection); + CORINFO_CLASS_HANDLE embedClassHandle(CORINFO_CLASS_HANDLE handle, void **ppIndirection); + CORINFO_METHOD_HANDLE embedMethodHandle(CORINFO_METHOD_HANDLE handle, void **ppIndirection); + CORINFO_FIELD_HANDLE embedFieldHandle(CORINFO_FIELD_HANDLE handle, void **ppIndirection); + void embedGenericHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, BOOL fEmbedParent, CORINFO_GENERICHANDLE_RESULT * pResult); + [ManualNativeWrapper] [ReturnAsParm] CORINFO_LOOKUP_KIND getLocationOfThisType(CORINFO_METHOD_HANDLE context); + void* getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method, void **ppIndirection); + void* getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method, void **ppIndirection); + void getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP *pLookup); + LPVOID GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void ** ppIndirection); + bool canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig); + CORINFO_JUST_MY_CODE_HANDLE getJustMyCodeHandle(CORINFO_METHOD_HANDLE method, CORINFO_JUST_MY_CODE_HANDLE**ppIndirection); + void GetProfilingHandle(BOOL *pbHookFunction, void **pProfilerHandle, BOOL *pbIndirectedHandles); + void getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_RESOLVED_TOKEN_PTR pConstrainedResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO *pResult); + BOOL canAccessFamily(CORINFO_METHOD_HANDLE hCaller, CORINFO_CLASS_HANDLE hInstanceType); + BOOL isRIDClassDomainID(CORINFO_CLASS_HANDLE cls); + unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection); + void* getFieldAddress(CORINFO_FIELD_HANDLE field, VOIDSTARSTAR ppIndirection); + CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, BoolStar pIsSpeculative); + CORINFO_VARARGS_HANDLE getVarArgsHandle(CORINFO_SIG_INFO *pSig, void **ppIndirection); + bool canGetVarArgsHandle(CORINFO_SIG_INFO *pSig); + InfoAccessType constructStringLiteral(CORINFO_MODULE_HANDLE module, mdToken metaTok, void **ppValue); + InfoAccessType emptyStringLiteral(void **ppValue); + DWORD getFieldThreadLocalStoreID (CORINFO_FIELD_HANDLE field, void **ppIndirection); + void setOverride(ICorDynamicInfo *pOverride, CORINFO_METHOD_HANDLE currentMethod); + void addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom, CORINFO_MODULE_HANDLE moduleTo); + CORINFO_METHOD_HANDLE GetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE targetMethodHnd, DelegateCtorArgs * pCtorData); + void MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd); + void* getTailCallCopyArgsThunk (CORINFO_SIG_INFO *pSig, CorInfoHelperTailCallSpecialHandling flags); + bool convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool mustConvert); + [ManualNativeWrapper] IEEMemoryManager* getMemoryManager(); + void allocMem( ULONG hotCodeSize, ULONG coldCodeSize, ULONG roDataSize, ULONG xcptnsCount, CorJitAllocMemFlag flag, void** hotCodeBlock, void** coldCodeBlock, void** roDataBlock ); + void reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize) + void allocUnwindInfo(BYTE* pHotCode, BYTE* pColdCode, ULONG startOffset, ULONG endOffset, ULONG unwindSize, BYTE* pUnwindBlock, CorJitFuncKind funcKind) + void* allocGCInfo(size_t size) + void yieldExecution() + void setEHcount(unsigned cEH) + void setEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause) + BOOL logMsg(unsigned level, const char* fmt, va_list args) + int doAssert(const char* szFile, int iLine, const char* szExpr) + void reportFatalError(CorJitResult result) + HRESULT allocMethodBlockCounts(UINT32 count, ICorJitInfo::BlockCounts** pBlockCounts) + HRESULT getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, UINT32* pCount, ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns) + void recordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle) + void recordRelocation(void* location, void* target, WORD fRelocType, WORD slotNum, INT32 addlDelta) + WORD getRelocTypeHint(void* target) + void getModuleNativeEntryPointRange(void** pStart, void** pEnd) + DWORD getExpectedTargetArchitecture() + DWORD getJitFlags(CORJIT_FLAGS* flags, DWORD sizeInBytes) diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat new file mode 100644 index 00000000000..2fec5117581 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat @@ -0,0 +1,2 @@ +cd /d %~dp0 +dotnet run -- ThunkInput.txt ..\CorInfoBase.cs ..\..\..\jitinterface\jitinterface.h \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.sh b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.sh new file mode 100755 index 00000000000..3eb458d6200 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +cd "$(dirname ${BASH_SOURCE[0]})" +dotnet run -- ThunkInput.txt ../CorInfoBase.cs ../../../jitinterface/jitinterface.h diff --git a/src/coreclr/src/tools/Common/JitInterface/TypeString.cs b/src/coreclr/src/tools/Common/JitInterface/TypeString.cs new file mode 100644 index 00000000000..52a9dcfb957 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/TypeString.cs @@ -0,0 +1,113 @@ +// 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.Text; + +using Internal.TypeSystem; + +namespace Internal.JitInterface +{ + // This is a very rough equivalent of typestring.cpp in the CLR. + // There's way more rules to capture. Hopefully, we'll only ever need this in the code to recognize SIMD intrisics + // and we won't need to replicate all the details around escaping and such. + internal class TypeString : TypeNameFormatter + { + public static TypeString Instance { get; } = new TypeString(); + + public override void AppendName(StringBuilder sb, PointerType type) + { + AppendName(sb, type.ParameterType); + sb.Append('*'); + } + + public override void AppendName(StringBuilder sb, GenericParameterDesc type) + { + string prefix = type.Kind == GenericParameterKind.Type ? "!" : "!!"; + sb.Append(prefix); + sb.Append(type.Name); + } + + public override void AppendName(StringBuilder sb, SignatureTypeVariable type) + { + sb.Append("!"); + sb.Append(type.Index); + } + + public override void AppendName(StringBuilder sb, SignatureMethodVariable type) + { + sb.Append("!!"); + sb.Append(type.Index); + } + + public override void AppendName(StringBuilder sb, FunctionPointerType type) + { + MethodSignature signature = type.Signature; + + AppendName(sb, signature.ReturnType); + + sb.Append(" ("); + for (int i = 0; i < signature.Length; i++) + { + if (i > 0) + sb.Append(", "); + AppendName(sb, signature[i]); + } + + sb.Append(')'); + } + + public override void AppendName(StringBuilder sb, ByRefType type) + { + AppendName(sb, type.ParameterType); + sb.Append("&"); + } + + public override void AppendName(StringBuilder sb, ArrayType type) + { + AppendName(sb, type.ElementType); + sb.Append('['); + + int rank = type.Rank; + if (rank == 1 && type.IsMdArray) + sb.Append('*'); + else + sb.Append(',', type.Rank - 1); + + sb.Append(']'); + } + + protected override void AppendNameForInstantiatedType(StringBuilder sb, DefType type) + { + AppendName(sb, type.GetTypeDefinition()); + sb.Append('['); + + for (int i = 0; i < type.Instantiation.Length; i++) + { + if (i > 0) + sb.Append(", "); + AppendName(sb, type.Instantiation[i]); + } + + sb.Append(']'); + } + + protected override void AppendNameForNamespaceType(StringBuilder sb, DefType type) + { + string ns = type.Namespace; + if (ns.Length > 0) + { + sb.Append(ns); + sb.Append('.'); + } + sb.Append(type.Name); + } + + protected override void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType) + { + AppendName(sb, containingType); + sb.Append('+'); + sb.Append(nestedType.Name); + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/UnboxingMethodDesc.cs b/src/coreclr/src/tools/Common/JitInterface/UnboxingMethodDesc.cs new file mode 100644 index 00000000000..2710f163b03 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/UnboxingMethodDesc.cs @@ -0,0 +1,108 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using Internal.TypeSystem; + +namespace Internal.JitInterface +{ + /// + /// Represents the unboxing entrypoint of a valuetype instance method. + /// This class is for internal purposes within the JitInterface. It's not expected + /// for it to escape the JitInterface. + /// + internal class UnboxingMethodDesc : MethodDelegator + { + private readonly UnboxingMethodDescFactory _factory; + + public MethodDesc Target => _wrappedMethod; + + public UnboxingMethodDesc(MethodDesc wrappedMethod, UnboxingMethodDescFactory factory) + : base(wrappedMethod) + { + Debug.Assert(wrappedMethod.OwningType.IsValueType); + Debug.Assert(!wrappedMethod.Signature.IsStatic); + _factory = factory; + } + + public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) + { + MethodDesc realCanonTarget = _wrappedMethod.GetCanonMethodTarget(kind); + if (realCanonTarget != _wrappedMethod) + return _factory.GetUnboxingMethod(realCanonTarget); + + return this; + } + + public override MethodDesc GetMethodDefinition() + { + MethodDesc realMethodDefinition = _wrappedMethod.GetMethodDefinition(); + if (realMethodDefinition != _wrappedMethod) + return _factory.GetUnboxingMethod(realMethodDefinition); + + return this; + } + + public override MethodDesc GetTypicalMethodDefinition() + { + MethodDesc realTypicalMethodDefinition = _wrappedMethod.GetTypicalMethodDefinition(); + if (realTypicalMethodDefinition != _wrappedMethod) + return _factory.GetUnboxingMethod(realTypicalMethodDefinition); + + return this; + } + + public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + MethodDesc realInstantiateSignature = _wrappedMethod.InstantiateSignature(typeInstantiation, methodInstantiation); + if (realInstantiateSignature != _wrappedMethod) + return _factory.GetUnboxingMethod(realInstantiateSignature); + + return this; + } + + public override string ToString() + { + return "Unboxing MethodDesc: " + _wrappedMethod.ToString(); + } + +#if !SUPPORT_JIT + protected override int ClassCode => throw new NotImplementedException(); + + protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) + { + throw new NotImplementedException(); + } +#endif + } + + internal class UnboxingMethodDescFactory : Dictionary + { + public UnboxingMethodDesc GetUnboxingMethod(MethodDesc method) + { + if (!TryGetValue(method, out UnboxingMethodDesc result)) + { + result = new UnboxingMethodDesc(method, this); + Add(method, result); + } + + return result; + } + } + + internal static class UnboxingMethodDescExtensions + { + public static bool IsUnboxingThunk(this MethodDesc method) + { + return method is UnboxingMethodDesc; + } + + public static MethodDesc GetUnboxedMethod(this MethodDesc method) + { + return ((UnboxingMethodDesc)method).Target; + } + } +} diff --git a/src/coreclr/src/tools/Common/System/Collections/Generic/ArrayBuilder.cs b/src/coreclr/src/tools/Common/System/Collections/Generic/ArrayBuilder.cs new file mode 100644 index 00000000000..07548eff7ff --- /dev/null +++ b/src/coreclr/src/tools/Common/System/Collections/Generic/ArrayBuilder.cs @@ -0,0 +1,109 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace System.Collections.Generic +{ + /// + /// Helper class for building lists that avoids unnecessary allocation + /// + internal struct ArrayBuilder + { + private T[] _items; + private int _count; + + public T[] ToArray() + { + if (_items == null) + return Array.Empty(); + if (_count != _items.Length) + Array.Resize(ref _items, _count); + return _items; + } + + public void Add(T item) + { + if (_items == null || _count == _items.Length) + Array.Resize(ref _items, 2 * _count + 1); + _items[_count++] = item; + } + + public void Append(T[] newItems) + { + Append(newItems, 0, newItems.Length); + } + + public void Append(T[] newItems, int offset, int length) + { + if (length == 0) + return; + + Debug.Assert(length > 0); + Debug.Assert(newItems.Length >= offset + length); + + EnsureCapacity(_count + length); + Array.Copy(newItems, offset, _items, _count, length); + _count += length; + } + + public void Append(ArrayBuilder newItems) + { + if (newItems.Count == 0) + return; + EnsureCapacity(_count + newItems.Count); + Array.Copy(newItems._items, 0, _items, _count, newItems.Count); + _count += newItems.Count; + } + + public void ZeroExtend(int numItems) + { + Debug.Assert(numItems >= 0); + EnsureCapacity(_count + numItems); + _count += numItems; + } + + public void EnsureCapacity(int requestedCapacity) + { + if (requestedCapacity > ((_items != null) ? _items.Length : 0)) + { + int newCount = Math.Max(2 * _count + 1, requestedCapacity); + Array.Resize(ref _items, newCount); + } + } + + public int Count + { + get + { + return _count; + } + } + + public T this[int index] + { + get + { + return _items[index]; + } + set + { + _items[index] = value; + } + } + + public bool Contains(T t) + { + for (int i = 0; i < _count; i++) + { + if (_items[i].Equals(t)) + { + return true; + } + } + + return false; + } + } +} diff --git a/src/coreclr/src/tools/Common/System/FormattingHelpers.cs b/src/coreclr/src/tools/Common/System/FormattingHelpers.cs new file mode 100644 index 00000000000..de7a6370a0a --- /dev/null +++ b/src/coreclr/src/tools/Common/System/FormattingHelpers.cs @@ -0,0 +1,21 @@ +// 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.Globalization; + +namespace System +{ + internal static class FormattingHelpers + { + public static string ToStringInvariant(this T value) where T : IConvertible + { + return value.ToString(CultureInfo.InvariantCulture); + } + + public static string ToStringInvariant(this T value, string format) where T : IFormattable + { + return value.ToString(format, CultureInfo.InvariantCulture); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/ArrayType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/ArrayType.Canon.cs new file mode 100644 index 00000000000..04bd817fa7d --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/ArrayType.Canon.cs @@ -0,0 +1,41 @@ +// 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 +{ + // Implements canonicalization for arrays + partial class ArrayType + { + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + TypeDesc paramTypeConverted = Context.ConvertToCanon(ParameterType, kind); + if (paramTypeConverted != ParameterType) + { + // Note: don't use the Rank property here, as that hides the difference + // between a single dimensional MD array and an SZArray. + return Context.GetArrayType(paramTypeConverted, _rank); + } + + return this; + } + } + + // Implements canonicalization for array methods + partial class ArrayMethod + { + public override bool IsCanonicalMethod(CanonicalFormKind policy) + { + return _owningType.IsCanonicalSubtype(policy); + } + + public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) + { + TypeDesc canonicalizedTypeOfTargetMethod = _owningType.ConvertToCanonForm(kind); + if (canonicalizedTypeOfTargetMethod == _owningType) + return this; + + return ((ArrayType)canonicalizedTypeOfTargetMethod).GetArrayMethod(_kind); + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/ByRefType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/ByRefType.Canon.cs new file mode 100644 index 00000000000..921eb901487 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/ByRefType.Canon.cs @@ -0,0 +1,19 @@ +// 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 +{ + // Implements canonicalizing ByRefs + partial class ByRefType + { + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + TypeDesc paramTypeConverted = Context.ConvertToCanon(ParameterType, kind); + if (paramTypeConverted != ParameterType) + return Context.GetByRefType(paramTypeConverted); + + return this; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs new file mode 100644 index 00000000000..3c4098cb4d0 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs @@ -0,0 +1,49 @@ +// 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.Collections.Generic; + +using Internal.NativeFormat; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + internal sealed partial class CanonType + { + public override string DiagnosticName + { + get + { + return _Name; + } + } + public override string DiagnosticNamespace + { + get + { + return _Namespace; + } + } + } + + internal sealed partial class UniversalCanonType + { + public override string DiagnosticName + { + get + { + return _Name; + } + } + public override string DiagnosticNamespace + { + get + { + return _Namespace; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Interop.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Interop.cs new file mode 100644 index 00000000000..cca6403d0c0 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Interop.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 +{ + partial class CanonBaseType + { + public override PInvokeStringFormat PInvokeStringFormat => default(PInvokeStringFormat); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Sorting.cs new file mode 100644 index 00000000000..0848de283ce --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.Sorting.cs @@ -0,0 +1,29 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Functionality related to determinstic ordering of types + partial class CanonBaseType + { + protected internal sealed override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + // These should be singletons + Debug.Assert(this == other); + return 0; + } + } + + partial class CanonType + { + protected internal override int ClassCode => 46114331; + } + + partial class UniversalCanonType + { + protected internal override int ClassCode => 1687626054; + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.cs new file mode 100644 index 00000000000..d84341b1540 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/CanonTypes.cs @@ -0,0 +1,280 @@ +// 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.Collections.Generic; + +using Internal.NativeFormat; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Type of canonicalization applied to a type + /// + public enum CanonicalFormKind + { + /// + /// Optimized for a particular set of instantiations (such as reference types) + /// + Specific, + + /// + /// Canonicalization that works for any type + /// + Universal, + + /// + /// Value used for lookup for Specific or Universal. Must not be used for canonicalizing. + /// + Any, + } + + /// + /// Base class for specialized and universal canon types + /// + public abstract partial class CanonBaseType : MetadataType + { + private TypeSystemContext _context; + + public CanonBaseType(TypeSystemContext context) + { + _context = context; + } + + public sealed override TypeSystemContext Context + { + get + { + return _context; + } + } + + protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() + { + return Array.Empty(); + } + + public override MetadataType MetadataBaseType => (MetadataType)BaseType; + + public override DefType ContainingType => null; + + public override DefType[] ExplicitlyImplementedInterfaces => Array.Empty(); + + public override bool IsAbstract => false; + + public override bool IsBeforeFieldInit => false; + + public override bool IsSequentialLayout => false; + + public override bool IsExplicitLayout => false; + + public override ModuleDesc Module => _context.CanonTypesModule; + + public override bool IsModuleType => false; + + public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name) + { + return null; + } + + public override ClassLayoutMetadata GetClassLayout() + { + return default(ClassLayoutMetadata); + } + + public override MetadataType GetNestedType(string name) + { + return null; + } + + public override IEnumerable GetNestedTypes() + { + return Array.Empty(); + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return false; + } + } + + /// + /// Type used for specific canonicalization (e.g. for reference types) + /// + internal sealed partial class CanonType : CanonBaseType + { + private const string _Namespace = "System"; + private const string _Name = "__Canon"; + public const string FullName = _Namespace + "." + _Name; + + private int _hashcode; + + public override string Namespace + { + get + { + return _Namespace; + } + } + + public override string Name + { + get + { + return _Name; + } + } + + public override bool IsSealed => false; + + public CanonType(TypeSystemContext context) + : base(context) + { + Initialize(); + } + + // Provides an extensibility hook for type system consumers that need to perform + // consumer-specific initialization. + partial void Initialize(); + + public override DefType BaseType + { + get + { + return Context.GetWellKnownType(WellKnownType.Object); + } + } + + public override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + return policy == CanonicalFormKind.Specific || + policy == CanonicalFormKind.Any; + } + + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + Debug.Assert(kind == CanonicalFormKind.Specific); + return this; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + if ((mask & TypeFlags.CategoryMask) != 0) + { + flags |= TypeFlags.Class; + } + + if ((mask & TypeFlags.HasGenericVarianceComputed) != 0) + { + flags |= TypeFlags.HasGenericVarianceComputed; + } + + flags |= TypeFlags.HasFinalizerComputed; + flags |= TypeFlags.AttributeCacheComputed; + + return flags; + } + + public override int GetHashCode() + { + if (_hashcode == 0) + { + _hashcode = TypeHashingAlgorithms.ComputeNameHashCode(FullName); + } + + return _hashcode; + } + } + + /// + /// Type that can be used for canonicalization of any type (including value types of unknown size) + /// + internal sealed partial class UniversalCanonType : CanonBaseType + { + private const string _Namespace = "System"; + private const string _Name = "__UniversalCanon"; + public const string FullName = _Namespace + "." + _Name; + + private int _hashcode; + + public override string Namespace + { + get + { + return _Namespace; + } + } + + public override string Name + { + get + { + return _Name; + } + } + + public override bool IsSealed => true; + + public UniversalCanonType(TypeSystemContext context) + : base(context) + { + Initialize(); + } + + // Provides an extensibility hook for type system consumers that need to perform + // consumer-specific initialization. + partial void Initialize(); + + public override DefType BaseType + { + get + { + // UniversalCanon is "a struct of indeterminate size and GC layout" + return Context.GetWellKnownType(WellKnownType.ValueType); + } + } + + public override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + return policy == CanonicalFormKind.Universal || + policy == CanonicalFormKind.Any; + } + + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + return this; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + if ((mask & TypeFlags.CategoryMask) != 0) + { + // Universally canonical type is reported as a variable-sized struct. + // It's the closest logical thing and avoids special casing around it. + flags |= TypeFlags.ValueType; + } + + flags |= TypeFlags.HasFinalizerComputed; + flags |= TypeFlags.AttributeCacheComputed; + + return flags; + } + + public override int GetHashCode() + { + if (_hashcode == 0) + { + _hashcode = TypeHashingAlgorithms.ComputeNameHashCode(FullName); + } + + return _hashcode; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/DefType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/DefType.Canon.cs new file mode 100644 index 00000000000..75c03bb4601 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/DefType.Canon.cs @@ -0,0 +1,15 @@ +// 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 +{ + // Implements canonicalization handling for TypeDefs + partial class DefType + { + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + return this; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/FunctionPointerType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/FunctionPointerType.Canon.cs new file mode 100644 index 00000000000..1a64efeb7b1 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/FunctionPointerType.Canon.cs @@ -0,0 +1,38 @@ +// 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; + +namespace Internal.TypeSystem +{ + // Holds code for canonicalizing a function pointer type + partial class FunctionPointerType + { + public override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + if (_signature.ReturnType.IsCanonicalSubtype(policy)) + return true; + + for (int i = 0; i < _signature.Length; i++) + if (_signature[i].IsCanonicalSubtype(policy)) + return true; + + return false; + } + + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + MethodSignatureBuilder sigBuilder = new MethodSignatureBuilder(_signature); + sigBuilder.ReturnType = Context.ConvertToCanon(_signature.ReturnType, kind); + for (int i = 0; i < _signature.Length; i++) + sigBuilder[i] = Context.ConvertToCanon(_signature[i], kind); + + MethodSignature canonSignature = sigBuilder.ToSignature(); + if (canonSignature != _signature) + return Context.GetFunctionPointerType(canonSignature); + + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/GenericParameterDesc.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/GenericParameterDesc.Canon.cs new file mode 100644 index 00000000000..59f1c731147 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/GenericParameterDesc.Canon.cs @@ -0,0 +1,24 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Implements canonicalization of generic parameters + public partial class GenericParameterDesc + { + public sealed override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + Debug.Fail("IsCanonicalSubtype of an indefinite type"); + return false; + } + + protected sealed override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + Debug.Fail("ConvertToCanonFormImpl for an indefinite type"); + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/InstantiatedMethod.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/InstantiatedMethod.Canon.cs new file mode 100644 index 00000000000..4e3e0204e77 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/InstantiatedMethod.Canon.cs @@ -0,0 +1,114 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Implements generic method canonicalization + partial class InstantiatedMethod + { + /// + /// Stores a cached version of the canonicalized form of this method since + /// calculating it is a recursive operation + /// + InstantiatedMethod _specificCanonCache = null; + InstantiatedMethod _universalCanonCache = null; + + /// + /// Returns the result of canonicalizing this method over the given kind of Canon + /// + public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) + { + InstantiatedMethod canonicalMethodResult = GetCachedCanonValue(kind); + if (canonicalMethodResult == null) + { + bool instantiationChanged; + Instantiation canonInstantiation = Context.ConvertInstantiationToCanonForm(Instantiation, kind, out instantiationChanged); + MethodDesc openMethodOnCanonicalizedType = _methodDef.GetCanonMethodTarget(kind); + + if (instantiationChanged || (openMethodOnCanonicalizedType != _methodDef)) + { + canonicalMethodResult = Context.GetInstantiatedMethod(openMethodOnCanonicalizedType, canonInstantiation); + } + else + { + canonicalMethodResult = this; + } + + // If the method instantiation is universal, we use a __UniversalCanon for all instantiation arguments for simplicity. + // This is to not end up having method instantiations like Foo<__UniversalCanon>.Method or Foo<__UniversalCanon>.Method + // or Foo<__UniversalCanon>.Method<__Canon> or Foo.Method<__UniversalCanon> + // It should just be Foo<__UniversalCanon>.Method<__UniversalCanon> + if ((kind == CanonicalFormKind.Specific) && + canonicalMethodResult.IsCanonicalMethod(CanonicalFormKind.Universal)) + { + canonicalMethodResult = (InstantiatedMethod)canonicalMethodResult.GetCanonMethodTarget(CanonicalFormKind.Universal); + } + + SetCachedCanonValue(kind, canonicalMethodResult); + } + + return canonicalMethodResult; + } + + InstantiatedMethod GetCachedCanonValue(CanonicalFormKind kind) + { + switch (kind) + { + case CanonicalFormKind.Specific: + return _specificCanonCache; + + case CanonicalFormKind.Universal: + return _universalCanonCache; + + default: + Debug.Fail("Invalid CanonicalFormKind: " + kind); + return null; + } + } + + void SetCachedCanonValue(CanonicalFormKind kind, InstantiatedMethod value) + { + switch(kind) + { + case CanonicalFormKind.Specific: + Debug.Assert(_specificCanonCache == null || _specificCanonCache == value); + _specificCanonCache = value; + break; + + case CanonicalFormKind.Universal: + Debug.Assert(_universalCanonCache == null || _universalCanonCache == value); + _universalCanonCache = value; + break; + + default: + Debug.Fail("Invalid CanonicalFormKind: " + kind); + break; + } + } + + /// + /// True if either the containing type instantiation or any of this method's generic arguments + /// are canonical + /// + public override bool IsCanonicalMethod(CanonicalFormKind policy) + { + if (OwningType.HasInstantiation && OwningType.IsCanonicalSubtype(policy)) + { + return true; + } + + foreach (TypeDesc type in Instantiation) + { + if (type.IsCanonicalSubtype(policy)) + { + return true; + } + } + + return false; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/InstantiatedType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/InstantiatedType.Canon.cs new file mode 100644 index 00000000000..8ed86f39c2e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/InstantiatedType.Canon.cs @@ -0,0 +1,36 @@ +// 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 +{ + // Implements canonicalization for generic instantiations + partial class InstantiatedType + { + public override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + foreach (TypeDesc t in Instantiation) + { + if (t.IsCanonicalSubtype(policy)) + { + return true; + } + } + + return false; + } + + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + bool needsChange; + Instantiation canonInstantiation = Context.ConvertInstantiationToCanonForm(Instantiation, kind, out needsChange); + if (needsChange) + { + MetadataType openType = (MetadataType)GetTypeDefinition(); + return Context.GetInstantiatedType(openType, canonInstantiation); + } + + return this; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/MetadataType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/MetadataType.Canon.cs new file mode 100644 index 00000000000..97d2dba1985 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/MetadataType.Canon.cs @@ -0,0 +1,15 @@ +// 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 +{ + // Holds code for canonicalization of metadata types + partial class MetadataType + { + public override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + return false; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodDelegator.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodDelegator.Canon.cs new file mode 100644 index 00000000000..9cc3a22040e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodDelegator.Canon.cs @@ -0,0 +1,17 @@ +// 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 +{ + partial class MethodDelegator + { + public override bool IsCanonicalMethod(CanonicalFormKind policy) + { + return _wrappedMethod.IsCanonicalMethod(policy); + } + + // For this method, delegating to the wrapped MethodDesc would likely be the wrong thing. + public abstract override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodDesc.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodDesc.Canon.cs new file mode 100644 index 00000000000..ad9e3d6b7fc --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodDesc.Canon.cs @@ -0,0 +1,23 @@ +// 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 +{ + // Implements method canonicalization + partial class MethodDesc + { + public virtual bool IsCanonicalMethod(CanonicalFormKind policy) + { + return false; + } + + /// + /// Returns the result of canonicalizing this method over the given kind of Canon + /// + public virtual MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) + { + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodForInstantiatedType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodForInstantiatedType.Canon.cs new file mode 100644 index 00000000000..abb49e6f5d7 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/MethodForInstantiatedType.Canon.cs @@ -0,0 +1,24 @@ +// 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 +{ + // Implements canonicalization for methods on instantiated types + partial class MethodForInstantiatedType + { + public override bool IsCanonicalMethod(CanonicalFormKind policy) + { + return OwningType.IsCanonicalSubtype(policy); + } + + public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) + { + TypeDesc canonicalizedTypeOfTargetMethod = OwningType.ConvertToCanonForm(kind); + if (canonicalizedTypeOfTargetMethod == OwningType) + return this; + + return Context.GetMethodForInstantiatedType(GetTypicalMethodDefinition(), (InstantiatedType)canonicalizedTypeOfTargetMethod); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/ParameterizedType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/ParameterizedType.Canon.cs new file mode 100644 index 00000000000..471022fc070 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/ParameterizedType.Canon.cs @@ -0,0 +1,15 @@ +// 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 +{ + // Holds code for canonicalizing a parameterized type + partial class ParameterizedType + { + public sealed override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + return ParameterType.IsCanonicalSubtype(policy); + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/PointerType.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/PointerType.Canon.cs new file mode 100644 index 00000000000..ae189951217 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/PointerType.Canon.cs @@ -0,0 +1,19 @@ +// 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 +{ + // Holds code for canonicalizing pointers + partial class PointerType + { + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + TypeDesc paramTypeConverted = Context.ConvertToCanon(ParameterType, kind); + if (paramTypeConverted != ParameterType) + return Context.GetPointerType(paramTypeConverted); + + return this; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/SignatureVariable.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/SignatureVariable.Canon.cs new file mode 100644 index 00000000000..a7da04a857c --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/SignatureVariable.Canon.cs @@ -0,0 +1,40 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Implements canonicalization of generic type parameters + partial class SignatureTypeVariable + { + public override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + Debug.Fail("IsCanonicalSubtype of an indefinite type"); + return false; + } + + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + Debug.Fail("ConvertToCanonFormImpl for an indefinite type"); + return this; + } + } + + // Implements canonicalization of generic method parameters + partial class SignatureMethodVariable + { + public override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + Debug.Fail("IsCanonicalSubtype of an indefinite type"); + return false; + } + + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + Debug.Fail("ConvertToCanonFormImpl for an indefinite type"); + return this; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/StandardCanonicalizationAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/StandardCanonicalizationAlgorithm.cs new file mode 100644 index 00000000000..8cac891b311 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/StandardCanonicalizationAlgorithm.cs @@ -0,0 +1,140 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Contains utility functionality for canonicalization used by multiple types. + /// + public static class StandardCanonicalizationAlgorithm + { + /// + /// Returns a new instantiation that canonicalizes all types in + /// if possible under the policy of '' + /// + /// True if the returned instantiation is different from ''. + public static Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) + { + TypeDesc[] canonInstantiation = null; + + CanonicalFormKind currentKind = kind; + CanonicalFormKind startLoopKind; + + // This logic is wrapped in a loop because we might potentially need to restart canonicalization if the policy + // changes due to one of the instantiation arguments already being universally canonical. + do + { + startLoopKind = currentKind; + + for (int instantiationIndex = 0; instantiationIndex < instantiation.Length; instantiationIndex++) + { + TypeDesc typeToConvert = instantiation[instantiationIndex]; + TypeDesc canonForm = ConvertToCanon(typeToConvert, ref currentKind); + if (typeToConvert != canonForm || canonInstantiation != null) + { + if (canonInstantiation == null) + { + canonInstantiation = new TypeDesc[instantiation.Length]; + for (int i = 0; i < instantiationIndex; i++) + canonInstantiation[i] = instantiation[i]; + } + + canonInstantiation[instantiationIndex] = canonForm; + } + } + + // Optimization: even if canonical policy changed, we don't actually need to re-run the loop + // for instantiations that only have a single element. + if (instantiation.Length == 1) + { + break; + } + + } while (currentKind != startLoopKind); + + + changed = canonInstantiation != null; + if (changed) + { + return new Instantiation(canonInstantiation); + } + + return instantiation; + } + + /// + /// Helper API to convert a type to its canonical or universal canonical form. + /// Note that for now, there is no mixture between specific canonical and universal canonical forms, + /// meaning that the canonical form or Foo can either be Foo<__Canon, int> or + /// Foo<__UniversalCanon, __UniversalCanon>. It cannot be Foo<__Canon, __UniversalCanon> (yet) + /// for simplicity. We can always change that rule in the futue and add support for the mixture, but + /// for now we are keeping it simple. + /// + public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) + { + // Wrap the call to the version that potentially modifies the parameter. External + // callers are not interested in that. + return ConvertToCanon(typeToConvert, ref kind); + } + + private static TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) + { + TypeSystemContext context = typeToConvert.Context; + if (kind == CanonicalFormKind.Universal) + { + return context.UniversalCanonType; + } + else if (kind == CanonicalFormKind.Specific) + { + if (typeToConvert == context.UniversalCanonType) + { + kind = CanonicalFormKind.Universal; + return context.UniversalCanonType; + } + else if (typeToConvert.IsSignatureVariable) + { + return typeToConvert; + } + else if (typeToConvert.IsDefType) + { + if (!typeToConvert.IsValueType) + return context.CanonType; + else if (typeToConvert.HasInstantiation) + { + TypeDesc convertedType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); + if (convertedType.IsCanonicalSubtype(CanonicalFormKind.Universal)) + { + kind = CanonicalFormKind.Universal; + return context.UniversalCanonType; + } + return convertedType; + } + else + return typeToConvert; + } + else if (typeToConvert.IsArray) + { + return context.CanonType; + } + else + { + TypeDesc convertedType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); + if (convertedType.IsCanonicalSubtype(CanonicalFormKind.Universal)) + { + kind = CanonicalFormKind.Universal; + return context.UniversalCanonType; + } + return convertedType; + } + } + else + { + Debug.Assert(false); + return null; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/TypeDesc.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/TypeDesc.Canon.cs new file mode 100644 index 00000000000..c4c141c42a3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/TypeDesc.Canon.cs @@ -0,0 +1,97 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Implements canonicalization for types + partial class TypeDesc + { + /// + /// Stores a cached version of the canonicalized form of this type since + /// calculating it is a recursive operation + /// + TypeDesc _specificCanonCache = null; + TypeDesc _universalCanonCache = null; + TypeDesc GetCachedCanonValue(CanonicalFormKind kind) + { + switch (kind) + { + case CanonicalFormKind.Specific: + return _specificCanonCache; + + case CanonicalFormKind.Universal: + return _universalCanonCache; + + default: + Debug.Fail("Invalid CanonicalFormKind: " + kind); + return null; + } + } + + void SetCachedCanonValue(CanonicalFormKind kind, TypeDesc value) + { + switch (kind) + { + case CanonicalFormKind.Specific: + Debug.Assert(_specificCanonCache == null || _specificCanonCache == value); + _specificCanonCache = value; + break; + + case CanonicalFormKind.Universal: + Debug.Assert(_universalCanonCache == null || _universalCanonCache == value); + _universalCanonCache = value; + break; + + default: + Debug.Fail("Invalid CanonicalFormKind: " + kind); + break; + } + } + + /// + /// Returns the canonical form of this type + /// + public TypeDesc ConvertToCanonForm(CanonicalFormKind kind) + { + TypeDesc canonForm = GetCachedCanonValue(kind); + if (canonForm == null) + { + canonForm = ConvertToCanonFormImpl(kind); + SetCachedCanonValue(kind, canonForm); + } + + return canonForm; + } + + /// + /// Derived types that override this should convert their generic parameters to canonical ones + /// + protected abstract TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind); + + /// + /// Returns true if this type matches the discovery policy or if it's parameterized over one that does. + /// + public abstract bool IsCanonicalSubtype(CanonicalFormKind policy); + + /// + /// Gets a value indicating whether this type is considered to be canonical type. + /// Note this will only return true if this is type is the actual __Canon/__UniversalCanon type, + /// or a struct instantiated over one of those. See also . + /// + internal bool IsCanonicalType + { + get + { + if (Context.IsCanonicalDefinitionType(this, CanonicalFormKind.Any)) + return true; + else if (this.IsValueType) + return this.IsCanonicalSubtype(CanonicalFormKind.Any); + else + return false; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs b/src/coreclr/src/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs new file mode 100644 index 00000000000..444f24b67a6 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs @@ -0,0 +1,117 @@ +// 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 Interlocked = System.Threading.Interlocked; +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Includes canonicalization objects local to a particular context + public partial class TypeSystemContext + { + private CanonType _canonType = null; + /// + /// Instance of System.__Canon for this context + /// + public CanonBaseType CanonType + { + get + { + if (_canonType == null) + { + Interlocked.CompareExchange(ref _canonType, new CanonType(this), null); + } + return _canonType; + } + } + + private UniversalCanonType _universalCanonType = null; + /// + /// Instance of System.__UniversalCanon for this context + /// + public CanonBaseType UniversalCanonType + { + get + { + if (_universalCanonType == null) + { + Interlocked.CompareExchange(ref _universalCanonType, new UniversalCanonType(this), null); + } + return _universalCanonType; + } + } + + protected internal virtual ModuleDesc CanonTypesModule + { + get { return SystemModule; } + } + + /// + /// Returns true if and only if the '' is __Canon or __UniversalCanon + /// that matches the parameter. + /// + public bool IsCanonicalDefinitionType(TypeDesc type, CanonicalFormKind kind) + { + if (kind == CanonicalFormKind.Any) + { + return type == CanonType || type == UniversalCanonType; + } + else if (kind == CanonicalFormKind.Specific) + { + return type == CanonType; + } + else + { + Debug.Assert(kind == CanonicalFormKind.Universal); + return type == UniversalCanonType; + } + } + + /// + /// Converts an instantiation into its canonical form. + /// + public Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind) + { + bool changed; + return ConvertInstantiationToCanonForm(instantiation, kind, out changed); + } + + /// + /// Converts an instantiation into its canonical form. Returns the canonical instantiation. The '' + /// parameter indicates whether the returned canonical instantiation is different from the specific instantiation + /// passed as the input. + /// + protected internal virtual Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) + { + throw new NotSupportedException(); + } + + /// + /// Converts a constituent of a constructed type to it's canonical form. Note this method is different + /// from . + /// + protected internal virtual TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) + { + throw new NotSupportedException(); + } + + public abstract bool SupportsCanon { get; } + public abstract bool SupportsUniversalCanon { get; } + + public MetadataType GetCanonType(string name) + { + switch (name) + { + case TypeSystem.CanonType.FullName: + return CanonType; + case TypeSystem.UniversalCanonType.FullName: + return UniversalCanonType; + } + + return null; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/FieldDesc.CodeGen.cs b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/FieldDesc.CodeGen.cs new file mode 100644 index 00000000000..1fd5ea231f0 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/FieldDesc.CodeGen.cs @@ -0,0 +1,33 @@ +// 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 +{ + // Additional members of FieldDesc related to code generation. + partial class FieldDesc + { + /// + /// Gets a value indicating whether this is a field that needs to be treated + /// specially. + /// + public virtual bool IsIntrinsic + { + get + { + return false; + } + } + } + + partial class FieldForInstantiatedType + { + public override bool IsIntrinsic + { + get + { + return _fieldDef.IsIntrinsic; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs new file mode 100644 index 00000000000..7091ea8a955 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs @@ -0,0 +1,105 @@ +// 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 +{ + partial class MethodDelegator + { + public override bool IsIntrinsic + { + get + { + return _wrappedMethod.IsIntrinsic; + } + } + + public override bool IsNoInlining + { + get + { + return _wrappedMethod.IsNoInlining; + } + } + + public override bool IsAggressiveInlining + { + get + { + return _wrappedMethod.IsAggressiveInlining; + } + } + + public override bool IsAggressiveOptimization + { + get + { + return _wrappedMethod.IsAggressiveOptimization; + } + } + + public override bool RequireSecObject + { + get + { + return _wrappedMethod.RequireSecObject; + } + } + + public override bool IsNoOptimization + { + get + { + return _wrappedMethod.IsNoOptimization; + } + } + + public override bool IsRuntimeImplemented + { + get + { + return _wrappedMethod.IsRuntimeImplemented; + } + } + + public override bool IsInternalCall + { + get + { + return _wrappedMethod.IsInternalCall; + } + } + + public override bool IsSynchronized + { + get + { + return _wrappedMethod.IsSynchronized; + } + } + + public override bool IsNativeCallable + { + get + { + return _wrappedMethod.IsNativeCallable; + } + } + + public override bool IsRuntimeExport + { + get + { + return _wrappedMethod.IsRuntimeExport; + } + } + + public override bool IsSpecialName + { + get + { + return _wrappedMethod.IsSpecialName; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs new file mode 100644 index 00000000000..5884f1dcb4c --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs @@ -0,0 +1,373 @@ +// 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 +{ + // Additional members of MethodDesc related to code generation. + public abstract partial class MethodDesc + { + /// + /// Gets a value specifying whether this method is an intrinsic. + /// This can either be an intrinsic recognized by the compiler, + /// by the codegen backend, or some other component. + /// + public virtual bool IsIntrinsic + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether this method should not be included + /// into the code of any caller methods by the compiler (and should be kept + /// as a separate routine). + /// + public virtual bool IsNoInlining + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether this method should be included into + /// the code of the caller methods aggressively. + /// + public virtual bool IsAggressiveInlining + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether this method contains hot code and should + /// be aggressively optimized if possible. + /// + public virtual bool IsAggressiveOptimization + { + get + { + return false; + } + } + + /// + /// Gets a value indicating whether this method was marked with the + /// System.Security.DynamicSecurityMethod attribute. For such methods + /// runtime needs to be able to find their caller, their caller's caller + /// or the method itself on the call stack using stack walking. + /// + public virtual bool RequireSecObject + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether this method should not be optimized. + /// + public virtual bool IsNoOptimization + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether the implementation of this method + /// is provided by the runtime (i.e., through generated IL). + /// + public virtual bool IsRuntimeImplemented + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether the implementation of this method is + /// provided externally by calling out into the runtime. + /// + public virtual bool IsInternalCall + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether the implementation of this method is + /// implicitly synchronized + /// + public virtual bool IsSynchronized + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether this method is directly callable + /// by external unmanaged code. + /// + public virtual bool IsNativeCallable + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether this method is an exported managed + /// entrypoint. + /// + public virtual bool IsRuntimeExport + { + get + { + return false; + } + } + + /// + /// Gets a value specifying whether this method has special semantics. + /// The name indicates the semantics. + /// + public virtual bool IsSpecialName + { + get + { + return false; + } + } + } + + // Additional members of InstantiatedMethod related to code generation. + public partial class InstantiatedMethod + { + public override bool IsIntrinsic + { + get + { + return _methodDef.IsIntrinsic; + } + } + + public override bool IsNoInlining + { + get + { + return _methodDef.IsNoInlining; + } + } + + public override bool IsAggressiveOptimization + { + get + { + return _methodDef.IsAggressiveOptimization; + } + } + + public override bool RequireSecObject + { + get + { + return _methodDef.RequireSecObject; + } + } + + public override bool IsNoOptimization + { + get + { + return _methodDef.IsNoOptimization; + } + } + + public override bool IsAggressiveInlining + { + get + { + return _methodDef.IsAggressiveInlining; + } + } + + public override bool IsRuntimeImplemented + { + get + { + return _methodDef.IsRuntimeImplemented; + } + } + + public override bool IsInternalCall + { + get + { + return _methodDef.IsInternalCall; + } + } + + public override bool IsSynchronized + { + get + { + return _methodDef.IsSynchronized; + } + } + + public override bool IsNativeCallable + { + get + { + return _methodDef.IsNativeCallable; + } + } + + public override bool IsSpecialName + { + get + { + return _methodDef.IsSpecialName; + } + } + } + + // Additional members of MethodForInstantiatedType related to code generation. + public partial class MethodForInstantiatedType + { + public override bool IsIntrinsic + { + get + { + return _typicalMethodDef.IsIntrinsic; + } + } + + public override bool IsNoInlining + { + get + { + return _typicalMethodDef.IsNoInlining; + } + } + + public override bool IsAggressiveOptimization + { + get + { + return _typicalMethodDef.IsAggressiveOptimization; + } + } + + public override bool RequireSecObject + { + get + { + return _typicalMethodDef.RequireSecObject; + } + } + + public override bool IsNoOptimization + { + get + { + return _typicalMethodDef.IsNoOptimization; + } + } + + public override bool IsAggressiveInlining + { + get + { + return _typicalMethodDef.IsAggressiveInlining; + } + } + + public override bool IsRuntimeImplemented + { + get + { + return _typicalMethodDef.IsRuntimeImplemented; + } + } + + public override bool IsInternalCall + { + get + { + return _typicalMethodDef.IsInternalCall; + } + } + + public override bool IsSynchronized + { + get + { + return _typicalMethodDef.IsSynchronized; + } + } + + public override bool IsNativeCallable + { + get + { + return _typicalMethodDef.IsNativeCallable; + } + } + + public override bool IsSpecialName + { + get + { + return _typicalMethodDef.IsSpecialName; + } + } + } + + // Additional members of ArrayMethod related to code generation. + public partial class ArrayMethod + { + public override bool IsIntrinsic + { + get + { + return true; + } + } + + public override bool IsNoInlining + { + get + { + // Do not allow inlining the Address method. The method that actually gets called is + // the one that has a hidden argument with the expected array type. + return Kind == ArrayMethodKind.Address; + } + } + + public override bool IsInternalCall + { + get + { + // We consider Address method an internal call since this will end up calling a different + // method at runtime. + return Kind == ArrayMethodKind.Address; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/TargetDetails.CodeGen.cs b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/TargetDetails.CodeGen.cs new file mode 100644 index 00000000000..311f7488dd5 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/TargetDetails.CodeGen.cs @@ -0,0 +1,45 @@ +// 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 +{ + // Extension to TargetDetails related to code generation + partial class TargetDetails + { + public TargetDetails(TargetArchitecture architecture, TargetOS targetOS, TargetAbi abi, SimdVectorLength simdVectorLength) + : this(architecture, targetOS, abi) + { + MaximumSimdVectorLength = simdVectorLength; + } + + /// + /// Specifies the maximum size of native vectors on the target architecture. + /// + public SimdVectorLength MaximumSimdVectorLength + { + get; + } + } + + /// + /// Specifies the size of native vectors. + /// + public enum SimdVectorLength + { + /// + /// Specifies that native vectors are not supported. + /// + None, + + /// + /// Specifies that native vectors are 128 bit (e.g. SSE on x86). + /// + Vector128Bit, + + /// + /// Specifies that native vectors are 256 bit (e.g. AVX on x86). + /// + Vector256Bit, + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/TypeDesc.CodeGen.cs b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/TypeDesc.CodeGen.cs new file mode 100644 index 00000000000..9a5a1c8b289 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/TypeDesc.CodeGen.cs @@ -0,0 +1,30 @@ +// 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 +{ + partial class TypeDesc + { + /// + /// Gets a value indicating whether this is a type that needs to be treated + /// specially. + /// + public bool IsIntrinsic + { + get + { + return (GetTypeFlags(TypeFlags.IsIntrinsic | TypeFlags.AttributeCacheComputed) & TypeFlags.IsIntrinsic) != 0; + } + } + } + + partial class InstantiatedType + { + partial void AddComputedIntrinsicFlag(ref TypeFlags flags) + { + if (_typeDef.IsIntrinsic) + flags |= TypeFlags.IsIntrinsic; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/AlignmentHelper.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/AlignmentHelper.cs new file mode 100644 index 00000000000..7678cd58b81 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/AlignmentHelper.cs @@ -0,0 +1,23 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public static class AlignmentHelper + { + public static int AlignUp(this int val, int alignment) + { + Debug.Assert(val >= 0 && alignment >= 0); + + // alignment must be a power of 2 for this implementation to work (need modulo otherwise) + Debug.Assert(0 == (alignment & (alignment - 1))); + int result = (val + (alignment - 1)) & ~(alignment - 1); + Debug.Assert(result >= val); // check for overflow + + return result; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs new file mode 100644 index 00000000000..4da118caeab --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs @@ -0,0 +1,18 @@ +// 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 +{ + public partial class ArrayMethod + { + public override string DiagnosticName + { + get + { + // The ArrayMethod.Name property is gauranteed to not throw + return Name; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayType.cs new file mode 100644 index 00000000000..eaa4547863b --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayType.cs @@ -0,0 +1,325 @@ +// 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.Collections.Generic; +using System.Threading; + +namespace Internal.TypeSystem +{ + /// + /// Represents an array type - either a multidimensional array, or a vector + /// (a one-dimensional array with a zero lower bound). + /// + public sealed partial class ArrayType : ParameterizedType + { + private int _rank; // -1 for regular single dimensional arrays, > 0 for multidimensional arrays + + internal ArrayType(TypeDesc elementType, int rank) + : base(elementType) + { + _rank = rank; + } + + public override int GetHashCode() + { + // ComputeArrayTypeHashCode expects -1 for an SzArray + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeArrayTypeHashCode(this.ElementType.GetHashCode(), _rank); + } + + public override DefType BaseType + { + get + { + return this.Context.GetWellKnownType(WellKnownType.Array); + } + } + + /// + /// Gets the type of the element of this array. + /// + public TypeDesc ElementType + { + get + { + return this.ParameterType; + } + } + + internal MethodDesc[] _methods; + + /// + /// Gets a value indicating whether this type is a vector. + /// + public new bool IsSzArray + { + get + { + return _rank < 0; + } + } + + /// + /// Gets a value indicating whether this type is an mdarray. + /// + public new bool IsMdArray + { + get + { + return _rank > 0; + } + } + + /// + /// Gets the rank of this array. Note this returns "1" for both vectors, and + /// for general arrays of rank 1. Use to disambiguate. + /// + public int Rank + { + get + { + return (_rank < 0) ? 1 : _rank; + } + } + + private void InitializeMethods() + { + int numCtors; + + if (IsSzArray) + { + numCtors = 1; + + // Jagged arrays have constructor for each possible depth + var t = this.ElementType; + while (t.IsSzArray) + { + t = ((ArrayType)t).ElementType; + numCtors++; + } + } + else + { + // Multidimensional arrays have two ctors, one with and one without lower bounds + numCtors = 2; + } + + MethodDesc[] methods = new MethodDesc[(int)ArrayMethodKind.Ctor + numCtors]; + + for (int i = 0; i < methods.Length; i++) + methods[i] = new ArrayMethod(this, (ArrayMethodKind)i); + + Interlocked.CompareExchange(ref _methods, methods, null); + } + + public override IEnumerable GetMethods() + { + if (_methods == null) + InitializeMethods(); + return _methods; + } + + public MethodDesc GetArrayMethod(ArrayMethodKind kind) + { + if (_methods == null) + InitializeMethods(); + return _methods[(int)kind]; + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc elementType = this.ElementType; + TypeDesc instantiatedElementType = elementType.InstantiateSignature(typeInstantiation, methodInstantiation); + if (instantiatedElementType != elementType) + return Context.GetArrayType(instantiatedElementType, _rank); + + return this; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = _rank == -1 ? TypeFlags.SzArray : TypeFlags.Array; + + flags |= TypeFlags.HasGenericVarianceComputed; + + flags |= TypeFlags.HasFinalizerComputed; + + flags |= TypeFlags.AttributeCacheComputed; + + return flags; + } + } + + public enum ArrayMethodKind + { + Get, + Set, + Address, + AddressWithHiddenArg, + Ctor + } + + /// + /// Represents one of the methods on array types. While array types are not typical + /// classes backed by metadata, they do have methods that can be referenced from the IL + /// and the type system needs to provide a way to represent them. + /// + /// + /// There are two array Address methods ( and + /// ). One is used when referencing Address + /// method from IL, the other is used when *compiling* the method body. + /// The reason we need to do this is that the Address method is required to do a type check using a type + /// that is only known at the callsite. The trick we use is that we tell codegen that the + /// method requires a hidden instantiation parameter (even though it doesn't). + /// The instantiation parameter is where we capture the type at the callsite. + /// When we compile the method body, we compile it as that + /// has the hidden argument explicitly listed in it's signature and is available as a regular parameter. + /// + public sealed partial class ArrayMethod : MethodDesc + { + private ArrayType _owningType; + private ArrayMethodKind _kind; + + internal ArrayMethod(ArrayType owningType, ArrayMethodKind kind) + { + _owningType = owningType; + _kind = kind; + } + + public override TypeSystemContext Context + { + get + { + return _owningType.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _owningType; + } + } + + public ArrayType OwningArray + { + get + { + return _owningType; + } + } + + public ArrayMethodKind Kind + { + get + { + return _kind; + } + } + + private MethodSignature _signature; + + public override MethodSignature Signature + { + get + { + if (_signature == null) + { + switch (_kind) + { + case ArrayMethodKind.Get: + { + var parameters = new TypeDesc[_owningType.Rank]; + for (int i = 0; i < _owningType.Rank; i++) + parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + _signature = new MethodSignature(0, 0, _owningType.ElementType, parameters); + break; + } + case ArrayMethodKind.Set: + { + var parameters = new TypeDesc[_owningType.Rank + 1]; + for (int i = 0; i < _owningType.Rank; i++) + parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + parameters[_owningType.Rank] = _owningType.ElementType; + _signature = new MethodSignature(0, 0, this.Context.GetWellKnownType(WellKnownType.Void), parameters); + break; + } + case ArrayMethodKind.Address: + { + var parameters = new TypeDesc[_owningType.Rank]; + for (int i = 0; i < _owningType.Rank; i++) + parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + _signature = new MethodSignature(0, 0, _owningType.ElementType.MakeByRefType(), parameters); + } + break; + case ArrayMethodKind.AddressWithHiddenArg: + { + var parameters = new TypeDesc[_owningType.Rank + 1]; + parameters[0] = Context.SystemModule.GetType("System", "EETypePtr"); + for (int i = 0; i < _owningType.Rank; i++) + parameters[i + 1] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + _signature = new MethodSignature(0, 0, _owningType.ElementType.MakeByRefType(), parameters); + } + break; + default: + { + int numArgs; + if (_owningType.IsSzArray) + { + numArgs = 1 + (int)_kind - (int)ArrayMethodKind.Ctor; + } + else + { + numArgs = (_kind == ArrayMethodKind.Ctor) ? _owningType.Rank : 2 * _owningType.Rank; + } + + var argTypes = new TypeDesc[numArgs]; + for (int i = 0; i < argTypes.Length; i++) + argTypes[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + _signature = new MethodSignature(0, 0, this.Context.GetWellKnownType(WellKnownType.Void), argTypes); + } + break; + } + } + return _signature; + } + } + + public override string Name + { + get + { + switch (_kind) + { + case ArrayMethodKind.Get: + return "Get"; + case ArrayMethodKind.Set: + return "Set"; + case ArrayMethodKind.Address: + case ArrayMethodKind.AddressWithHiddenArg: + return "Address"; + default: + return ".ctor"; + } + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return false; + } + + public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc owningType = this.OwningType; + TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); + + if (owningType != instantiatedOwningType) + return ((ArrayType)instantiatedOwningType).GetArrayMethod(_kind); + else + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/BaseTypeRuntimeInterfacesAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/BaseTypeRuntimeInterfacesAlgorithm.cs new file mode 100644 index 00000000000..8f814cfb594 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/BaseTypeRuntimeInterfacesAlgorithm.cs @@ -0,0 +1,33 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// RuntimeInterfaces algorithm for types known to have no explicitly defined interfaces + /// but which do have a base type. (For instance multidimensional arrays) + /// + public sealed class BaseTypeRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm + { + private static RuntimeInterfacesAlgorithm _singleton = new BaseTypeRuntimeInterfacesAlgorithm(); + + private BaseTypeRuntimeInterfacesAlgorithm() { } + + public static RuntimeInterfacesAlgorithm Instance + { + get + { + return _singleton; + } + } + + public override DefType[] ComputeRuntimeInterfaces(TypeDesc _type) + { + return _type.BaseType.RuntimeInterfaces; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ByRefType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ByRefType.cs new file mode 100644 index 00000000000..6d198459452 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ByRefType.cs @@ -0,0 +1,45 @@ +// 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 +{ + /// + /// Represents a managed pointer type. + /// + public sealed partial class ByRefType : ParameterizedType + { + internal ByRefType(TypeDesc parameter) + : base(parameter) + { + } + + public override int GetHashCode() + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeByrefTypeHashCode(this.ParameterType.GetHashCode()); + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc parameterType = this.ParameterType; + TypeDesc instantiatedParameterType = parameterType.InstantiateSignature(typeInstantiation, methodInstantiation); + if (instantiatedParameterType != parameterType) + return Context.GetByRefType(instantiatedParameterType); + + return this; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = TypeFlags.ByRef; + + flags |= TypeFlags.HasGenericVarianceComputed; + + flags |= TypeFlags.HasFinalizerComputed; + + flags |= TypeFlags.AttributeCacheComputed; + + return flags; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/CastingHelper.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/CastingHelper.cs new file mode 100644 index 00000000000..d850cc6b334 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/CastingHelper.cs @@ -0,0 +1,426 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public static partial class CastingHelper + { + /// + /// Returns true if '' can be cast to ''. + /// Assumes '' is in it's boxed form if it's a value type (i.e. + /// [System.Int32].CanCastTo([System.Object]) will return true). + /// + public static bool CanCastTo(this TypeDesc thisType, TypeDesc otherType) + { + return thisType.CanCastToInternal(otherType, null); + } + + private static bool CanCastToInternal(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) + { + if (thisType == otherType) + { + return true; + } + + switch (thisType.Category) + { + case TypeFlags.GenericParameter: + return ((GenericParameterDesc)thisType).CanCastGenericParameterTo(otherType, protect); + + case TypeFlags.Array: + case TypeFlags.SzArray: + return ((ArrayType)thisType).CanCastArrayTo(otherType, protect); + + default: + Debug.Assert(thisType.IsDefType); + return thisType.CanCastToClassOrInterface(otherType, protect); + } + } + + private static bool CanCastGenericParameterTo(this GenericParameterDesc thisType, TypeDesc otherType, StackOverflowProtect protect) + { + // A boxed variable type can be cast to any of its constraints, or object, if none are specified + if (otherType.IsObject) + { + return true; + } + + if (thisType.HasNotNullableValueTypeConstraint && + otherType.IsWellKnownType(WellKnownType.ValueType)) + { + return true; + } + + foreach (var typeConstraint in thisType.TypeConstraints) + { + if (typeConstraint.CanCastToInternal(otherType, protect)) + { + return true; + } + } + + return false; + } + + private static bool CanCastArrayTo(this ArrayType thisType, TypeDesc otherType, StackOverflowProtect protect) + { + // Casting the array to one of the base types or interfaces? + if (otherType.IsDefType) + { + return thisType.CanCastToClassOrInterface(otherType, protect); + } + + // Casting array to something else (between SzArray and Array, for example)? + if (thisType.Category != otherType.Category) + { + // An SzArray is castable to MdArray rank 1. We follow the same casting rules as SzArray to SzArray. + if (thisType.Category == TypeFlags.SzArray + && otherType.Category == TypeFlags.Array + && ((ArrayType)otherType).Rank == 1) + { + return thisType.CanCastParamTo(((ArrayType)otherType).ParameterType, protect); + } + + return false; + } + + ArrayType otherArrayType = (ArrayType)otherType; + + // Check ranks if we're casting multidim arrays + if (!thisType.IsSzArray && thisType.Rank != otherArrayType.Rank) + { + return false; + } + + return thisType.CanCastParamTo(otherArrayType.ParameterType, protect); + } + + private static bool CanCastParamTo(this ParameterizedType thisType, TypeDesc paramType, StackOverflowProtect protect) + { + // While boxed value classes inherit from object their + // unboxed versions do not. Parameterized types have the + // unboxed version, thus, if the from type parameter is value + // class then only an exact match/equivalence works. + if (thisType.ParameterType == paramType) + { + return true; + } + + TypeDesc curTypesParm = thisType.ParameterType; + + // Object parameters don't need an exact match but only inheritance, check for that + TypeDesc fromParamUnderlyingType = curTypesParm.UnderlyingType; + if (fromParamUnderlyingType.IsGCPointer) + { + return curTypesParm.CanCastToInternal(paramType, protect); + } + else if (curTypesParm.IsGenericParameter) + { + var genericVariableFromParam = (GenericParameterDesc)curTypesParm; + if (genericVariableFromParam.HasReferenceTypeConstraint) + { + return genericVariableFromParam.CanCastToInternal(paramType, protect); + } + } + else if (fromParamUnderlyingType.IsPrimitive) + { + TypeDesc toParamUnderlyingType = paramType.UnderlyingType; + if (toParamUnderlyingType.IsPrimitive) + { + if (toParamUnderlyingType == fromParamUnderlyingType) + { + return true; + } + + if (ArePrimitveTypesEquivalentSize(fromParamUnderlyingType, toParamUnderlyingType)) + { + return true; + } + } + } + + // Anything else is not a match + return false; + } + + // Returns true of the two types are equivalent primitive types. Used by array casts. + private static bool ArePrimitveTypesEquivalentSize(TypeDesc type1, TypeDesc type2) + { + Debug.Assert(type1.IsPrimitive && type2.IsPrimitive); + + // Primitive types such as E_T_I4 and E_T_U4 are interchangeable + // Enums with interchangeable underlying types are interchangable + // BOOL is NOT interchangeable with I1/U1, neither CHAR -- with I2/U2 + // Float and double are not interchangable here. + + int sourcePrimitiveTypeEquivalenceSize = type1.GetIntegralTypeMatchSize(); + + // Quick check to see if the first type can be matched. + if (sourcePrimitiveTypeEquivalenceSize == 0) + { + return false; + } + + int targetPrimitiveTypeEquivalenceSize = type2.GetIntegralTypeMatchSize(); + + return sourcePrimitiveTypeEquivalenceSize == targetPrimitiveTypeEquivalenceSize; + } + + private static int GetIntegralTypeMatchSize(this TypeDesc type) + { + Debug.Assert(type.IsPrimitive); + + switch (type.Category) + { + case TypeFlags.SByte: + case TypeFlags.Byte: + return 1; + case TypeFlags.UInt16: + case TypeFlags.Int16: + return 2; + case TypeFlags.Int32: + case TypeFlags.UInt32: + return 4; + case TypeFlags.Int64: + case TypeFlags.UInt64: + return 8; + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + return type.Context.Target.PointerSize; + default: + return 0; + } + } + + public static bool IsArrayElementTypeCastableBySize(TypeDesc elementType) + { + TypeDesc underlyingType = elementType.UnderlyingType; + return underlyingType.IsPrimitive && GetIntegralTypeMatchSize(underlyingType) != 0; + } + + private static bool CanCastToClassOrInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) + { + if (otherType.IsInterface) + { + return thisType.CanCastToInterface(otherType, protect); + } + else + { + return thisType.CanCastToClass(otherType, protect); + } + } + + private static bool CanCastToInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) + { + if (!otherType.HasVariance) + { + return thisType.CanCastToNonVariantInterface(otherType,protect); + } + else + { + if (thisType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) + { + return true; + } + + foreach (var interfaceType in thisType.RuntimeInterfaces) + { + if (interfaceType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) + { + return true; + } + } + } + + return false; + } + + private static bool CanCastToNonVariantInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) + { + if (otherType == thisType) + { + return true; + } + + foreach (var interfaceType in thisType.RuntimeInterfaces) + { + if (interfaceType == otherType) + { + return true; + } + } + + return false; + } + + private static bool CanCastByVarianceToInterfaceOrDelegate(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protectInput) + { + if (!thisType.HasSameTypeDefinition(otherType)) + { + return false; + } + + var stackOverflowProtectKey = new CastingPair(thisType, otherType); + if (protectInput != null) + { + if (protectInput.Contains(stackOverflowProtectKey)) + return false; + } + + StackOverflowProtect protect = new StackOverflowProtect(stackOverflowProtectKey, protectInput); + + Instantiation instantiationThis = thisType.Instantiation; + Instantiation instantiationTarget = otherType.Instantiation; + Instantiation instantiationOpen = thisType.GetTypeDefinition().Instantiation; + + Debug.Assert(instantiationThis.Length == instantiationTarget.Length && + instantiationThis.Length == instantiationOpen.Length); + + for (int i = 0; i < instantiationThis.Length; i++) + { + TypeDesc arg = instantiationThis[i]; + TypeDesc targetArg = instantiationTarget[i]; + + if (arg != targetArg) + { + GenericParameterDesc openArgType = (GenericParameterDesc)instantiationOpen[i]; + + switch (openArgType.Variance) + { + case GenericVariance.Covariant: + if (!arg.IsBoxedAndCanCastTo(targetArg, protect)) + return false; + break; + + case GenericVariance.Contravariant: + if (!targetArg.IsBoxedAndCanCastTo(arg, protect)) + return false; + break; + + default: + // non-variant + Debug.Assert(openArgType.Variance == GenericVariance.None); + return false; + } + } + } + + return true; + } + + private static bool CanCastToClass(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) + { + TypeDesc curType = thisType; + + if (curType.IsInterface && otherType.IsObject) + { + return true; + } + + // If the target type has variant type parameters, we take a slower path + if (curType.HasVariance) + { + // First chase inheritance hierarchy until we hit a class that only differs in its instantiation + do + { + if (curType == otherType) + { + return true; + } + + if (curType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) + { + return true; + } + + curType = curType.BaseType; + } + while (curType != null); + } + else + { + // If there are no variant type parameters, just chase the hierarchy + + // Allow curType to be nullable, which means this method + // will additionally return true if curType is Nullable && ( + // currType == otherType + // OR otherType is System.ValueType or System.Object) + + // Always strip Nullable from the otherType, if present + if (otherType.IsNullable && !curType.IsNullable) + { + return thisType.CanCastTo(otherType.Instantiation[0]); + } + + do + { + if (curType == otherType) + return true; + + curType = curType.BaseType; + } while (curType != null); + } + + return false; + } + + private static bool IsBoxedAndCanCastTo(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) + { + TypeDesc fromUnderlyingType = thisType.UnderlyingType; + + if (fromUnderlyingType.IsGCPointer) + { + return thisType.CanCastToInternal(otherType, protect); + } + else if (thisType.IsGenericParameter) + { + var genericVariableFromParam = (GenericParameterDesc)thisType; + if (genericVariableFromParam.HasReferenceTypeConstraint) + { + return genericVariableFromParam.CanCastToInternal(otherType, protect); + } + } + + return false; + } + + private class StackOverflowProtect + { + private CastingPair _value; + private StackOverflowProtect _previous; + + public StackOverflowProtect(CastingPair value, StackOverflowProtect previous) + { + _value = value; + _previous = previous; + } + + public bool Contains(CastingPair value) + { + for (var current = this; current != null; current = current._previous) + if (current._value.Equals(value)) + return true; + return false; + } + } + + private struct CastingPair + { + public readonly TypeDesc FromType; + public readonly TypeDesc ToType; + + public CastingPair(TypeDesc fromType, TypeDesc toType) + { + FromType = fromType; + ToType = toType; + } + + public bool Equals(CastingPair other) => FromType == other.FromType && ToType == other.ToType; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.Diagnostic.cs new file mode 100644 index 00000000000..8ef92715ab3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.Diagnostic.cs @@ -0,0 +1,25 @@ +// 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.Collections.Generic; + +namespace Internal.TypeSystem +{ + /// + /// Type with metadata available that is equivalent to a TypeDef record in an ECMA 335 metadata stream. + /// A class, an interface, or a value type. + /// + abstract partial class DefType + { + /// + /// Gets the Name of a type. This must not throw + /// + public abstract string DiagnosticName { get; } + + /// + /// Gets the Namespace of a type. This must not throw + /// + public abstract string DiagnosticNamespace { get; } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs new file mode 100644 index 00000000000..e1b1beee819 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs @@ -0,0 +1,411 @@ +// 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; + +namespace Internal.TypeSystem +{ + // This is the api surface necessary to query the field layout of a type + public abstract partial class DefType : TypeDesc + { + /// + /// Bit flags for layout + /// + private class FieldLayoutFlags + { + /// + /// True if ContainsGCPointers has been computed + /// + public const int ComputedContainsGCPointers = 1; + + /// + /// True if the type contains GC pointers + /// + public const int ContainsGCPointers = 2; + + /// + /// True if the instance type only layout is computed + /// + public const int ComputedInstanceTypeLayout = 4; + + /// + /// True if the static field layout for the static regions have been computed + /// + public const int ComputedStaticRegionLayout = 8; + + /// + /// True if the instance type layout is complete including fields + /// + public const int ComputedInstanceTypeFieldsLayout = 0x10; + + /// + /// True if the static field layout for the static fields have been computed + /// + public const int ComputedStaticFieldsLayout = 0x20; + + /// + /// True if information about the shape of value type has been computed. + /// + public const int ComputedValueTypeShapeCharacteristics = 0x40; + } + + private class StaticBlockInfo + { + public StaticsBlock NonGcStatics; + public StaticsBlock GcStatics; + public StaticsBlock ThreadNonGcStatics; + public StaticsBlock ThreadGcStatics; + } + + ThreadSafeFlags _fieldLayoutFlags; + + LayoutInt _instanceFieldSize; + LayoutInt _instanceFieldAlignment; + LayoutInt _instanceByteCountUnaligned; + LayoutInt _instanceByteAlignment; + + // Information about various static blocks is rare, so we keep it out of line. + StaticBlockInfo _staticBlockInfo; + + ValueTypeShapeCharacteristics _valueTypeShapeCharacteristics; + + /// + /// Does a type transitively have any fields which are GC object pointers + /// + public bool ContainsGCPointers + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedContainsGCPointers)) + { + ComputeTypeContainsGCPointers(); + } + return _fieldLayoutFlags.HasFlags(FieldLayoutFlags.ContainsGCPointers); + } + } + + /// + /// The number of bytes required to hold a field of this type + /// + public LayoutInt InstanceFieldSize + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) + { + ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); + } + return _instanceFieldSize; + } + } + + /// + /// What is the alignment requirement of the fields of this type + /// + public LayoutInt InstanceFieldAlignment + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) + { + ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); + } + return _instanceFieldAlignment; + } + } + + /// + /// The number of bytes required when allocating this type on this GC heap + /// + public LayoutInt InstanceByteCount + { + get + { + return LayoutInt.AlignUp(InstanceByteCountUnaligned, InstanceByteAlignment, Context.Target); + } + } + + /// + /// The number of bytes used by the instance fields of this type and its parent types without padding at the end for alignment/gc. + /// + public LayoutInt InstanceByteCountUnaligned + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) + { + ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); + } + return _instanceByteCountUnaligned; + } + } + + /// + /// The alignment required for instances of this type on the GC heap + /// + public LayoutInt InstanceByteAlignment + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) + { + ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); + } + return _instanceByteAlignment; + } + } + + /// + /// How many bytes must be allocated to represent the non GC visible static fields of this type. + /// + public LayoutInt NonGCStaticFieldSize + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) + { + ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.NonGcStatics.Size; + } + } + + /// + /// What is the alignment required for allocating the non GC visible static fields of this type. + /// + public LayoutInt NonGCStaticFieldAlignment + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) + { + ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.NonGcStatics.LargestAlignment; + } + } + + /// + /// How many bytes must be allocated to represent the GC visible static fields of this type. + /// + public LayoutInt GCStaticFieldSize + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) + { + ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.GcStatics.Size; + } + } + + /// + /// What is the alignment required for allocating the GC visible static fields of this type. + /// + public LayoutInt GCStaticFieldAlignment + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) + { + ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.GcStatics.LargestAlignment; + } + } + + /// + /// How many bytes must be allocated to represent the non GC visible thread static fields + /// of this type. + /// + public LayoutInt ThreadNonGcStaticFieldSize + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) + { + ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadNonGcStatics.Size; + } + } + + /// + /// What is the alignment required for allocating the non GC visible thread static fields + /// of this type. + /// + public LayoutInt ThreadNonGcStaticFieldAlignment + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) + { + ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadNonGcStatics.LargestAlignment; + } + } + + /// + /// How many bytes must be allocated to represent the (potentially GC visible) thread static + /// fields of this type. + /// + public LayoutInt ThreadGcStaticFieldSize + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) + { + ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadGcStatics.Size; + } + } + + /// + /// What is the alignment required for allocating the (potentially GC visible) thread static + /// fields of this type. + /// + public LayoutInt ThreadGcStaticFieldAlignment + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) + { + ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadGcStatics.LargestAlignment; + } + } + + /// + /// Gets a value indicating whether the fields of the type satisfy the Homogeneous Float Aggregate classification. + /// + public bool IsHfa + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics)) + { + ComputeValueTypeShapeCharacteristics(); + } + return (_valueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.HomogenousFloatAggregate) != 0; + } + } + + internal ValueTypeShapeCharacteristics ValueTypeShapeCharacteristics + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics)) + { + ComputeValueTypeShapeCharacteristics(); + } + return _valueTypeShapeCharacteristics; + } + } + + /// + /// Get the Homogeneous Float Aggregate element type if this is a HFA type ( is true). + /// + public DefType HfaElementType + { + get + { + // We are not caching this because this is rare and not worth wasting space in DefType. + return this.Context.GetLayoutAlgorithmForType(this).ComputeHomogeneousFloatAggregateElementType(this); + } + } + + private void ComputeValueTypeShapeCharacteristics() + { + _valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this); + _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics); + } + + + public void ComputeInstanceLayout(InstanceLayoutKind layoutKind) + { + if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout | FieldLayoutFlags.ComputedInstanceTypeLayout)) + return; + + var computedLayout = this.Context.GetLayoutAlgorithmForType(this).ComputeInstanceLayout(this, layoutKind); + + _instanceFieldSize = computedLayout.FieldSize; + _instanceFieldAlignment = computedLayout.FieldAlignment; + _instanceByteCountUnaligned = computedLayout.ByteCountUnaligned; + _instanceByteAlignment = computedLayout.ByteCountAlignment; + + if (computedLayout.Offsets != null) + { + foreach (var fieldAndOffset in computedLayout.Offsets) + { + Debug.Assert(fieldAndOffset.Field.OwningType == this); + fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset); + } + _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout); + } + + _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedInstanceTypeLayout); + } + + public void ComputeStaticFieldLayout(StaticLayoutKind layoutKind) + { + if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticFieldsLayout | FieldLayoutFlags.ComputedStaticRegionLayout)) + return; + + var computedStaticLayout = this.Context.GetLayoutAlgorithmForType(this).ComputeStaticFieldLayout(this, layoutKind); + + if ((computedStaticLayout.NonGcStatics.Size != LayoutInt.Zero) || + (computedStaticLayout.GcStatics.Size != LayoutInt.Zero) || + (computedStaticLayout.ThreadNonGcStatics.Size != LayoutInt.Zero) || + (computedStaticLayout.ThreadGcStatics.Size != LayoutInt.Zero)) + { + var staticBlockInfo = new StaticBlockInfo + { + NonGcStatics = computedStaticLayout.NonGcStatics, + GcStatics = computedStaticLayout.GcStatics, + ThreadNonGcStatics = computedStaticLayout.ThreadNonGcStatics, + ThreadGcStatics = computedStaticLayout.ThreadGcStatics + }; + _staticBlockInfo = staticBlockInfo; + } + + if (computedStaticLayout.Offsets != null) + { + foreach (var fieldAndOffset in computedStaticLayout.Offsets) + { + Debug.Assert(fieldAndOffset.Field.OwningType == this); + fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset); + } + _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedStaticFieldsLayout); + } + + _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedStaticRegionLayout); + } + + public void ComputeTypeContainsGCPointers() + { + if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedContainsGCPointers)) + return; + + int flagsToAdd = FieldLayoutFlags.ComputedContainsGCPointers; + + if (!IsValueType && HasBaseType && BaseType.ContainsGCPointers) + { + _fieldLayoutFlags.AddFlags(flagsToAdd | FieldLayoutFlags.ContainsGCPointers); + return; + } + + if (this.Context.GetLayoutAlgorithmForType(this).ComputeContainsGCPointers(this)) + { + flagsToAdd |= FieldLayoutFlags.ContainsGCPointers; + } + + _fieldLayoutFlags.AddFlags(flagsToAdd); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.cs new file mode 100644 index 00000000000..fb1cf075c91 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.cs @@ -0,0 +1,28 @@ +// 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 +{ + /// + /// Type that is logically equivalent to a type which is defined by a TypeDef + /// record in an ECMA 335 metadata stream - a class, an interface, or a value type. + /// + public abstract partial class DefType : TypeDesc + { + /// + /// Gets the namespace of the type. + /// + public virtual string Namespace => null; + + /// + /// Gets the name of the type as represented in the metadata. + /// + public virtual string Name => null; + + /// + /// Gets the containing type of this type or null if the type is not nested. + /// + public virtual DefType ContainingType => null; + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs new file mode 100644 index 00000000000..7de12aa4fe0 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs @@ -0,0 +1,41 @@ +// 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 +{ + /// + /// Represents an ID of a localized exception string. + /// + public enum ExceptionStringID + { + // TypeLoadException + ClassLoadGeneral, + ClassLoadExplicitGeneric, + ClassLoadBadFormat, + ClassLoadExplicitLayout, + ClassLoadValueClassTooLarge, + ClassLoadRankTooLarge, + + // MissingMethodException + MissingMethod, + + // MissingFieldException + MissingField, + + // FileNotFoundException + FileLoadErrorGeneric, + + // InvalidProgramException + InvalidProgramDefault, + InvalidProgramSpecific, + InvalidProgramVararg, + InvalidProgramCallVirtFinalize, + InvalidProgramNativeCallable, + InvalidProgramCallAbstractMethod, + InvalidProgramCallVirtStatic, + + // BadImageFormatException + BadImageFormatGeneric, + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs new file mode 100644 index 00000000000..b1c4ae54a09 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs @@ -0,0 +1,155 @@ +// 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; + +namespace Internal.TypeSystem +{ + public struct ExplicitLayoutValidator + { + private enum FieldLayoutTag : byte + { + Empty, + NonORef, + ORef, + } + + private readonly int _pointerSize; + + private readonly FieldLayoutTag[] _fieldLayout; + + private readonly MetadataType _typeBeingValidated; + + private ExplicitLayoutValidator(MetadataType type, int typeSizeInBytes) + { + _typeBeingValidated = type; + _pointerSize = type.Context.Target.PointerSize; + _fieldLayout = new FieldLayoutTag[typeSizeInBytes]; + } + + public static void Validate(MetadataType type, ComputedInstanceFieldLayout layout) + { + ExplicitLayoutValidator validator = new ExplicitLayoutValidator(type, layout.ByteCountUnaligned.AsInt); + foreach (FieldAndOffset fieldAndOffset in layout.Offsets) + { + validator.AddToFieldLayout(fieldAndOffset.Offset.AsInt, fieldAndOffset.Field.FieldType); + } + } + + private void AddToFieldLayout(int offset, TypeDesc fieldType) + { + if (fieldType.IsGCPointer) + { + if (offset % _pointerSize != 0) + { + // Misaligned ORef + ThrowFieldLayoutError(offset); + } + SetFieldLayout(offset, _pointerSize, FieldLayoutTag.ORef); + } + else if (fieldType.IsPointer || fieldType.IsFunctionPointer) + { + SetFieldLayout(offset, _pointerSize, FieldLayoutTag.NonORef); + } + else if (fieldType.IsValueType) + { + if (fieldType.IsByRefLike && offset % _pointerSize != 0) + { + // Misaligned ByRefLike + ThrowFieldLayoutError(offset); + } + + MetadataType mdType = (MetadataType)fieldType; + int fieldSize = mdType.InstanceByteCountUnaligned.AsInt; + if (!mdType.ContainsGCPointers) + { + // Plain value type, mark the entire range as NonORef + SetFieldLayout(offset, fieldSize, FieldLayoutTag.NonORef); + } + else + { + if (offset % _pointerSize != 0) + { + // Misaligned struct with GC pointers + ThrowFieldLayoutError(offset); + } + + bool[] fieldORefMap = new bool[fieldSize]; + MarkORefLocations(mdType, fieldORefMap, offset: 0); + for (int index = 0; index < fieldSize; index++) + { + SetFieldLayout(offset + index, fieldORefMap[index] ? FieldLayoutTag.ORef : FieldLayoutTag.NonORef); + } + } + } + else if (fieldType.IsByRef) + { + if (offset % _pointerSize != 0) + { + // Misaligned pointer field + ThrowFieldLayoutError(offset); + } + SetFieldLayout(offset, _pointerSize, FieldLayoutTag.NonORef); + } + else + { + Debug.Assert(false, fieldType.ToString()); + } + } + + private void MarkORefLocations(MetadataType type, bool[] orefMap, int offset) + { + // Recurse into struct fields + foreach (FieldDesc field in type.GetFields()) + { + if (!field.IsStatic) + { + int fieldOffset = offset + field.Offset.AsInt; + if (field.FieldType.IsGCPointer) + { + for (int index = 0; index < _pointerSize; index++) + { + orefMap[fieldOffset + index] = true; + } + } + else if (field.FieldType.IsValueType) + { + MetadataType mdFieldType = (MetadataType)field.FieldType; + if (mdFieldType.ContainsGCPointers) + { + MarkORefLocations(mdFieldType, orefMap, fieldOffset); + } + } + } + } + } + + private void SetFieldLayout(int offset, int count, FieldLayoutTag tag) + { + for (int index = 0; index < count; index++) + { + SetFieldLayout(offset + index, tag); + } + } + + private void SetFieldLayout(int offset, FieldLayoutTag tag) + { + FieldLayoutTag existingTag = _fieldLayout[offset]; + if (existingTag != tag) + { + if (existingTag != FieldLayoutTag.Empty) + { + ThrowFieldLayoutError(offset); + } + _fieldLayout[offset] = tag; + } + } + + private void ThrowFieldLayoutError(int offset) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadExplicitLayout, _typeBeingValidated, offset.ToStringInvariant()); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.FieldLayout.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.FieldLayout.cs new file mode 100644 index 00000000000..4452e8d6ee7 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.FieldLayout.cs @@ -0,0 +1,53 @@ +// 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; + +namespace Internal.TypeSystem +{ + // Api extensions for fields that allow keeping track of field layout + + public partial class FieldDesc + { + private LayoutInt _offset = FieldAndOffset.InvalidOffset; + + public LayoutInt Offset + { + get + { + if (_offset == FieldAndOffset.InvalidOffset) + { + if (IsStatic) + OwningType.ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizesAndFields); + else + OwningType.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields); + + // If the offset still wasn't computed, this must be a field that doesn't participate in layout + // (either literal or RVA mapped). We shouldn't be asking for the offset. + Debug.Assert(_offset != FieldAndOffset.InvalidOffset); + } + return _offset; + } + } + + /// + /// For static fields, represents whether or not the field is held in the GC or non GC statics region. + /// + public bool HasGCStaticBase + { + get + { + Debug.Assert(IsStatic); + return Context.ComputeHasGCStaticBase(this); + } + } + + internal void InitializeOffset(LayoutInt offset) + { + Debug.Assert(_offset == FieldAndOffset.InvalidOffset || _offset == offset); + _offset = offset; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.ToString.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.ToString.cs new file mode 100644 index 00000000000..29cea11d53e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.ToString.cs @@ -0,0 +1,14 @@ +// 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 +{ + partial class FieldDesc + { + public override string ToString() + { + return $"{OwningType}.{Name}"; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.cs new file mode 100644 index 00000000000..be2d81bd563 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldDesc.cs @@ -0,0 +1,99 @@ +// 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.Runtime.CompilerServices; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public abstract partial class FieldDesc : TypeSystemEntity + { + public static readonly FieldDesc[] EmptyFields = new FieldDesc[0]; + + public override int GetHashCode() + { + // Inherited types are expected to override + return RuntimeHelpers.GetHashCode(this); + } + + public override bool Equals(Object o) + { + // Its only valid to compare two FieldDescs in the same context + Debug.Assert(Object.ReferenceEquals(o, null) || !(o is FieldDesc) || Object.ReferenceEquals(((FieldDesc)o).Context, this.Context)); + return Object.ReferenceEquals(this, o); + } + + public virtual string Name + { + get + { + return null; + } + } + + public abstract DefType OwningType + { + get; + } + + public abstract TypeDesc FieldType + { + get; + } + + public abstract bool IsStatic + { + get; + } + + public abstract bool IsInitOnly + { + get; + } + + public abstract bool IsThreadStatic + { + get; + } + + public abstract bool HasRva + { + get; + } + + public abstract bool IsLiteral + { + get; + } + + public abstract bool HasCustomAttribute(string attributeNamespace, string attributeName); + + public virtual FieldDesc GetTypicalFieldDefinition() + { + return this; + } + + public bool IsTypicalFieldDefinition + { + get + { + return GetTypicalFieldDefinition() == this; + } + } + + public virtual FieldDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + FieldDesc field = this; + + TypeDesc owningType = field.OwningType; + TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); + if (owningType != instantiatedOwningType) + field = instantiatedOwningType.Context.GetFieldForInstantiatedType(field.GetTypicalFieldDefinition(), (InstantiatedType)instantiatedOwningType); + + return field; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/FieldForInstantiatedType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldForInstantiatedType.cs new file mode 100644 index 00000000000..5fac1161448 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldForInstantiatedType.cs @@ -0,0 +1,105 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public sealed partial class FieldForInstantiatedType : FieldDesc + { + private readonly FieldDesc _fieldDef; + private readonly InstantiatedType _instantiatedType; + + internal FieldForInstantiatedType(FieldDesc fieldDef, InstantiatedType instantiatedType) + { + Debug.Assert(fieldDef.GetTypicalFieldDefinition() == fieldDef); + _fieldDef = fieldDef; + _instantiatedType = instantiatedType; + } + + public override TypeSystemContext Context + { + get + { + return _fieldDef.Context; + } + } + + public override DefType OwningType + { + get + { + return _instantiatedType; + } + } + + public override string Name + { + get + { + return _fieldDef.Name; + } + } + + public override TypeDesc FieldType + { + get + { + return _fieldDef.FieldType.InstantiateSignature(_instantiatedType.Instantiation, new Instantiation()); + } + } + + public override bool IsStatic + { + get + { + return _fieldDef.IsStatic; + } + } + + public override bool IsInitOnly + { + get + { + return _fieldDef.IsInitOnly; + } + } + + public override bool IsThreadStatic + { + get + { + return _fieldDef.IsThreadStatic; + } + } + + public override bool HasRva + { + get + { + return _fieldDef.HasRva; + } + } + + public override bool IsLiteral + { + get + { + return _fieldDef.IsLiteral; + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return _fieldDef.HasCustomAttribute(attributeNamespace, attributeName); + } + + public override FieldDesc GetTypicalFieldDefinition() + { + return _fieldDef; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs new file mode 100644 index 00000000000..720c80a6597 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs @@ -0,0 +1,126 @@ +// 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 +{ + /// + /// Pluggable field layout algorithm. Provides means to compute static/instance sizes for types, + /// offsets for their fields and other type information that depends on type's fields. + /// The information computed by this algorithm is exposed on various properties of + /// and . + /// + /// + /// The algorithms are expected to be directly used by derivatives + /// only. The most obvious implementation of this algorithm that uses type's metadata to + /// compute the answers is in . + /// + public abstract class FieldLayoutAlgorithm + { + /// + /// Compute the instance field layout for a DefType. Must not depend on static field layout for any other type. + /// + public abstract ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind); + + /// + /// Compute the static field layout for a DefType. Must not depend on static field layout for any other type. + /// + public abstract ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, StaticLayoutKind layoutKind); + + /// + /// Compute whether the fields of the specified type contain a GC pointer. + /// + public abstract bool ComputeContainsGCPointers(DefType type); + + /// + /// Compute the shape of a valuetype. The shape information is used to control code generation and allocation + /// (such as vectorization, passing the valuetype by value across method calls, or boxing alignment). + /// + public abstract ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type); + + /// + /// If the type has characteristic, returns + /// the element type of the homogenous float aggregate. This will either be System.Double or System.Float. + /// + public abstract DefType ComputeHomogeneousFloatAggregateElementType(DefType type); + } + + /// + /// Specifies the level to which to compute the instance field layout. + /// + public enum InstanceLayoutKind + { + /// + /// Compute instance sizes and alignments. + /// + TypeOnly, + + /// + /// Compute instance sizes, alignments and field offsets. + /// + TypeAndFields + } + + /// + /// Specifies the level to which to compute static field layout. + /// + public enum StaticLayoutKind + { + /// + /// Compute static region sizes. + /// + StaticRegionSizes, + + /// + /// Compute static region sizes and static field offsets. + /// + StaticRegionSizesAndFields + } + + public struct ComputedInstanceFieldLayout + { + public LayoutInt FieldSize; + public LayoutInt FieldAlignment; + public LayoutInt ByteCountUnaligned; + public LayoutInt ByteCountAlignment; + + /// + /// If Offsets is non-null, then all field based layout is complete. + /// Otherwise, only the non-field based data is considered to be complete + /// + public FieldAndOffset[] Offsets; + } + + public struct StaticsBlock + { + public LayoutInt Size; + public LayoutInt LargestAlignment; + } + + public struct ComputedStaticFieldLayout + { + public StaticsBlock NonGcStatics; + public StaticsBlock GcStatics; + public StaticsBlock ThreadNonGcStatics; + public StaticsBlock ThreadGcStatics; + + /// + /// If Offsets is non-null, then all field based layout is complete. + /// Otherwise, only the non-field based data is considered to be complete + /// + public FieldAndOffset[] Offsets; + } + + /// + /// Describes shape of a value type for code generation and allocation purposes. + /// + public enum ValueTypeShapeCharacteristics + { + None = 0x00, + + /// + /// The structure is an aggregate of floating point values of the same type. + /// + HomogenousFloatAggregate = 0x01, + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/FunctionPointerType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/FunctionPointerType.cs new file mode 100644 index 00000000000..523b105d0fa --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/FunctionPointerType.cs @@ -0,0 +1,75 @@ +// 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.Text; + +namespace Internal.TypeSystem +{ + /// + /// Represents an unmanaged pointer to a method with a signature compatible with the signature of the pointer. + /// + public sealed partial class FunctionPointerType : TypeDesc + { + private MethodSignature _signature; + private int _hashCode; + + internal FunctionPointerType(MethodSignature signature) + { + _signature = signature; + } + + /// + /// Gets the signature of the method this pointer points to. + /// + public MethodSignature Signature + { + get + { + return _signature; + } + } + + public override TypeSystemContext Context + { + get + { + return _signature.ReturnType.Context; + } + } + + public override int GetHashCode() + { + if (_hashCode == 0) + _hashCode = _signature.GetHashCode(); + return _hashCode; + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + MethodSignatureBuilder sigBuilder = new MethodSignatureBuilder(_signature); + sigBuilder.ReturnType = _signature.ReturnType.InstantiateSignature(typeInstantiation, methodInstantiation); + for (int i = 0; i < _signature.Length; i++) + sigBuilder[i] = _signature[i].InstantiateSignature(typeInstantiation, methodInstantiation); + + MethodSignature instantiatedSignature = sigBuilder.ToSignature(); + if (instantiatedSignature != _signature) + return Context.GetFunctionPointerType(instantiatedSignature); + + return this; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = TypeFlags.FunctionPointer; + + flags |= TypeFlags.HasGenericVarianceComputed; + + flags |= TypeFlags.HasFinalizerComputed; + + flags |= TypeFlags.AttributeCacheComputed; + + return flags; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs new file mode 100644 index 00000000000..f78dc80fa6a --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs @@ -0,0 +1,17 @@ +// 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.Collections.Generic; + +namespace Internal.TypeSystem +{ + public abstract partial class GenericParameterDesc + { + /// + /// Gets the name of the generic parameter as defined in the metadata. This must not throw + /// + public abstract string DiagnosticName { get; } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/GenericParameterDesc.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/GenericParameterDesc.cs new file mode 100644 index 00000000000..4eff6c6cbc5 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/GenericParameterDesc.cs @@ -0,0 +1,179 @@ +// 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.Collections.Generic; + +namespace Internal.TypeSystem +{ + public enum GenericParameterKind + { + Type, + Method, + } + + /// + /// Describes the variance on a generic type parameter of a generic type or method. + /// + public enum GenericVariance + { + None = 0, + + /// + /// The generic type parameter is covariant. A covariant type parameter can appear + /// as the result type of a method, the type of a read-only field, a declared base + /// type, or an implemented interface. + /// + Covariant = 1, + + /// + /// The generic type parameter is contravariant. A contravariant type parameter can + /// appear as a parameter type in method signatures. + /// + Contravariant = 2 + } + + /// + /// Describes the constraints on a generic type parameter of a generic type or method. + /// + [Flags] + public enum GenericConstraints + { + None = 0, + + /// + /// A type can be substituted for the generic type parameter only if it is a reference type. + /// + ReferenceTypeConstraint = 0x04, + + /// + // A type can be substituted for the generic type parameter only if it is a value + // type and is not nullable. + /// + NotNullableValueTypeConstraint = 0x08, + + /// + /// A type can be substituted for the generic type parameter only if it has a parameterless + /// constructor. + /// + DefaultConstructorConstraint = 0x10, + } + + public abstract partial class GenericParameterDesc : TypeDesc + { + /// + /// Gets the name of the generic parameter as defined in the metadata. + /// + public virtual string Name + { + get + { + return String.Concat("T", Index.ToStringInvariant()); + } + } + + /// + /// Gets a value indicating whether this is a type or method generic parameter. + /// + public abstract GenericParameterKind Kind { get; } + + /// + /// Gets the zero based index of the generic parameter within the declaring type or method. + /// + public abstract int Index { get; } + + /// + /// Gets a value indicating the variance of this generic parameter. + /// + public virtual GenericVariance Variance + { + get + { + return GenericVariance.None; + } + } + + /// + /// Gets a value indicating generic constraints of this generic parameter. + /// + public virtual GenericConstraints Constraints + { + get + { + return GenericConstraints.None; + } + } + + /// + /// Gets type constraints imposed on substitutions. + /// + public virtual IEnumerable TypeConstraints + { + get + { + return TypeDesc.EmptyTypes; + } + } + + public bool HasNotNullableValueTypeConstraint + { + get + { + return (Constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0; + } + } + + public bool HasReferenceTypeConstraint + { + get + { + return (Constraints & GenericConstraints.ReferenceTypeConstraint) != 0; + } + } + + public bool HasDefaultConstructorConstraint + { + get + { + return (Constraints & GenericConstraints.DefaultConstructorConstraint) != 0; + } + } + + public bool IsCovariant + { + get + { + return (Variance & GenericVariance.Covariant) != 0; + } + } + + public bool IsContravariant + { + get + { + return (Variance & GenericVariance.Contravariant) != 0; + } + } + + protected sealed override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + flags |= TypeFlags.GenericParameter; + + flags |= TypeFlags.HasGenericVarianceComputed; + + flags |= TypeFlags.AttributeCacheComputed; + + return flags; + } + + public sealed override int GetHashCode() + { + // TODO: Determine what a the right hash function should be. Use stable hashcode based on the type name? + // For now, use the same hash as a SignatureVariable type. + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeSignatureVariableHashCode(Index, Kind == GenericParameterKind.Method); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/IAssemblyDesc.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/IAssemblyDesc.cs new file mode 100644 index 00000000000..e9db5b76e92 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/IAssemblyDesc.cs @@ -0,0 +1,19 @@ +// 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.Reflection; + +namespace Internal.TypeSystem +{ + /// + /// Optional interface a should implement if it represents an assembly. + /// + public interface IAssemblyDesc + { + /// + /// Gets the assembly name. + /// + AssemblyName GetName(); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs new file mode 100644 index 00000000000..c33020e88e1 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs @@ -0,0 +1,17 @@ +// 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 +{ + public sealed partial class InstantiatedMethod + { + public override string DiagnosticName + { + get + { + return _methodDef.DiagnosticName; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedMethod.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedMethod.cs new file mode 100644 index 00000000000..f73366c0a54 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedMethod.cs @@ -0,0 +1,154 @@ +// 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 System.Text; +using Internal.NativeFormat; + +namespace Internal.TypeSystem +{ + public sealed partial class InstantiatedMethod : MethodDesc + { + private MethodDesc _methodDef; + private Instantiation _instantiation; + + private MethodSignature _signature; + + internal InstantiatedMethod(MethodDesc methodDef, Instantiation instantiation) + { + Debug.Assert(!(methodDef is InstantiatedMethod)); + _methodDef = methodDef; + + Debug.Assert(instantiation.Length > 0); + _instantiation = instantiation; + } + + // This constructor is a performance optimization - it allows supplying the hash code if it has already + // been computed prior to the allocation of this type. The supplied hash code still has to match the + // hash code this type would compute on it's own (and we assert to enforce that). + internal InstantiatedMethod(MethodDesc methodDef, Instantiation instantiation, int hashcode) + : this(methodDef, instantiation) + { + SetHashCode(hashcode); + } + + protected override int ComputeHashCode() + { + return TypeHashingAlgorithms.ComputeMethodHashCode(OwningType.GetHashCode(), Instantiation.ComputeGenericInstanceHashCode(TypeHashingAlgorithms.ComputeNameHashCode(Name))); + } + + public override TypeSystemContext Context + { + get + { + return _methodDef.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _methodDef.OwningType; + } + } + + private TypeDesc Instantiate(TypeDesc type) + { + return type.InstantiateSignature(new Instantiation(), _instantiation); + } + + public override MethodSignature Signature + { + get + { + if (_signature == null) + { + MethodSignature template = _methodDef.Signature; + MethodSignatureBuilder builder = new MethodSignatureBuilder(template); + + builder.ReturnType = Instantiate(template.ReturnType); + for (int i = 0; i < template.Length; i++) + builder[i] = Instantiate(template[i]); + + _signature = builder.ToSignature(); + } + + return _signature; + } + } + + public override Instantiation Instantiation + { + get + { + return _instantiation; + } + } + + public override bool IsVirtual + { + get + { + return _methodDef.IsVirtual; + } + } + + public override bool IsNewSlot + { + get + { + return _methodDef.IsNewSlot; + } + } + + public override bool IsAbstract + { + get + { + return _methodDef.IsAbstract; + } + } + + public override bool IsFinal + { + get + { + return _methodDef.IsFinal; + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return _methodDef.HasCustomAttribute(attributeNamespace, attributeName); + } + + public override bool IsDefaultConstructor + { + get + { + return false; + } + } + + public override MethodDesc GetMethodDefinition() + { + return _methodDef; + } + + public override MethodDesc GetTypicalMethodDefinition() + { + return _methodDef.GetTypicalMethodDefinition(); + } + + public override string Name + { + get + { + return _methodDef.Name; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs new file mode 100644 index 00000000000..5490cf1dc62 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs @@ -0,0 +1,25 @@ +// 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 +{ + public sealed partial class InstantiatedType + { + public override string DiagnosticName + { + get + { + return _typeDef.DiagnosticName; + } + } + + public override string DiagnosticNamespace + { + get + { + return _typeDef.DiagnosticNamespace; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.Interfaces.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.Interfaces.cs new file mode 100644 index 00000000000..a51056923fe --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.Interfaces.cs @@ -0,0 +1,36 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Implementation for Instantiated type specific interface logic + + public sealed partial class InstantiatedType : MetadataType + { + private DefType[] _implementedInterfaces = null; + + private DefType[] InitializeImplementedInterfaces() + { + return InstantiateTypeArray(_typeDef.ExplicitlyImplementedInterfaces, _instantiation, new Instantiation()); + + // TODO Add duplicate detection + } + + /// + /// The interfaces explicitly declared as implemented by this InstantiatedType. Duplicates are not permitted + /// + public override DefType[] ExplicitlyImplementedInterfaces + { + get + { + if (_implementedInterfaces == null) + return InitializeImplementedInterfaces(); + return _implementedInterfaces; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.MethodImpls.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.MethodImpls.cs new file mode 100644 index 00000000000..474ac1a6ae3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.MethodImpls.cs @@ -0,0 +1,57 @@ +// 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; + +namespace Internal.TypeSystem +{ + // Implementation of MethodImpl api surface implemented without metadata access. + public partial class InstantiatedType + { + /// + /// Instantiate a MethodImplRecord from uninstantiated form to instantiated form + /// + /// + /// + private MethodImplRecord[] InstantiateMethodImpls(MethodImplRecord[] uninstMethodImpls) + { + if (uninstMethodImpls == null || uninstMethodImpls.Length == 0) + return uninstMethodImpls; + + MethodImplRecord[] instMethodImpls = new MethodImplRecord[uninstMethodImpls.Length]; + + for (int i = 0; i < uninstMethodImpls.Length; i++) + { + MethodDesc decl; + + var implTypeInstantiated = uninstMethodImpls[i].Decl.OwningType.InstantiateSignature(this.Instantiation, new Instantiation()); + if (implTypeInstantiated is InstantiatedType) + { + decl = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Decl.GetTypicalMethodDefinition(), (InstantiatedType)implTypeInstantiated); + } + else + { + decl = uninstMethodImpls[i].Decl; + } + + MethodDesc body = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Body, this); + instMethodImpls[i] = new MethodImplRecord(decl, body); + } + + return instMethodImpls; + } + + protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() + { + MethodImplRecord[] uninstMethodImpls = _typeDef.VirtualMethodImplsForType; + return InstantiateMethodImpls(uninstMethodImpls); + } + + public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name) + { + MethodImplRecord[] uninstMethodImpls = _typeDef.FindMethodsImplWithMatchingDeclName(name); + return InstantiateMethodImpls(uninstMethodImpls); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.cs new file mode 100644 index 00000000000..a777f223f09 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/InstantiatedType.cs @@ -0,0 +1,367 @@ +// 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.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace Internal.TypeSystem +{ + public sealed partial class InstantiatedType : MetadataType + { + private MetadataType _typeDef; + private Instantiation _instantiation; + + internal InstantiatedType(MetadataType typeDef, Instantiation instantiation) + { + Debug.Assert(!(typeDef is InstantiatedType)); + _typeDef = typeDef; + + Debug.Assert(instantiation.Length > 0); + _instantiation = instantiation; + + _baseType = this; // Not yet initialized flag + } + + private int _hashCode; + + public override int GetHashCode() + { + if (_hashCode == 0) + _hashCode = _instantiation.ComputeGenericInstanceHashCode(_typeDef.GetHashCode()); + return _hashCode; + } + + public override TypeSystemContext Context + { + get + { + return _typeDef.Context; + } + } + + public override Instantiation Instantiation + { + get + { + return _instantiation; + } + } + + private MetadataType _baseType /* = this */; + + private MetadataType InitializeBaseType() + { + var uninst = _typeDef.MetadataBaseType; + + return (_baseType = (uninst != null) ? (MetadataType)uninst.InstantiateSignature(_instantiation, new Instantiation()) : null); + } + + public override DefType BaseType + { + get + { + if (_baseType == this) + return InitializeBaseType(); + return _baseType; + } + } + + public override MetadataType MetadataBaseType + { + get + { + if (_baseType == this) + return InitializeBaseType(); + return _baseType; + } + } + + // Type system implementations that support the notion of intrinsic types + // will provide an implementation that adds the flag if necessary. + partial void AddComputedIntrinsicFlag(ref TypeFlags flags); + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + if ((mask & TypeFlags.CategoryMask) != 0) + { + flags |= _typeDef.Category; + } + + if ((mask & TypeFlags.HasGenericVarianceComputed) != 0) + { + flags |= TypeFlags.HasGenericVarianceComputed; + + if (_typeDef.HasVariance) + flags |= TypeFlags.HasGenericVariance; + } + + if ((mask & TypeFlags.HasFinalizerComputed) != 0) + { + flags |= TypeFlags.HasFinalizerComputed; + + if (_typeDef.HasFinalizer) + flags |= TypeFlags.HasFinalizer; + } + + if ((mask & TypeFlags.AttributeCacheComputed) != 0) + { + flags |= TypeFlags.AttributeCacheComputed; + + if (_typeDef.IsByRefLike) + flags |= TypeFlags.IsByRefLike; + + AddComputedIntrinsicFlag(ref flags); + } + + return flags; + } + + public override string Name + { + get + { + return _typeDef.Name; + } + } + + public override string Namespace + { + get + { + return _typeDef.Namespace; + } + } + + public override IEnumerable GetMethods() + { + foreach (var typicalMethodDef in _typeDef.GetMethods()) + { + yield return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this); + } + } + + // TODO: Substitutions, generics, modopts, ... + public override MethodDesc GetMethod(string name, MethodSignature signature) + { + MethodDesc typicalMethodDef = _typeDef.GetMethod(name, signature); + if (typicalMethodDef == null) + return null; + return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this); + } + + public override MethodDesc GetStaticConstructor() + { + MethodDesc typicalCctor = _typeDef.GetStaticConstructor(); + if (typicalCctor == null) + return null; + return _typeDef.Context.GetMethodForInstantiatedType(typicalCctor, this); + } + + public override MethodDesc GetDefaultConstructor() + { + MethodDesc typicalCtor = _typeDef.GetDefaultConstructor(); + if (typicalCtor == null) + return null; + return _typeDef.Context.GetMethodForInstantiatedType(typicalCtor, this); + } + + public override MethodDesc GetFinalizer() + { + MethodDesc typicalFinalizer = _typeDef.GetFinalizer(); + if (typicalFinalizer == null) + return null; + + MetadataType typeInHierarchy = this; + + // Note, we go back to the type definition/typical method definition in this code. + // If the finalizer is implemented on a base type that is also a generic, then the + // typicalFinalizer in that case is a MethodForInstantiatedType for an instantiated type + // which is instantiated over the open type variables of the derived type. + + while (typicalFinalizer.OwningType.GetTypeDefinition() != typeInHierarchy.GetTypeDefinition()) + { + typeInHierarchy = typeInHierarchy.MetadataBaseType; + } + + if (typeInHierarchy == typicalFinalizer.OwningType) + { + return typicalFinalizer; + } + else + { + Debug.Assert(typeInHierarchy is InstantiatedType); + return _typeDef.Context.GetMethodForInstantiatedType(typicalFinalizer.GetTypicalMethodDefinition(), (InstantiatedType)typeInHierarchy); + } + } + + public override IEnumerable GetFields() + { + foreach (var fieldDef in _typeDef.GetFields()) + { + yield return _typeDef.Context.GetFieldForInstantiatedType(fieldDef, this); + } + } + + // TODO: Substitutions, generics, modopts, ... + public override FieldDesc GetField(string name) + { + FieldDesc fieldDef = _typeDef.GetField(name); + if (fieldDef == null) + return null; + return _typeDef.Context.GetFieldForInstantiatedType(fieldDef, this); + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc[] clone = null; + + for (int i = 0; i < _instantiation.Length; i++) + { + TypeDesc uninst = _instantiation[i]; + TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); + if (inst != uninst) + { + if (clone == null) + { + clone = new TypeDesc[_instantiation.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = _instantiation[j]; + } + } + clone[i] = inst; + } + } + + return (clone == null) ? this : _typeDef.Context.GetInstantiatedType(_typeDef, new Instantiation(clone)); + } + + /// + /// Instantiate an array of TypeDescs over typeInstantiation and methodInstantiation + /// + public static T[] InstantiateTypeArray(T[] uninstantiatedTypes, Instantiation typeInstantiation, Instantiation methodInstantiation) where T : TypeDesc + { + T[] clone = null; + + for (int i = 0; i < uninstantiatedTypes.Length; i++) + { + T uninst = uninstantiatedTypes[i]; + TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); + if (inst != uninst) + { + if (clone == null) + { + clone = new T[uninstantiatedTypes.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = uninstantiatedTypes[j]; + } + } + clone[i] = (T)inst; + } + } + + return clone != null ? clone : uninstantiatedTypes; + } + + // Strips instantiation. E.g C -> C + public override TypeDesc GetTypeDefinition() + { + return _typeDef; + } + + // Properties that are passed through from the type definition + public override ClassLayoutMetadata GetClassLayout() + { + return _typeDef.GetClassLayout(); + } + + public override bool IsExplicitLayout + { + get + { + return _typeDef.IsExplicitLayout; + } + } + + public override bool IsSequentialLayout + { + get + { + return _typeDef.IsSequentialLayout; + } + } + + public override bool IsBeforeFieldInit + { + get + { + return _typeDef.IsBeforeFieldInit; + } + } + + public override bool IsModuleType + { + get + { + // The global module type cannot be generic. + return false; + } + } + + public override bool IsSealed + { + get + { + return _typeDef.IsSealed; + } + } + + public override bool IsAbstract + { + get + { + return _typeDef.IsAbstract; + } + } + + public override ModuleDesc Module + { + get + { + return _typeDef.Module; + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return _typeDef.HasCustomAttribute(attributeNamespace, attributeName); + } + + public override DefType ContainingType + { + get + { + // Return the result from the typical type definition. + return _typeDef.ContainingType; + } + } + + public override MetadataType GetNestedType(string name) + { + // Return the result from the typical type definition. + return _typeDef.GetNestedType(name); + } + + public override IEnumerable GetNestedTypes() + { + // Return the result from the typical type definition. + return _typeDef.GetNestedTypes(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Instantiation.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Instantiation.cs new file mode 100644 index 00000000000..d403f0c9bdb --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Instantiation.cs @@ -0,0 +1,113 @@ +// 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.Runtime.CompilerServices; +using System.Text; + +namespace Internal.TypeSystem +{ + /// + /// Represents a generic instantiation - a collection of generic parameters + /// or arguments of a generic type or a generic method. + /// + public struct Instantiation + { + private TypeDesc[] _genericParameters; + + public Instantiation(params TypeDesc[] genericParameters) + { + _genericParameters = genericParameters; + } + + [IndexerName("GenericParameters")] + public TypeDesc this[int index] + { + get + { + return _genericParameters[index]; + } + } + + public int Length + { + get + { + return _genericParameters.Length; + } + } + + public bool IsNull + { + get + { + return _genericParameters == null; + } + } + + /// + /// Combines the given generic definition's hash code with the hashes + /// of the generic parameters in this instantiation + /// + public int ComputeGenericInstanceHashCode(int genericDefinitionHashCode) + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeGenericInstanceHashCode(genericDefinitionHashCode, _genericParameters); + } + + public static readonly Instantiation Empty = new Instantiation(TypeDesc.EmptyTypes); + + public Enumerator GetEnumerator() + { + return new Enumerator(_genericParameters); + } + + public override string ToString() + { + if (_genericParameters == null) + return String.Empty; + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < _genericParameters.Length; i++) + { + if (i > 0) + sb.Append(", "); + sb.Append(_genericParameters[i]); + } + return sb.ToString(); + } + + /// + /// Enumerator for iterating over the types in an instantiation + /// + public struct Enumerator + { + private TypeDesc[] _collection; + private int _currentIndex; + + public Enumerator(TypeDesc[] collection) + { + _collection = collection; + _currentIndex = -1; + } + + public TypeDesc Current + { + get + { + return _collection[_currentIndex]; + } + } + + public bool MoveNext() + { + _currentIndex++; + if (_currentIndex >= _collection.Length) + { + return false; + } + return true; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/LayoutInt.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/LayoutInt.cs new file mode 100644 index 00000000000..331bdec0f4f --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/LayoutInt.cs @@ -0,0 +1,136 @@ +// 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; + +namespace Internal.TypeSystem +{ + /// + /// A integer type used for layout calculations. Supports addition, max, min, comparison and alignup operations + /// A custom type is used to allow the concept of an indeterminate value. (Some types representable in the + /// type system do not have a known size. This type is used to make such sizes viral through the type layout + /// computations) + /// + public struct LayoutInt + { + private int _value; + + public static LayoutInt Indeterminate = CreateIndeterminateLayoutInt(); + public static LayoutInt Zero = new LayoutInt(0); + public static LayoutInt One = new LayoutInt(1); + + public LayoutInt(int input) + { + if (input < 0) + { + throw new ArgumentException(); + } + else + { + _value = input; + } + } + + private static LayoutInt CreateIndeterminateLayoutInt() + { + LayoutInt output = default(LayoutInt); + output._value = -1; + Debug.Assert(output.IsIndeterminate); + return output; + } + + public bool IsIndeterminate => _value == -1; + public int AsInt + { + get + { + if (IsIndeterminate) + throw new InvalidOperationException(); + return _value; + } + } + + public override string ToString() + { + return ToStringInvariant(); + } + + public string ToStringInvariant() + { + if (IsIndeterminate) + return "Indeterminate"; + else + return _value.ToStringInvariant(); + } + + public static bool operator ==(LayoutInt left, LayoutInt right) + { + return left._value == right._value; + } + + public static bool operator !=(LayoutInt left, LayoutInt right) + { + return left._value != right._value; + } + + public static LayoutInt operator+(LayoutInt left, LayoutInt right) + { + if (left.IsIndeterminate || right.IsIndeterminate) + return Indeterminate; + + return new LayoutInt(checked(left._value + right._value)); + } + + public override bool Equals(object obj) + { + if (obj is LayoutInt) + { + return this == (LayoutInt)obj; + } + return false; + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + public static LayoutInt Max(LayoutInt left, LayoutInt right) + { + if (left.IsIndeterminate || right.IsIndeterminate) + return Indeterminate; + + return new LayoutInt(Math.Max(left._value, right._value)); + } + + public static LayoutInt Min(LayoutInt left, LayoutInt right) + { + if (left.IsIndeterminate || right.IsIndeterminate) + return Indeterminate; + + return new LayoutInt(Math.Min(left._value, right._value)); + } + + public static LayoutInt AlignUp(LayoutInt value, LayoutInt alignment, TargetDetails target) + { + if (value.IsIndeterminate || alignment.IsIndeterminate) + { + // If value is already aligned to maximum possible alignment, then whatever + // alignment is can't change value + if (!value.IsIndeterminate) + { + if (value.AsInt.AlignUp(target.MaximumAlignment) == value.AsInt) + return value; + } + return Indeterminate; + } + + Debug.Assert(alignment._value <= target.MaximumAlignment); // Assert that the alignment handling for indeterminate types is safe + Debug.Assert(alignment._value >= 1 || ((value._value == 0) && (alignment._value == 0))); // Alignment to less than one doesn't make sense, except for 0 to 0 alignment + + return new LayoutInt(AlignmentHelper.AlignUp(value._value, alignment._value)); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/LocalVariableDefinition.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/LocalVariableDefinition.cs new file mode 100644 index 00000000000..95f978a49d9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/LocalVariableDefinition.cs @@ -0,0 +1,31 @@ +// 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 +{ + public struct LocalVariableDefinition + { + /// + /// Gets a value indicating whether the stored target should be pinned in the runtime + /// heap and shouldn't be moved by the actions of the garbage collector. + /// + public readonly bool IsPinned; + + /// + /// Gets the type of the local variable. + /// + public readonly TypeDesc Type; + + public LocalVariableDefinition(TypeDesc type, bool isPinned) + { + IsPinned = isPinned; + Type = type; + } + + public override string ToString() + { + return IsPinned ? "pinned " + Type.ToString() : Type.ToString(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs new file mode 100644 index 00000000000..b998f6dce93 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -0,0 +1,957 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// MetadataFieldLayout algorithm which can be used to compute field layout + /// for any MetadataType where all fields are available by calling GetFields. + /// + public class MetadataFieldLayoutAlgorithm : FieldLayoutAlgorithm + { + public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind) + { + MetadataType type = (MetadataType)defType; + // CLI - Partition 1, section 9.5 - Generic types shall not be marked explicitlayout. + if (type.HasInstantiation && type.IsExplicitLayout) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadExplicitGeneric, type.GetTypeDefinition()); + } + + // Count the number of instance fields in advance for convenience + int numInstanceFields = 0; + foreach (var field in type.GetFields()) + { + if (field.IsStatic) + continue; + + TypeDesc fieldType = field.FieldType; + + // ByRef instance fields are not allowed. + if (fieldType.IsByRef) + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + + // ByRef-like instance fields on non-byref-like types are not allowed. + if (fieldType.IsByRefLike && !type.IsByRefLike) + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + + numInstanceFields++; + } + + if (type.IsModuleType) + { + // This is a global type, it must not have instance fields. + if (numInstanceFields > 0) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + // Global types do not do the rest of instance field layout. + ComputedInstanceFieldLayout result = new ComputedInstanceFieldLayout(); + result.Offsets = Array.Empty(); + return result; + } + + // CLI - Partition 2, section 22.8 + // A type has layout if it is marked SequentialLayout or ExplicitLayout. If any type within an inheritance chain has layout, + // then so shall all its base classes, up to the one that descends immediately from System.ValueType (if it exists in the type’s + // hierarchy); otherwise, from System.Object + // Note: While the CLI isn't clearly worded, the layout needs to be the same for the entire chain. + // If the current type isn't ValueType or System.Object and has a layout and the parent type isn't + // ValueType or System.Object then the layout type attributes need to match + if ((!type.IsValueType && !type.IsObject) && + (type.IsSequentialLayout || type.IsExplicitLayout) && + (!type.BaseType.IsValueType && !type.BaseType.IsObject)) + { + MetadataType baseType = type.MetadataBaseType; + + if (type.IsSequentialLayout != baseType.IsSequentialLayout || + type.IsExplicitLayout != baseType.IsExplicitLayout) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type); + } + } + + // Enum types must have a single instance field + if (type.IsEnum && numInstanceFields != 1) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + if (type.IsPrimitive) + { + // Primitive types are special - they may have a single field of the same type + // as the type itself. They do not do the rest of instance field layout. + if (numInstanceFields > 1) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + SizeAndAlignment instanceByteSizeAndAlignment; + var sizeAndAlignment = ComputeInstanceSize( + type, + type.Context.Target.GetWellKnownTypeSize(type), + type.Context.Target.GetWellKnownTypeAlignment(type), + out instanceByteSizeAndAlignment + ); + + ComputedInstanceFieldLayout result = new ComputedInstanceFieldLayout + { + ByteCountUnaligned = instanceByteSizeAndAlignment.Size, + ByteCountAlignment = instanceByteSizeAndAlignment.Alignment, + FieldAlignment = sizeAndAlignment.Alignment, + FieldSize = sizeAndAlignment.Size, + }; + + if (numInstanceFields > 0) + { + FieldDesc instanceField = null; + foreach (FieldDesc field in type.GetFields()) + { + if (!field.IsStatic) + { + Debug.Assert(instanceField == null, "Unexpected extra instance field"); + instanceField = field; + } + } + + Debug.Assert(instanceField != null, "Null instance field"); + + result.Offsets = new FieldAndOffset[] { + new FieldAndOffset(instanceField, LayoutInt.Zero) + }; + } + else + { + result.Offsets = Array.Empty(); + } + + return result; + } + + // If the type has layout, read its packing and size info + // If the type has explicit layout, also read the field offset info + if (type.IsExplicitLayout || type.IsSequentialLayout) + { + if (type.IsEnum) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type); + } + + var layoutMetadata = type.GetClassLayout(); + + // If packing is out of range or not a power of two, throw that the size is invalid + int packing = layoutMetadata.PackingSize; + if (packing < 0 || packing > 128 || ((packing & (packing - 1)) != 0)) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type); + } + + Debug.Assert(layoutMetadata.Offsets == null || layoutMetadata.Offsets.Length == numInstanceFields); + } + + // At this point all special cases are handled and all inputs validated + return ComputeInstanceFieldLayout(type, numInstanceFields); + } + + protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(MetadataType type, int numInstanceFields) + { + if (type.IsExplicitLayout) + { + return ComputeExplicitFieldLayout(type, numInstanceFields); + } + else if (type.IsSequentialLayout || type.Context.Target.Abi == TargetAbi.CppCodegen) + { + return ComputeSequentialFieldLayout(type, numInstanceFields); + } + else + { + return ComputeAutoFieldLayout(type, numInstanceFields); + } + } + + public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind) + { + MetadataType type = (MetadataType)defType; + int numStaticFields = 0; + + foreach (var field in type.GetFields()) + { + if (!field.IsStatic || field.HasRva || field.IsLiteral) + continue; + + numStaticFields++; + } + + ComputedStaticFieldLayout result; + result.GcStatics = new StaticsBlock(); + result.NonGcStatics = new StaticsBlock(); + result.ThreadGcStatics = new StaticsBlock(); + result.ThreadNonGcStatics = new StaticsBlock(); + + if (numStaticFields == 0) + { + result.Offsets = Array.Empty(); + return result; + } + + result.Offsets = new FieldAndOffset[numStaticFields]; + + TypeSystemContext context = type.Context; + + PrepareRuntimeSpecificStaticFieldLayout(context, ref result); + + int index = 0; + + foreach (var field in type.GetFields()) + { + // Nonstatic fields, literal fields, and RVA mapped fields don't participate in layout + if (!field.IsStatic || field.HasRva || field.IsLiteral) + continue; + + TypeDesc fieldType = field.FieldType; + if (fieldType.IsByRef || (fieldType.IsValueType && ((DefType)fieldType).IsByRefLike)) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); + } + + ref StaticsBlock block = ref GetStaticsBlockForField(ref result, field); + SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, context.Target.DefaultPackingSize); + + block.Size = LayoutInt.AlignUp(block.Size, sizeAndAlignment.Alignment, context.Target); + result.Offsets[index] = new FieldAndOffset(field, block.Size); + block.Size = block.Size + sizeAndAlignment.Size; + + block.LargestAlignment = LayoutInt.Max(block.LargestAlignment, sizeAndAlignment.Alignment); + + index++; + } + + FinalizeRuntimeSpecificStaticFieldLayout(context, ref result); + + return result; + } + + private ref StaticsBlock GetStaticsBlockForField(ref ComputedStaticFieldLayout layout, FieldDesc field) + { + if (field.IsThreadStatic) + { + if (field.HasGCStaticBase) + return ref layout.ThreadGcStatics; + else + return ref layout.ThreadNonGcStatics; + } + else if (field.HasGCStaticBase) + return ref layout.GcStatics; + else + return ref layout.NonGcStatics; + } + + public override bool ComputeContainsGCPointers(DefType type) + { + bool someFieldContainsPointers = false; + + foreach (var field in type.GetFields()) + { + if (field.IsStatic) + continue; + + TypeDesc fieldType = field.FieldType; + if (fieldType.IsValueType) + { + if (fieldType.IsPrimitive) + continue; + + if (((DefType)fieldType).ContainsGCPointers) + { + someFieldContainsPointers = true; + break; + } + } + else if (fieldType.IsGCPointer) + { + someFieldContainsPointers = true; + break; + } + } + + return someFieldContainsPointers; + } + + /// + /// Called during static field layout to setup initial contents of statics blocks + /// + protected virtual void PrepareRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout) + { + } + + /// + /// Called during static field layout to finish static block layout + /// + protected virtual void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout) + { + } + + protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields) + { + // Instance slice size is the total size of instance not including the base type. + // It is calculated as the field whose offset and size add to the greatest value. + LayoutInt cumulativeInstanceFieldPos = + type.HasBaseType && !type.IsValueType ? type.BaseType.InstanceByteCount : LayoutInt.Zero; + LayoutInt instanceSize = cumulativeInstanceFieldPos; + + var layoutMetadata = type.GetClassLayout(); + + int packingSize = ComputePackingSize(type, layoutMetadata); + LayoutInt largestAlignmentRequired = LayoutInt.One; + + var offsets = new FieldAndOffset[numInstanceFields]; + int fieldOrdinal = 0; + + foreach (var fieldAndOffset in layoutMetadata.Offsets) + { + TypeDesc fieldType = fieldAndOffset.Field.FieldType; + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize); + + largestAlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequired); + + if (fieldAndOffset.Offset == FieldAndOffset.InvalidOffset) + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type); + + LayoutInt computedOffset = fieldAndOffset.Offset + cumulativeInstanceFieldPos; + + // GC pointers MUST be aligned. + // We treat byref-like structs as GC pointers too. + bool needsToBeAligned = + !computedOffset.IsIndeterminate + && + ( + fieldType.IsGCPointer + || fieldType.IsByRefLike + || (fieldType.IsValueType && ((DefType)fieldType).ContainsGCPointers) + ); + if (needsToBeAligned) + { + int offsetModulo = computedOffset.AsInt % type.Context.Target.PointerSize; + if (offsetModulo != 0) + { + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadExplicitLayout, type, fieldAndOffset.Offset.ToStringInvariant()); + } + } + + offsets[fieldOrdinal] = new FieldAndOffset(fieldAndOffset.Field, computedOffset); + + LayoutInt fieldExtent = computedOffset + fieldSizeAndAlignment.Size; + instanceSize = LayoutInt.Max(fieldExtent, instanceSize); + + fieldOrdinal++; + } + + if (type.IsValueType) + { + instanceSize = LayoutInt.Max(new LayoutInt(layoutMetadata.Size), instanceSize); + } + + SizeAndAlignment instanceByteSizeAndAlignment; + var instanceSizeAndAlignment = ComputeInstanceSize(type, instanceSize, largestAlignmentRequired, out instanceByteSizeAndAlignment); + + ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); + computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; + computedLayout.FieldSize = instanceSizeAndAlignment.Size; + computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; + computedLayout.ByteCountAlignment = instanceByteSizeAndAlignment.Alignment; + computedLayout.Offsets = offsets; + + ExplicitLayoutValidator.Validate(type, computedLayout); + + return computedLayout; + } + + protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType type, int numInstanceFields) + { + var offsets = new FieldAndOffset[numInstanceFields]; + + // For types inheriting from another type, field offsets continue on from where they left off + LayoutInt cumulativeInstanceFieldPos = ComputeBytesUsedInParentType(type); + + var layoutMetadata = type.GetClassLayout(); + + LayoutInt largestAlignmentRequirement = LayoutInt.One; + int fieldOrdinal = 0; + int packingSize = ComputePackingSize(type, layoutMetadata); + + foreach (var field in type.GetFields()) + { + if (field.IsStatic) + continue; + + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize); + + largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement); + + cumulativeInstanceFieldPos = LayoutInt.AlignUp(cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, type.Context.Target); + offsets[fieldOrdinal] = new FieldAndOffset(field, cumulativeInstanceFieldPos); + cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + fieldSizeAndAlignment.Size); + + fieldOrdinal++; + } + + if (type.IsValueType) + { + cumulativeInstanceFieldPos = LayoutInt.Max(cumulativeInstanceFieldPos, new LayoutInt(layoutMetadata.Size)); + } + + SizeAndAlignment instanceByteSizeAndAlignment; + var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, largestAlignmentRequirement, out instanceByteSizeAndAlignment); + + ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); + computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; + computedLayout.FieldSize = instanceSizeAndAlignment.Size; + computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; + computedLayout.ByteCountAlignment = instanceByteSizeAndAlignment.Alignment; + computedLayout.Offsets = offsets; + + return computedLayout; + } + + protected virtual void AlignBaseOffsetIfNecessary(MetadataType type, ref LayoutInt baseOffset) + { + } + + protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, int numInstanceFields) + { + // For types inheriting from another type, field offsets continue on from where they left off + LayoutInt cumulativeInstanceFieldPos = ComputeBytesUsedInParentType(type); + + AlignBaseOffsetIfNecessary(type, ref cumulativeInstanceFieldPos); + + var layoutMetadata = type.GetClassLayout(); + + int packingSize = ComputePackingSize(type, layoutMetadata); + + var offsets = new FieldAndOffset[numInstanceFields]; + int fieldOrdinal = 0; + + TypeSystemContext context = type.Context; + + // Iterate over the instance fields and keep track of the number of fields of each category + // For the non-GC Pointer fields, we will keep track of the number of fields by log2(size) + int maxLog2Size = CalculateLog2(TargetDetails.MaximumPrimitiveSize); + int log2PointerSize = CalculateLog2(context.Target.PointerSize); + int instanceValueClassFieldCount = 0; + int instanceGCPointerFieldsCount = 0; + int[] instanceNonGCPointerFieldsCount = new int[maxLog2Size + 1]; + + foreach (var field in type.GetFields()) + { + if (field.IsStatic) + continue; + + TypeDesc fieldType = field.FieldType; + if (IsByValueClass(fieldType)) + { + instanceValueClassFieldCount++; + } + else if (fieldType.IsGCPointer) + { + instanceGCPointerFieldsCount++; + } + else + { + Debug.Assert(fieldType.IsPrimitive || fieldType.IsPointer || fieldType.IsFunctionPointer || fieldType.IsEnum); + + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize); + instanceNonGCPointerFieldsCount[CalculateLog2(fieldSizeAndAlignment.Size.AsInt)]++; + } + } + + // Initialize three different sets of lists to hold the instance fields + // 1. Array of value class fields + // 2. Array of GC Pointer fields + // 3. Jagged array of remaining fields. To access the fields of size n, you must index the first array at index log2(n) + FieldDesc[] instanceValueClassFieldsArr = new FieldDesc[instanceValueClassFieldCount]; + FieldDesc[] instanceGCPointerFieldsArr = new FieldDesc[instanceGCPointerFieldsCount]; + FieldDesc[][] instanceNonGCPointerFieldsArr = new FieldDesc[maxLog2Size + 1][]; + + for (int i = 0; i <= maxLog2Size; i++) + { + instanceNonGCPointerFieldsArr[i] = new FieldDesc[instanceNonGCPointerFieldsCount[i]]; + + // Reset the counters to be used later as the index to insert into the arrays + instanceNonGCPointerFieldsCount[i] = 0; + } + + // Reset the counters to be used later as the index to insert into the array + instanceGCPointerFieldsCount = 0; + instanceValueClassFieldCount = 0; + + // Iterate over all fields and do the following + // - Add instance fields to the appropriate array (while maintaining the enumerated order) + // - Save the largest alignment we've seen + foreach (var field in type.GetFields()) + { + if (field.IsStatic) + continue; + + TypeDesc fieldType = field.FieldType; + + if (IsByValueClass(fieldType)) + { + instanceValueClassFieldsArr[instanceValueClassFieldCount++] = field; + } + else if (fieldType.IsGCPointer) + { + instanceGCPointerFieldsArr[instanceGCPointerFieldsCount++] = field; + } + else + { + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize); + int log2size = CalculateLog2(fieldSizeAndAlignment.Size.AsInt); + instanceNonGCPointerFieldsArr[log2size][instanceNonGCPointerFieldsCount[log2size]++] = field; + } + } + + // We've finished placing the fields into their appropriate arrays + // The next optimization may place non-GC Pointers, so repurpose our + // counter to keep track of the next non-GC Pointer that must be placed + // for a given field size + Array.Clear(instanceNonGCPointerFieldsCount, 0, instanceNonGCPointerFieldsCount.Length); + + // If the position is Indeterminate, proceed immediately to placing the fields + // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments + if (!cumulativeInstanceFieldPos.IsIndeterminate) + { + // First, place small fields immediately after the parent field bytes if there are a number of field bytes that are not aligned + // GC pointer fields and value class fields are not considered for this optimization + int parentByteOffsetModulo = cumulativeInstanceFieldPos.AsInt % context.Target.PointerSize; + if (parentByteOffsetModulo != 0) + { + for (int i = 0; i < maxLog2Size; i++) + { + int j; + + // Check if the position is aligned such that we could place a larger type + int offsetModulo = cumulativeInstanceFieldPos.AsInt % (1 << (i+1)); + if (offsetModulo == 0) + { + continue; + } + + // Check whether there are any bigger fields + // We must consider both GC Pointers and non-GC Pointers + for (j = i + 1; j <= maxLog2Size; j++) + { + // Check if there are any elements left to place of the given size + if (instanceNonGCPointerFieldsCount[j] < instanceNonGCPointerFieldsArr[j].Length + || (j == log2PointerSize && instanceGCPointerFieldsArr.Length > 0)) + break; + } + + // Nothing to gain if there are no bigger fields + // (the subsequent loop will place fields from large to small fields) + if (j > maxLog2Size) + break; + + // Check whether there are any small enough fields + // We must consider both GC Pointers and non-GC Pointers + for (j = i; j >= 0; j--) + { + if (instanceNonGCPointerFieldsCount[j] < instanceNonGCPointerFieldsArr[j].Length + || (j == log2PointerSize && instanceGCPointerFieldsArr.Length > 0)) + break; + } + + // Nothing to do if there are no smaller fields + if (j < 0) + break; + + // Go back and use the smaller field as filling + i = j; + + // Assert that we have at least one field of this size + Debug.Assert(instanceNonGCPointerFieldsCount[i] < instanceNonGCPointerFieldsArr[i].Length + || (i == log2PointerSize && instanceGCPointerFieldsArr.Length > 0)); + + // Avoid reordering of gc fields + // Exit if there are no more non-GC fields of this size (pointer size) to place + if (i == log2PointerSize) + { + if (instanceNonGCPointerFieldsCount[i] >= instanceNonGCPointerFieldsArr[i].Length) + break; + } + + // Place the field + j = instanceNonGCPointerFieldsCount[i]; + FieldDesc field = instanceNonGCPointerFieldsArr[i][j]; + PlaceInstanceField(field, packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal); + + instanceNonGCPointerFieldsCount[i]++; + } + } + } + + // Next, place GC pointer fields and non-GC pointer fields + // Starting with the largest-sized fields, place the GC pointer fields in order then place the non-GC pointer fields in order. + // Once the largest-sized fields are placed, repeat with the next-largest-sized group of fields and continue. + for (int i = maxLog2Size; i >= 0; i--) + { + // First, if we're placing the size that also corresponds to the pointer size, place GC pointer fields in order + if (i == log2PointerSize) + { + for (int j = 0; j < instanceGCPointerFieldsArr.Length; j++) + { + PlaceInstanceField(instanceGCPointerFieldsArr[j], packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal); + } + } + + // The start index will be the index that may have been increased in the previous optimization + for (int j = instanceNonGCPointerFieldsCount[i]; j < instanceNonGCPointerFieldsArr[i].Length; j++) + { + PlaceInstanceField(instanceNonGCPointerFieldsArr[i][j], packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal); + } + } + + // Place value class fields last + for (int i = 0; i < instanceValueClassFieldsArr.Length; i++) + { + // If the field has an indeterminate alignment, align the cumulative field offset to the indeterminate value + // Otherwise, align the cumulative field offset to the PointerSize + // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(instanceValueClassFieldsArr[i].FieldType, packingSize); + + if (fieldSizeAndAlignment.Alignment.IsIndeterminate) + { + cumulativeInstanceFieldPos = LayoutInt.AlignUp(cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, context.Target); + } + else + { + cumulativeInstanceFieldPos = LayoutInt.AlignUp(cumulativeInstanceFieldPos, context.Target.LayoutPointerSize, context.Target); + } + offsets[fieldOrdinal] = new FieldAndOffset(instanceValueClassFieldsArr[i], cumulativeInstanceFieldPos); + + // If the field has an indeterminate size, align the cumulative field offset to the indeterminate value + // Otherwise, align the cumulative field offset to the aligned-instance field size + // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments + LayoutInt alignedInstanceFieldBytes = fieldSizeAndAlignment.Size.IsIndeterminate ? fieldSizeAndAlignment.Size : GetAlignedNumInstanceFieldBytes(fieldSizeAndAlignment.Size); + cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + alignedInstanceFieldBytes); + + fieldOrdinal++; + } + + if (type.IsValueType) + { + cumulativeInstanceFieldPos = LayoutInt.Max(cumulativeInstanceFieldPos, new LayoutInt(layoutMetadata.Size)); + } + + // The JITs like to copy full machine words, + // so if the size is bigger than a void* round it up to minAlign + // and if the size is smaller than void* round it up to next power of two + LayoutInt minAlign; + if (cumulativeInstanceFieldPos.IsIndeterminate) + { + minAlign = LayoutInt.Indeterminate; + } + else if (cumulativeInstanceFieldPos.AsInt > type.Context.Target.PointerSize) + { + minAlign = type.Context.Target.LayoutPointerSize; + } + else + { + minAlign = new LayoutInt(1); + while (minAlign.AsInt < cumulativeInstanceFieldPos.AsInt) + minAlign = new LayoutInt(minAlign.AsInt * 2); + } + + SizeAndAlignment instanceByteSizeAndAlignment; + var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, minAlign, out instanceByteSizeAndAlignment); + + ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); + computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; + computedLayout.FieldSize = instanceSizeAndAlignment.Size; + computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; + computedLayout.ByteCountAlignment = instanceByteSizeAndAlignment.Alignment; + computedLayout.Offsets = offsets; + + return computedLayout; + } + + private static void PlaceInstanceField(FieldDesc field, int packingSize, FieldAndOffset[] offsets, ref LayoutInt instanceFieldPos, ref int fieldOrdinal) + { + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize); + + instanceFieldPos = LayoutInt.AlignUp(instanceFieldPos, fieldSizeAndAlignment.Alignment, field.Context.Target); + offsets[fieldOrdinal] = new FieldAndOffset(field, instanceFieldPos); + instanceFieldPos = checked(instanceFieldPos + fieldSizeAndAlignment.Size); + + fieldOrdinal++; + } + + // The aligned instance field bytes calculation here matches the calculation of CoreCLR MethodTable::GetAlignedNumInstanceFieldBytes + // This will calculate the next multiple of 4 that is greater than or equal to the instance size + private static LayoutInt GetAlignedNumInstanceFieldBytes(LayoutInt instanceSize) + { + uint inputSize = (uint) instanceSize.AsInt; + uint result = (uint)(((inputSize + 3) & (~3))); + return new LayoutInt((int) result); + } + + private static int CalculateLog2(int size) + { + // Size must be a positive number + Debug.Assert(size > 0); + + // Size must be a power of 2 + Debug.Assert( 0 == (size & (size - 1))); + + int log2size; + for (log2size = 0; size > 1; log2size++) + { + size = size >> 1; + } + + return log2size; + } + + private static bool IsByValueClass(TypeDesc type) + { + return type.IsValueType && !type.IsPrimitive && !type.IsEnum; + } + + private static LayoutInt ComputeBytesUsedInParentType(DefType type) + { + LayoutInt cumulativeInstanceFieldPos = LayoutInt.Zero; + + if (!type.IsValueType && type.HasBaseType) + { + cumulativeInstanceFieldPos = type.BaseType.InstanceByteCountUnaligned; + } + + return cumulativeInstanceFieldPos; + } + + private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, int packingSize) + { + SizeAndAlignment result; + + if (fieldType.IsDefType) + { + if (fieldType.IsValueType) + { + DefType metadataType = (DefType)fieldType; + result.Size = metadataType.InstanceFieldSize; + result.Alignment = metadataType.InstanceFieldAlignment; + } + else + { + result.Size = fieldType.Context.Target.LayoutPointerSize; + result.Alignment = fieldType.Context.Target.LayoutPointerSize; + } + } + else if (fieldType.IsArray) + { + // This could use InstanceFieldSize/Alignment (and those results should match what's here) + // but, its more efficient to just assume pointer size instead of fulling processing + // the instance field layout of fieldType here. + result.Size = fieldType.Context.Target.LayoutPointerSize; + result.Alignment = fieldType.Context.Target.LayoutPointerSize; + } + else + { + Debug.Assert(fieldType.IsPointer || fieldType.IsFunctionPointer); + result.Size = fieldType.Context.Target.LayoutPointerSize; + result.Alignment = fieldType.Context.Target.LayoutPointerSize; + } + + result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize)); + + return result; + } + + private static int ComputePackingSize(MetadataType type, ClassLayoutMetadata layoutMetadata) + { + // If a type contains pointers then the metadata specified packing size is ignored (On desktop this is disqualification from ManagedSequential) + if (layoutMetadata.PackingSize == 0 || type.ContainsGCPointers) + return type.Context.Target.DefaultPackingSize; + else + return layoutMetadata.PackingSize; + } + + private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, out SizeAndAlignment byteCount) + { + SizeAndAlignment result; + + TargetDetails target = type.Context.Target; + + // Pad the length of structs to be 1 if they are empty so we have no zero-length structures + if (type.IsValueType && instanceSize == LayoutInt.Zero) + { + instanceSize = LayoutInt.One; + } + + if (type.IsValueType) + { + instanceSize = LayoutInt.AlignUp(instanceSize, alignment, target); + result.Size = instanceSize; + result.Alignment = alignment; + } + else + { + result.Size = target.LayoutPointerSize; + result.Alignment = target.LayoutPointerSize; + if (type.HasBaseType) + alignment = LayoutInt.Max(alignment, type.BaseType.InstanceByteAlignment); + } + + // Determine the alignment needed by the type when allocated + // This is target specific, and not just pointer sized due to + // 8 byte alignment requirements on ARM for longs and doubles + alignment = target.GetObjectAlignment(alignment); + + byteCount.Size = instanceSize; + byteCount.Alignment = alignment; + + return result; + } + + public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) + { + if (!type.IsValueType) + return ValueTypeShapeCharacteristics.None; + + ValueTypeShapeCharacteristics result = ComputeHomogeneousFloatAggregateCharacteristic(type); + + // TODO: System V AMD64 characteristics (https://github.com/dotnet/corert/issues/158) + + return result; + } + + private ValueTypeShapeCharacteristics ComputeHomogeneousFloatAggregateCharacteristic(DefType type) + { + Debug.Assert(type.IsValueType); + + MetadataType metadataType = (MetadataType)type; + + // No HFAs with explicit layout. There may be cases where explicit layout may be still + // eligible for HFA, but it is hard to tell the real intent. Make it simple and just + // unconditionally disable HFAs for explicit layout. + if (metadataType.IsExplicitLayout) + return ValueTypeShapeCharacteristics.None; + + switch (metadataType.Category) + { + case TypeFlags.Single: + case TypeFlags.Double: + // These are the primitive types that constitute a HFA type. + return ValueTypeShapeCharacteristics.HomogenousFloatAggregate; + + case TypeFlags.ValueType: + DefType expectedElementType = null; + + foreach (FieldDesc field in metadataType.GetFields()) + { + if (field.IsStatic) + continue; + + // If a field isn't a DefType, then this type cannot be an HFA type + // If a field isn't a HFA type, then this type cannot be an HFA type + DefType fieldType = field.FieldType as DefType; + if (fieldType == null || !fieldType.IsHfa) + return ValueTypeShapeCharacteristics.None; + + if (expectedElementType == null) + { + // If we hadn't yet figured out what form of HFA this type might be, we've + // now found one case. + expectedElementType = fieldType.HfaElementType; + Debug.Assert(expectedElementType != null); + } + else if (expectedElementType != fieldType.HfaElementType) + { + // If we had already determined the possible HFA type of the current type, but + // the field we've encountered is not of that type, then the current type cannot + // be an HFA type. + return ValueTypeShapeCharacteristics.None; + } + } + + // No fields means this is not HFA. + if (expectedElementType == null) + return ValueTypeShapeCharacteristics.None; + + // Types which are indeterminate in field size are not considered to be HFA + if (expectedElementType.InstanceFieldSize.IsIndeterminate) + return ValueTypeShapeCharacteristics.None; + + // Types which are indeterminate in field size are not considered to be HFA + if (type.InstanceFieldSize.IsIndeterminate) + return ValueTypeShapeCharacteristics.None; + + // Note that we check the total size, but do not perform any checks on number of fields: + // - Type of fields can be HFA valuetype itself + // - Managed C++ HFA valuetypes have just one of type float to signal that + // the valuetype is HFA and explicitly specified size + int maxSize = expectedElementType.InstanceFieldSize.AsInt * expectedElementType.Context.Target.MaximumHfaElementCount; + if (type.InstanceFieldSize.AsInt > maxSize) + return ValueTypeShapeCharacteristics.None; + + // All the tests passed. This is an HFA type. + return ValueTypeShapeCharacteristics.HomogenousFloatAggregate; + } + + return ValueTypeShapeCharacteristics.None; + } + + public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) + { + if (!type.IsHfa) + return null; + + if (type.IsWellKnownType(WellKnownType.Double) || type.IsWellKnownType(WellKnownType.Single)) + return type; + + for (; ; ) + { + Debug.Assert(type.IsValueType); + + // All HFA fields have to be of the same HFA type, so we can just return the type of the first field + TypeDesc firstFieldType = null; + foreach (var field in type.GetFields()) + { + if (field.IsStatic) + continue; + + firstFieldType = field.FieldType; + break; + } + Debug.Assert(firstFieldType != null, "Why is IsHfa true on this type?"); + + switch (firstFieldType.Category) + { + case TypeFlags.Single: + case TypeFlags.Double: + return (DefType)firstFieldType; + + case TypeFlags.ValueType: + // Drill into the struct and find the type of its first field + type = (DefType)firstFieldType; + break; + + default: + Debug.Fail("Why is IsHfa true on this type?"); + return null; + } + } + } + + private struct SizeAndAlignment + { + public LayoutInt Size; + public LayoutInt Alignment; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataRuntimeInterfacesAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataRuntimeInterfacesAlgorithm.cs new file mode 100644 index 00000000000..4b71985bfbe --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataRuntimeInterfacesAlgorithm.cs @@ -0,0 +1,98 @@ +// 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.Collections.Generic; +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Metadata based RuntimeInterfaces algorithm which can be used to compute the + /// RuntimeInterfaces for any MetadataType based on the base types RuntimeInterfaces + /// and the MetadataTypes explicit interfaces. + /// + public sealed class MetadataRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm + { + public override DefType[] ComputeRuntimeInterfaces(TypeDesc _type) + { + MetadataType type = (MetadataType)_type; + + // TODO: need to implement deduplication + // https://github.com/dotnet/corert/issues/208 + + if (type.IsInterface) + { + // For interfaces, the set of interfaces implemented directly matches the + // explicitly implemented interface list + return type.ExplicitlyImplementedInterfaces; + } + else if (type is InstantiatedType) + { + return ComputeRuntimeInterfacesForInstantiatedType((InstantiatedType)type); + } + else + { + return ComputeRuntimeInterfacesForNonInstantiatedMetadataType(type); + } + } + + /// + /// Instantiated type computation for runtime interfaces. Instantiated types + /// must have the same count of interfaces across all possible instantiations + /// so the algorithm works by computing the uninstantiated form, and then + /// specializing each interface as needed. + /// + private DefType[] ComputeRuntimeInterfacesForInstantiatedType(InstantiatedType instantiatedType) + { + MetadataType uninstantiatedType = (MetadataType)instantiatedType.GetTypeDefinition(); + + DefType[] genericTypeDefinitionInterfaces = uninstantiatedType.RuntimeInterfaces; + + return InstantiatedType.InstantiateTypeArray(uninstantiatedType.RuntimeInterfaces, instantiatedType.Instantiation, new Instantiation()); + } + + /// + /// Metadata based computation of interfaces. + /// + private DefType[] ComputeRuntimeInterfacesForNonInstantiatedMetadataType(MetadataType type) + { + DefType[] explicitInterfaces = type.ExplicitlyImplementedInterfaces; + DefType[] baseTypeInterfaces = (type.BaseType != null) ? (type.BaseType.RuntimeInterfaces) : Array.Empty(); + + // Optimized case for no interfaces newly defined. + if (explicitInterfaces.Length == 0) + return baseTypeInterfaces; + + ArrayBuilder interfacesArray = new ArrayBuilder(); + interfacesArray.Append(baseTypeInterfaces); + + foreach (DefType iface in explicitInterfaces) + { + BuildPostOrderInterfaceList(iface, ref interfacesArray); + } + + return interfacesArray.ToArray(); + } + + /// + /// Add an interface and its required interfaces to the interfacesArray + /// + private void BuildPostOrderInterfaceList(DefType iface, ref ArrayBuilder interfacesArray) + { + if (interfacesArray.Contains(iface)) + return; + + foreach (DefType implementedInterface in iface.RuntimeInterfaces) + { + BuildPostOrderInterfaceList(implementedInterface, ref interfacesArray); + } + + if (interfacesArray.Contains(iface)) + return; + + interfacesArray.Add(iface); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.Interfaces.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.Interfaces.cs new file mode 100644 index 00000000000..e6fd004d932 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.Interfaces.cs @@ -0,0 +1,23 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Api surface definition for interfaces that all MetadataTypes must implement + + public abstract partial class MetadataType : DefType + { + /// + /// The interfaces explicitly declared as implemented by this MetadataType in the type's metadata. + /// These correspond to the InterfaceImpls of a type in metadata + /// + public abstract DefType[] ExplicitlyImplementedInterfaces + { + get; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.MethodImpls.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.MethodImpls.cs new file mode 100644 index 00000000000..b41133e36fa --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.MethodImpls.cs @@ -0,0 +1,55 @@ +// 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; + +namespace Internal.TypeSystem +{ + public struct MethodImplRecord + { + public readonly MethodDesc Decl; + public readonly MethodDesc Body; + + public MethodImplRecord(MethodDesc decl, MethodDesc body) + { + Decl = decl; + Body = body; + } + } + + // MethodImpl api surface for types. + public partial class MetadataType + { + /// + /// Compute an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type. + /// May be expensive. + /// + protected abstract MethodImplRecord[] ComputeVirtualMethodImplsForType(); + + private MethodImplRecord[] _allVirtualMethodImplsForType; + /// + /// Get an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type. + /// Expected to cache results so this api can be used repeatedly. + /// + public MethodImplRecord[] VirtualMethodImplsForType + { + get + { + if (_allVirtualMethodImplsForType == null) + { + _allVirtualMethodImplsForType = ComputeVirtualMethodImplsForType(); + } + + return _allVirtualMethodImplsForType; + } + } + + /// + /// Get an array of MethodImpls where the Decl method matches by name with the specified name. + /// + /// + /// + public abstract MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.cs new file mode 100644 index 00000000000..9fe484c9a01 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataType.cs @@ -0,0 +1,114 @@ +// 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.Collections.Generic; + +namespace Internal.TypeSystem +{ + /// + /// Type with metadata available that is equivalent to a TypeDef record in an ECMA 335 metadata stream. + /// A class, an interface, or a value type. + /// + public abstract partial class MetadataType : DefType + { + public abstract override string Name { get; } + + public abstract override string Namespace { get; } + + /// + /// Gets metadata that controls instance layout of this type. + /// + public abstract ClassLayoutMetadata GetClassLayout(); + + /// + /// If true, the type layout is dictated by the explicit layout rules provided. + /// Corresponds to the definition of explicitlayout semantic defined in the ECMA-335 specification. + /// + public abstract bool IsExplicitLayout { get; } + + /// + /// If true, the order of the fields needs to be preserved. Corresponds to the definition + /// of sequentiallayout semantic defined in the ECMA-335 specification. + /// + public abstract bool IsSequentialLayout { get; } + + /// + /// If true, the type initializer of this type has a relaxed semantic. Corresponds + /// to the definition of beforefieldinit semantic defined in the ECMA-335 specification. + /// + public abstract bool IsBeforeFieldInit { get; } + + /// + /// If true, this is the special <Module> type that contains the definitions + /// of global fields and methods in the module. + /// + public virtual bool IsModuleType + { + get + { + return Module.GetGlobalModuleType() == this; + } + } + + /// + /// Gets the module that defines this type. + /// + public abstract ModuleDesc Module { get; } + + /// + /// Same as , but the result is a MetadataType (avoids casting). + /// + public abstract MetadataType MetadataBaseType { get; } + + /// + /// If true, the type cannot be used as a base type of any other type. + /// + public abstract bool IsSealed { get; } + + /// + /// Gets a value indicating whether the type is abstract and cannot be allocated. + /// + public abstract bool IsAbstract { get; } + + /// + /// Returns true if the type has given custom attribute. + /// + public abstract bool HasCustomAttribute(string attributeNamespace, string attributeName); + + public abstract override DefType ContainingType { get; } + + /// + /// Get all of the types nested in this type. + /// + public abstract IEnumerable GetNestedTypes(); + + /// + /// Get a specific type nested in this type. Returns null if the type + /// doesn't exist. + /// + public abstract MetadataType GetNestedType(string name); + } + + public struct ClassLayoutMetadata + { + public int PackingSize; + public int Size; + public FieldAndOffset[] Offsets; + } + + public struct FieldAndOffset + { + public static readonly LayoutInt InvalidOffset = new LayoutInt(int.MaxValue); + + public readonly FieldDesc Field; + + public readonly LayoutInt Offset; + + public FieldAndOffset(FieldDesc field, LayoutInt offset) + { + Field = field; + Offset = offset; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataTypeSystemContext.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataTypeSystemContext.cs new file mode 100644 index 00000000000..2d8a9378cc5 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataTypeSystemContext.cs @@ -0,0 +1,104 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public abstract partial class MetadataTypeSystemContext : TypeSystemContext + { + private static readonly string[] s_wellKnownTypeNames = new string[] { + "Void", + + "Boolean", + "Char", + "SByte", + "Byte", + "Int16", + "UInt16", + "Int32", + "UInt32", + "Int64", + "UInt64", + "IntPtr", + "UIntPtr", + "Single", + "Double", + + "ValueType", + "Enum", + "Nullable`1", + + "Object", + "String", + "Array", + "MulticastDelegate", + + "RuntimeTypeHandle", + "RuntimeMethodHandle", + "RuntimeFieldHandle", + + "Exception", + + "TypedReference", + "ByReference`1", + }; + + private MetadataType[] _wellKnownTypes; + + public MetadataTypeSystemContext() + { + } + + public MetadataTypeSystemContext(TargetDetails details) + : base(details) + { + } + + public virtual void SetSystemModule(ModuleDesc systemModule) + { + InitializeSystemModule(systemModule); + + // Sanity check the name table + Debug.Assert(s_wellKnownTypeNames[(int)WellKnownType.MulticastDelegate - 1] == "MulticastDelegate"); + + _wellKnownTypes = new MetadataType[s_wellKnownTypeNames.Length]; + + // Initialize all well known types - it will save us from checking the name for each loaded type + for (int typeIndex = 0; typeIndex < _wellKnownTypes.Length; typeIndex++) + { + // Require System.Object to be present as a minimal sanity check. + // The set of required well-known types is not strictly defined since different .NET profiles implement different subsets. + MetadataType type = systemModule.GetType("System", s_wellKnownTypeNames[typeIndex], typeIndex == (int)WellKnownType.Object); + if (type != null) + { + type.SetWellKnownType((WellKnownType)(typeIndex + 1)); + _wellKnownTypes[typeIndex] = type; + } + } + } + + public override DefType GetWellKnownType(WellKnownType wellKnownType, bool throwIfNotFound = true) + { + Debug.Assert(_wellKnownTypes != null, "Forgot to call SetSystemModule?"); + + int typeIndex = (int)wellKnownType - 1; + DefType type = _wellKnownTypes[typeIndex]; + if (type == null && throwIfNotFound) + ThrowHelper.ThrowTypeLoadException("System", s_wellKnownTypeNames[typeIndex], SystemModule); + + return type; + } + + protected sealed internal override bool ComputeHasStaticConstructor(TypeDesc type) + { + if (type is MetadataType) + { + return ((MetadataType)type).GetStaticConstructor() != null; + } + return false; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs new file mode 100644 index 00000000000..d27fbf6b480 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs @@ -0,0 +1,677 @@ +// 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.Collections.Generic; +using System.Diagnostics; + +namespace Internal.TypeSystem +{ + public class MetadataVirtualMethodAlgorithm : VirtualMethodAlgorithm + { + private class MethodDescHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(MethodDesc key) + { + return key.GetHashCode(); + } + + protected override int GetValueHashCode(MethodDesc value) + { + return value.GetHashCode(); + } + + protected override bool CompareKeyToValue(MethodDesc key, MethodDesc value) + { + Debug.Assert(key.Context == value.Context); + return Object.ReferenceEquals(key, value); + } + + protected override bool CompareValueToValue(MethodDesc value1, MethodDesc value2) + { + Debug.Assert(value1.Context == value2.Context); + return Object.ReferenceEquals(value1, value2); + } + + protected override MethodDesc CreateValueFromKey(MethodDesc key) + { + return key; + } + } + + private class UnificationGroup + { + private MethodDesc[] _members = MethodDesc.EmptyMethods; + private int _memberCount = 0; + + /// + /// Custom enumerator struct for Unification group. Makes enumeration require 0 allocations. + /// + public struct Enumerator + { + private MethodDesc[] _arrayToEnumerate; + private int _index; + private MethodDesc _current; + + internal Enumerator(MethodDesc[] arrayToEnumerate) + { + _arrayToEnumerate = arrayToEnumerate; + _index = 0; + _current = default(MethodDesc); + } + + public bool MoveNext() + { + for (; _index < _arrayToEnumerate.Length; _index++) + { + if (_arrayToEnumerate[_index] != null) + { + _current = _arrayToEnumerate[_index]; + _index++; + return true; + } + } + + _current = default(MethodDesc); + return false; + } + + public MethodDesc Current + { + get + { + return _current; + } + } + } + + public UnificationGroup(MethodDesc definingMethod) + { + DefiningMethod = definingMethod; + // TODO! Add assertion that DefiningMethod is a slot defining method + } + + public MethodDesc DefiningMethod; + + public Enumerator GetEnumerator() + { + return new Enumerator(_members); + } + + public void SetDefiningMethod(MethodDesc newDefiningMethod) + { + // Do not change the defining method if its the same as + // one of the members, or it isn't a change at all + if (!IsInGroup(newDefiningMethod) && + DefiningMethod != newDefiningMethod) + { + // When we set the defining method, ensure that the old defining method isn't removed from the group + MethodDesc oldDefiningMethod = DefiningMethod; + DefiningMethod = newDefiningMethod; + AddToGroup(oldDefiningMethod); + + // TODO! Add assertion that DefiningMethod is a slot defining method + } + } + + public void AddToGroup(MethodDesc method) + { + if (method == DefiningMethod) + return; + + if (!IsInGroup(method)) + { + _memberCount++; + if (_memberCount >= _members.Length) + { + Array.Resize(ref _members, Math.Max(_members.Length * 2, 2)); + } + for (int i = 0; i < _members.Length; i++) + { + if (_members[i] == null) + { + _members[i] = method; + break; + } + } + } + } + + public void RemoveFromGroup(MethodDesc method) + { + if (method == DefiningMethod) + throw new BadImageFormatException(); + + for (int i = 0; i < _members.Length; i++) + { + if (_members[i] == method) + { + _memberCount--; + _members[i] = null; + return; + } + } + } + + public bool IsInGroupOrIsDefiningSlot(MethodDesc method) + { + if (DefiningMethod == method) + return true; + + return IsInGroup(method); + } + + public bool IsInGroup(MethodDesc method) + { + for (int i = 0; i < _members.Length; i++) + { + if (_members[i] == method) + return true; + } + + return false; + } + } + + public override MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, TypeDesc objectType) + { + return FindVirtualFunctionTargetMethodOnObjectType(targetMethod, (MetadataType)objectType); + } + + /// + /// Resolve a virtual function call (to a virtual method, not an interface method) + /// + /// + /// + /// The override of the virtual method that should be called + private static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, MetadataType objectType) + { + // Step 1, convert objectType to uninstantiated form + MetadataType uninstantiatedType = objectType; + MethodDesc initialTargetMethod = targetMethod; + InstantiatedType initialInstantiatedType = objectType as InstantiatedType; + if (initialInstantiatedType != null) + { + uninstantiatedType = (MetadataType)initialInstantiatedType.GetTypeDefinition(); + } + + // Step 2, convert targetMethod to method in type hierarchy of uninstantiated form + targetMethod = targetMethod.GetMethodDefinition(); + if (uninstantiatedType != objectType) + { + targetMethod = uninstantiatedType.FindMethodOnTypeWithMatchingTypicalMethod(targetMethod); + } + + // Step 3, find unification group of target method + UnificationGroup group = new UnificationGroup(FindSlotDefiningMethodForVirtualMethod(targetMethod)); + FindBaseUnificationGroup(uninstantiatedType, group); + + // Step 4, name/sig match virtual function resolve + MethodDesc resolutionTarget = FindNameSigOverrideForVirtualMethod(group.DefiningMethod, uninstantiatedType); + if (resolutionTarget == null) + return null; + + // Step 5, convert resolution target from uninstantiated form target to objecttype target, + // and instantiate as appropriate + if (uninstantiatedType != objectType) + { + resolutionTarget = objectType.FindMethodOnTypeWithMatchingTypicalMethod(resolutionTarget); + } + if (initialTargetMethod.HasInstantiation) + { + resolutionTarget = resolutionTarget.MakeInstantiatedMethod(initialTargetMethod.Instantiation); + } + + return resolutionTarget; + } + + private static bool IsInterfaceImplementedOnType(MetadataType type, MetadataType interfaceType) + { + foreach (TypeDesc iface in type.RuntimeInterfaces) + { + if (iface == interfaceType) + return true; + } + return false; + } + + private static MethodDesc FindImplFromDeclFromMethodImpls(MetadataType type, MethodDesc decl) + { + MethodImplRecord[] foundMethodImpls = type.FindMethodsImplWithMatchingDeclName(decl.Name); + + if (foundMethodImpls == null) + return null; + + bool interfaceDecl = decl.OwningType.IsInterface; + + foreach (MethodImplRecord record in foundMethodImpls) + { + MethodDesc recordDecl = record.Decl; + + if (interfaceDecl != recordDecl.OwningType.IsInterface) + continue; + + if (!interfaceDecl) + recordDecl = FindSlotDefiningMethodForVirtualMethod(recordDecl); + + if (recordDecl == decl) + { + return FindSlotDefiningMethodForVirtualMethod(record.Body); + } + } + + return null; + } + + private static bool IsInterfaceExplicitlyImplementedOnType(MetadataType type, MetadataType interfaceType) + { + foreach (TypeDesc iface in type.ExplicitlyImplementedInterfaces) + { + if (iface == interfaceType) + return true; + } + return false; + } + + /// + /// Find matching a matching method by name and sig on a type. (Restricted to virtual methods only) + /// + /// + /// + /// Used to control the order of the search. For historical purposes to + /// match .NET Framework behavior, this is typically true, but not always. There is no particular rationale + /// for the particular orders other than to attempt to be consistent in virtual method override behavior + /// betweeen runtimes. + /// + /// + private static MethodDesc FindMatchingVirtualMethodOnTypeByNameAndSig(MethodDesc targetMethod, DefType currentType, bool reverseMethodSearch, Func nameSigMatchMethodIsValidCandidate) + { + string name = targetMethod.Name; + MethodSignature sig = targetMethod.Signature; + + MethodDesc implMethod = null; + foreach (MethodDesc candidate in currentType.GetAllMethods()) + { + if (!candidate.IsVirtual) + continue; + + if (candidate.Name == name) + { + if (candidate.Signature.Equals(sig)) + { + if (nameSigMatchMethodIsValidCandidate == null || nameSigMatchMethodIsValidCandidate(targetMethod, candidate)) + { + implMethod = candidate; + + // If reverseMethodSearch is enabled, we want to find the last match on this type, not the first + // (reverseMethodSearch is used for most matches except for searches for name/sig method matches for interface methods on the most derived type) + if (!reverseMethodSearch) + return implMethod; + } + } + } + } + + return implMethod; + } + + // This function is used to find the name/sig based override for a given method. This method ignores all + // method impl's as it assumes they have been resolved. The algorithm is simple. Walk to the base type looking + // for overrides by name and signature. If one is found, return it as long as the newslot defining method + // for the found method matches that of the target method. + private static MethodDesc FindNameSigOverrideForVirtualMethod(MethodDesc targetMethod, MetadataType currentType) + { + while (currentType != null) + { + MethodDesc nameSigOverride = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(targetMethod, currentType, reverseMethodSearch:true); + + if (nameSigOverride != null) + { + return nameSigOverride; + } + + currentType = currentType.MetadataBaseType; + } + + return null; + } + + // This function looks for the base type method that defines the slot for a method + // This is either the newslot method most derived that is in the parent hierarchy of method + // or the least derived method that isn't newslot that matches by name and sig. + public static MethodDesc FindSlotDefiningMethodForVirtualMethod(MethodDesc method) + { + if (method == null) + return method; + + DefType currentType = method.OwningType.BaseType; + + // Loop until a newslot method is found + while ((currentType != null) && !method.IsNewSlot) + { + MethodDesc foundMethod = FindMatchingVirtualMethodOnTypeByNameAndSig(method, currentType, reverseMethodSearch: true, nameSigMatchMethodIsValidCandidate:null); + if (foundMethod != null) + { + method = foundMethod; + } + + currentType = currentType.BaseType; + } + + // Newslot method found, or if not the least derived method that matches by name and + // sig is to be returned. + return method; + } + + /// + /// Find matching a matching method by name and sig on a type. (Restricted to virtual methods only) Only search amongst methods with the same vtable slot. + /// + /// + /// + /// Used to control the order of the search. For historical purposes to + /// match .NET Framework behavior, this is typically true, but not always. There is no particular rationale + /// for the particular orders other than to attempt to be consistent in virtual method override behavior + /// betweeen runtimes. + /// + private static MethodDesc FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(MethodDesc method, DefType currentType, bool reverseMethodSearch) + { + return FindMatchingVirtualMethodOnTypeByNameAndSig(method, currentType, reverseMethodSearch, nameSigMatchMethodIsValidCandidate: s_VerifyMethodsHaveTheSameVirtualSlot); + } + + private static Func s_VerifyMethodsHaveTheSameVirtualSlot = VerifyMethodsHaveTheSameVirtualSlot; + + // Return true if the slot that defines methodToVerify matches slotDefiningMethod + private static bool VerifyMethodsHaveTheSameVirtualSlot(MethodDesc slotDefiningMethod, MethodDesc methodToVerify) + { + MethodDesc slotDefiningMethodOfMethodToVerify = FindSlotDefiningMethodForVirtualMethod(methodToVerify); + return slotDefiningMethodOfMethodToVerify == slotDefiningMethod; + } + + private static void FindBaseUnificationGroup(MetadataType currentType, UnificationGroup unificationGroup) + { + MethodDesc originalDefiningMethod = unificationGroup.DefiningMethod; + + MethodDesc methodImpl = FindImplFromDeclFromMethodImpls(currentType, unificationGroup.DefiningMethod); + if (methodImpl != null) + { + unificationGroup.SetDefiningMethod(methodImpl); + } + + MethodDesc nameSigMatchMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(unificationGroup.DefiningMethod, currentType, reverseMethodSearch: true); + MetadataType baseType = currentType.MetadataBaseType; + + // Unless the current type has a name/sig match for the group, look to the base type to define the unification group further + if ((nameSigMatchMethod == null) && (baseType != null)) + { + FindBaseUnificationGroup(baseType, unificationGroup); + } + + Debug.Assert(unificationGroup.IsInGroupOrIsDefiningSlot(originalDefiningMethod)); + + // Now, we have the unification group from the type, or have discovered its defined on the current type. + // Adjust the group to contain all of the elements that are added to it on this type, remove the components that + // have seperated themselves from the group + + // Start with removing methods that seperated themselves from the group via name/sig matches + MethodDescHashtable separatedMethods = null; + + foreach (MethodDesc memberMethod in unificationGroup) + { + MethodDesc nameSigMatchMemberMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(memberMethod, currentType, reverseMethodSearch: true); + if (nameSigMatchMemberMethod != null) + { + if (separatedMethods == null) + separatedMethods = new MethodDescHashtable(); + separatedMethods.AddOrGetExisting(memberMethod); + } + } + + if (separatedMethods != null) + { + foreach (MethodDesc seperatedMethod in MethodDescHashtable.Enumerator.Get(separatedMethods)) + { + unificationGroup.RemoveFromGroup(seperatedMethod); + } + } + + // Next find members which have seperated or added themselves to the group via MethodImpls + foreach (MethodImplRecord methodImplRecord in currentType.VirtualMethodImplsForType) + { + MethodDesc declSlot = FindSlotDefiningMethodForVirtualMethod(methodImplRecord.Decl); + MethodDesc implSlot = FindSlotDefiningMethodForVirtualMethod(methodImplRecord.Body); + + if (unificationGroup.IsInGroup(declSlot) && !unificationGroup.IsInGroupOrIsDefiningSlot(implSlot)) + { + unificationGroup.RemoveFromGroup(declSlot); + + if (separatedMethods == null) + separatedMethods = new MethodDescHashtable(); + separatedMethods.AddOrGetExisting(declSlot); + continue; + } + if (!unificationGroup.IsInGroupOrIsDefiningSlot(declSlot) && unificationGroup.IsInGroupOrIsDefiningSlot(implSlot)) + { + // Add decl to group. + + // To do so, we need to have the Unification Group of the decl slot, as it may have multiple members itself + UnificationGroup addDeclGroup = new UnificationGroup(declSlot); + FindBaseUnificationGroup(baseType, addDeclGroup); + Debug.Assert(addDeclGroup.IsInGroupOrIsDefiningSlot(declSlot)); + + // Add all members from the decl's unification group except for ones that have been seperated by name/sig matches + // or previously processed methodimpls. NOTE: This implies that method impls are order dependent. + if (separatedMethods == null || !separatedMethods.Contains(addDeclGroup.DefiningMethod)) + { + unificationGroup.AddToGroup(addDeclGroup.DefiningMethod); + } + + foreach (MethodDesc addDeclGroupMemberMethod in addDeclGroup) + { + if (separatedMethods == null || !separatedMethods.Contains(addDeclGroupMemberMethod)) + { + unificationGroup.AddToGroup(addDeclGroupMemberMethod); + } + } + } + } + } + + public override MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType) + { + return ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, (MetadataType)currentType); + } + + public override MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType) + { + return ResolveVariantInterfaceMethodToVirtualMethodOnType(interfaceMethod, (MetadataType)currentType); + } + + //////////////////////// INTERFACE RESOLUTION + //Interface function resolution + // Interface function resolution follows the following rules + // 1. Apply any method impl that may exist, if once of these exists, resolve to target immediately. + // 2. If an interface is explicitly defined on a type, then attempt to perform a namesig match on the + // current type to resolve.If the interface isn’t resolved, if it isn’t implemented on a base type, + // scan all base types for name / sig matches. + // 3. If implicitly defined, attempt to perform a namesig match if the interface method implementation + // has not been found on some base type. + // The above will resolve an interface to a virtual method slot. From there perform virtual resolution + // to find out the actual target.Note, to preserve correct behavior in the presence of variance, this + // function returns null if the interface method implementation is not defined by the current type in + // the hierarchy.For variance to work correctly, this requires that interfaces be queried in correct order. + // See current interface call resolution for details on how that happens. + private static MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, MetadataType currentType) + { + if (currentType.IsInterface) + return null; + + MethodDesc methodImpl = FindImplFromDeclFromMethodImpls(currentType, interfaceMethod); + if (methodImpl != null) + return methodImpl; + + MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; + + // If interface is explicitly defined on a type, search for a name/sig match. + bool foundExplicitInterface = IsInterfaceExplicitlyImplementedOnType(currentType, interfaceType); + MetadataType baseType = currentType.MetadataBaseType; + + if (foundExplicitInterface) + { + MethodDesc foundOnCurrentType = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType + , reverseMethodSearch: false /* When searching for name/sig overrides on a type that explicitly defines an interface, search through the type in the forward direction*/ + , nameSigMatchMethodIsValidCandidate :null); + foundOnCurrentType = FindSlotDefiningMethodForVirtualMethod(foundOnCurrentType); + + if (baseType == null) + return foundOnCurrentType; + + if (foundOnCurrentType == null && (ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, baseType) == null)) + { + // TODO! Does this handle the case where the base type explicitly implements the interface, but is abstract + // and doesn't actually have an implementation? + if (!IsInterfaceImplementedOnType(baseType, interfaceType)) + { + return FindNameSigOverrideForInterfaceMethodRecursive(interfaceMethod, baseType); + } + } + return foundOnCurrentType; + } + else + { + // Implicit interface case + if (!IsInterfaceImplementedOnType(currentType, interfaceType)) + { + // If the interface isn't implemented on this type at all, don't go searching + return null; + } + + // This is an implicitly implemented interface method. Only return a vlaue if this is the first type in the class + // hierarchy that implements the interface. NOTE: If we pay attention to whether or not the parent type is + // abstract or not, we may be able to be more efficient here, but let's skip that for now + MethodDesc baseClassImplementationOfInterfaceMethod = ResolveInterfaceMethodToVirtualMethodOnTypeRecursive(interfaceMethod, baseType); + if (baseClassImplementationOfInterfaceMethod != null) + { + return null; + } + else + { + MethodDesc foundOnCurrentType = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType + , reverseMethodSearch: false /* When searching for name/sig overrides on a type that is the first type in the hierarchy to require the interface, search through the type in the forward direction*/ + , nameSigMatchMethodIsValidCandidate: null); + + foundOnCurrentType = FindSlotDefiningMethodForVirtualMethod(foundOnCurrentType); + + if (foundOnCurrentType != null) + return foundOnCurrentType; + + return FindNameSigOverrideForInterfaceMethodRecursive(interfaceMethod, baseType); + } + } + } + + public static MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, MetadataType currentType) + { + MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; + bool foundInterface = IsInterfaceImplementedOnType(currentType, interfaceType); + MethodDesc implMethod; + + if (foundInterface) + { + implMethod = ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, currentType); + if (implMethod != null) + return implMethod; + } + + foreach (TypeDesc iface in currentType.RuntimeInterfaces) + { + if (iface.CanCastTo(interfaceType)) + { + implMethod = iface.FindMethodOnTypeWithMatchingTypicalMethod(interfaceMethod); + Debug.Assert(implMethod != null); + implMethod = ResolveInterfaceMethodToVirtualMethodOnType(implMethod, currentType); + if (implMethod != null) + return implMethod; + } + } + + return null; + } + + // Helper routine used during implicit interface implementation discovery + private static MethodDesc ResolveInterfaceMethodToVirtualMethodOnTypeRecursive(MethodDesc interfaceMethod, MetadataType currentType) + { + while (true) + { + if (currentType == null) + return null; + + MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; + + if (!IsInterfaceImplementedOnType(currentType, interfaceType)) + { + // If the interface isn't implemented on this type at all, don't go searching + return null; + } + + MethodDesc currentTypeInterfaceResolution = ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, currentType); + if (currentTypeInterfaceResolution != null) + return currentTypeInterfaceResolution; + + currentType = currentType.MetadataBaseType; + } + } + + // Perform a name/sig match for a virtual method across the specified types and all of the types parents. + private static MethodDesc FindNameSigOverrideForInterfaceMethodRecursive(MethodDesc interfaceMethod, MetadataType currentType) + { + while (true) + { + if (currentType == null) + return null; + + MethodDesc nameSigOverride = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType + , reverseMethodSearch: true /* When searching for a name sig match for an interface on parent types search in reverse order of declaration */ + , nameSigMatchMethodIsValidCandidate:null); + + if (nameSigOverride != null) + { + return FindSlotDefiningMethodForVirtualMethod(nameSigOverride); + } + + currentType = currentType.MetadataBaseType; + } + } + + public override IEnumerable ComputeAllVirtualSlots(TypeDesc type) + { + return EnumAllVirtualSlots((MetadataType)type); + } + + // Enumerate all possible virtual slots of a type + public static IEnumerable EnumAllVirtualSlots(MetadataType type) + { + MethodDescHashtable alreadyEnumerated = new MethodDescHashtable(); + if (!type.IsInterface) + { + do + { + foreach (MethodDesc m in type.GetAllMethods()) + { + if (!m.IsVirtual) + continue; + + MethodDesc possibleVirtual = FindSlotDefiningMethodForVirtualMethod(m); + if (!alreadyEnumerated.Contains(possibleVirtual)) + { + alreadyEnumerated.AddOrGetExisting(possibleVirtual); + yield return possibleVirtual; + } + } + + type = type.MetadataBaseType; + } while (type != null); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDelegator.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDelegator.Diagnostic.cs new file mode 100644 index 00000000000..946f4a0d79b --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDelegator.Diagnostic.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 +{ + partial class MethodDelegator + { + public override string DiagnosticName => _wrappedMethod.DiagnosticName; + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDelegator.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDelegator.cs new file mode 100644 index 00000000000..b1fc85dfc90 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDelegator.cs @@ -0,0 +1,53 @@ +// 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 +{ + /// + /// Wraps a object and delegates methods to that . + /// + public abstract partial class MethodDelegator : MethodDesc + { + protected readonly MethodDesc _wrappedMethod; + + public MethodDelegator(MethodDesc wrappedMethod) + { + _wrappedMethod = wrappedMethod; + } + + public override TypeSystemContext Context => _wrappedMethod.Context; + + public override TypeDesc OwningType => _wrappedMethod.OwningType; + + public override MethodSignature Signature => _wrappedMethod.Signature; + + public override Instantiation Instantiation => _wrappedMethod.Instantiation; + + public override bool IsDefaultConstructor => _wrappedMethod.IsDefaultConstructor; + + public override string Name => _wrappedMethod.Name; + + public override bool IsVirtual => _wrappedMethod.IsVirtual; + + public override bool IsNewSlot => _wrappedMethod.IsNewSlot; + + public override bool IsAbstract => _wrappedMethod.IsAbstract; + + public override bool IsFinal => _wrappedMethod.IsFinal; + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return _wrappedMethod.HasCustomAttribute(attributeNamespace, attributeName); + } + + // For this method, delegating to the wrapped MethodDesc would likely be the wrong thing. + public abstract override MethodDesc GetMethodDefinition(); + + // For this method, delegating to the wrapped MethodDesc would likely be the wrong thing. + public abstract override MethodDesc GetTypicalMethodDefinition(); + + // For this method, delegating to the wrapped MethodDesc would likely be the wrong thing. + public abstract override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs new file mode 100644 index 00000000000..581125911c3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs @@ -0,0 +1,13 @@ +// 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.Text; + +namespace Internal.TypeSystem +{ + partial class MethodDesc + { + public abstract string DiagnosticName { get; } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.ToString.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.ToString.cs new file mode 100644 index 00000000000..984faa2433e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.ToString.cs @@ -0,0 +1,85 @@ +// 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.Text; + +namespace Internal.TypeSystem +{ + partial class MethodSignature + { + public override string ToString() + { + return ToString(includeReturnType: true); + } + + public string ToString(bool includeReturnType) + { + var sb = new StringBuilder(); + + if (includeReturnType) + { + DebugNameFormatter.Instance.AppendName(sb, ReturnType, DebugNameFormatter.FormatOptions.None); + sb.Append('('); + } + + bool first = true; + foreach (TypeDesc param in _parameters) + { + if (first) + first = false; + else + sb.Append(','); + DebugNameFormatter.Instance.AppendName(sb, param, DebugNameFormatter.FormatOptions.None); + } + + if (includeReturnType) + sb.Append(')'); + + return sb.ToString(); + } + } + + partial class MethodDesc + { + public override string ToString() + { + var sb = new StringBuilder(); + + // (Skipping return type to keep things short) + sb.Append(OwningType); + sb.Append('.'); + sb.Append(DiagnosticName); + + bool first = true; + for (int i = 0; i < Instantiation.Length; i++) + { + if (first) + { + sb.Append('<'); + first = false; + } + else + { + sb.Append(','); + } + DebugNameFormatter.Instance.AppendName(sb, Instantiation[i], DebugNameFormatter.FormatOptions.None); + } + if (!first) + sb.Append('>'); + + sb.Append('('); + try + { + sb.Append(Signature.ToString(includeReturnType: false)); + } + catch + { + sb.Append("Unknown"); + } + sb.Append(')'); + + return sb.ToString(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.cs new file mode 100644 index 00000000000..3e204f8fa75 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.cs @@ -0,0 +1,580 @@ +// 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 System.Runtime.CompilerServices; +using Internal.NativeFormat; + +namespace Internal.TypeSystem +{ + [Flags] + public enum MethodSignatureFlags + { + None = 0x0000, + // TODO: Generic, etc. + + UnmanagedCallingConventionMask = 0x000F, + UnmanagedCallingConventionCdecl = 0x0001, + UnmanagedCallingConventionStdCall = 0x0002, + UnmanagedCallingConventionThisCall = 0x0003, + CallingConventionVarargs = 0x0005, + + Static = 0x0010, + } + + public enum EmbeddedSignatureDataKind + { + RequiredCustomModifier = 0, + OptionalCustomModifier = 1 + } + + public struct EmbeddedSignatureData + { + public string index; + public EmbeddedSignatureDataKind kind; + public TypeDesc type; + } + + /// + /// Represents the parameter types, the return type, and flags of a method. + /// + public sealed partial class MethodSignature : TypeSystemEntity + { + internal MethodSignatureFlags _flags; + internal int _genericParameterCount; + internal TypeDesc _returnType; + internal TypeDesc[] _parameters; + internal EmbeddedSignatureData[] _embeddedSignatureData; + + public MethodSignature(MethodSignatureFlags flags, int genericParameterCount, TypeDesc returnType, TypeDesc[] parameters, EmbeddedSignatureData[] embeddedSignatureData = null) + { + _flags = flags; + _genericParameterCount = genericParameterCount; + _returnType = returnType; + _parameters = parameters; + _embeddedSignatureData = embeddedSignatureData; + + Debug.Assert(parameters != null, "Parameters must not be null"); + } + + public MethodSignatureFlags Flags + { + get + { + return _flags; + } + } + + public bool IsStatic + { + get + { + return (_flags & MethodSignatureFlags.Static) != 0; + } + } + + public int GenericParameterCount + { + get + { + return _genericParameterCount; + } + } + + public TypeDesc ReturnType + { + get + { + return _returnType; + } + } + + /// + /// Gets the parameter type at the specified index. + /// + [IndexerName("Parameter")] + public TypeDesc this[int index] + { + get + { + return _parameters[index]; + } + } + + /// + /// Gets the number of parameters of this method signature. + /// + public int Length + { + get + { + return _parameters.Length; + } + } + + public bool Equals(MethodSignature otherSignature) + { + // TODO: Generics, etc. + if (this._flags != otherSignature._flags) + return false; + + if (this._genericParameterCount != otherSignature._genericParameterCount) + return false; + + if (this._returnType != otherSignature._returnType) + return false; + + if (this._parameters.Length != otherSignature._parameters.Length) + return false; + + for (int i = 0; i < this._parameters.Length; i++) + { + if (this._parameters[i] != otherSignature._parameters[i]) + return false; + } + + if (this._embeddedSignatureData == null && otherSignature._embeddedSignatureData == null) + { + return true; + } + + if (this._embeddedSignatureData != null && otherSignature._embeddedSignatureData != null) + { + if (this._embeddedSignatureData.Length != otherSignature._embeddedSignatureData.Length) + { + return false; + } + + for (int i = 0; i < this._embeddedSignatureData.Length; i++) + { + if (this._embeddedSignatureData[i].index != otherSignature._embeddedSignatureData[i].index) + return false; + if (this._embeddedSignatureData[i].kind != otherSignature._embeddedSignatureData[i].kind) + return false; + if (this._embeddedSignatureData[i].type != otherSignature._embeddedSignatureData[i].type) + return false; + } + + return true; + } + + return false; + } + + public override bool Equals(object obj) + { + return obj is MethodSignature && Equals((MethodSignature)obj); + } + + public override int GetHashCode() + { + return TypeHashingAlgorithms.ComputeMethodSignatureHashCode(_returnType.GetHashCode(), _parameters); + } + + public SignatureEnumerator GetEnumerator() + { + return new SignatureEnumerator(this); + } + + public override TypeSystemContext Context => _returnType.Context; + + public struct SignatureEnumerator + { + private int _index; + private MethodSignature _signature; + + public SignatureEnumerator(MethodSignature signature) + { + _signature = signature; + _index = -1; + } + + public TypeDesc Current => _signature[_index]; + + public bool MoveNext() + { + _index++; + return _index < _signature.Length; + } + } + } + + /// + /// Helper structure for building method signatures by cloning an existing method signature. + /// + /// + /// This can potentially avoid array allocation costs for allocating the parameter type list. + /// + public struct MethodSignatureBuilder + { + private MethodSignature _template; + private MethodSignatureFlags _flags; + private int _genericParameterCount; + private TypeDesc _returnType; + private TypeDesc[] _parameters; + private EmbeddedSignatureData[] _customModifiers; + + public MethodSignatureBuilder(MethodSignature template) + { + _template = template; + + _flags = template._flags; + _genericParameterCount = template._genericParameterCount; + _returnType = template._returnType; + _parameters = template._parameters; + _customModifiers = template._embeddedSignatureData; + } + + public MethodSignatureFlags Flags + { + set + { + _flags = value; + } + } + + public TypeDesc ReturnType + { + set + { + _returnType = value; + } + } + + [System.Runtime.CompilerServices.IndexerName("Parameter")] + public TypeDesc this[int index] + { + set + { + if (_parameters[index] == value) + return; + + if (_template != null && _parameters == _template._parameters) + { + TypeDesc[] parameters = new TypeDesc[_parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + parameters[i] = _parameters[i]; + _parameters = parameters; + } + _parameters[index] = value; + } + } + + public int Length + { + set + { + _parameters = new TypeDesc[value]; + _template = null; + } + } + + public MethodSignature ToSignature() + { + if (_template == null || + _flags != _template._flags || + _genericParameterCount != _template._genericParameterCount || + _returnType != _template._returnType || + _parameters != _template._parameters) + { + _template = new MethodSignature(_flags, _genericParameterCount, _returnType, _parameters, _customModifiers); + } + + return _template; + } + } + + /// + /// Represents the fundamental base type for all methods within the type system. + /// + public abstract partial class MethodDesc : TypeSystemEntity + { + public static readonly MethodDesc[] EmptyMethods = new MethodDesc[0]; + + private int _hashcode; + + /// + /// Allows a performance optimization that skips the potentially expensive + /// construction of a hash code if a hash code has already been computed elsewhere. + /// Use to allow objects to have their hashcode computed + /// independently of the allocation of a MethodDesc object + /// For instance, compute the hashcode when looking up the object, + /// then when creating the object, pass in the hashcode directly. + /// The hashcode specified MUST exactly match the algorithm implemented + /// on this type normally. + /// + protected void SetHashCode(int hashcode) + { + _hashcode = hashcode; + Debug.Assert(hashcode == ComputeHashCode()); + } + + public sealed override int GetHashCode() + { + if (_hashcode != 0) + return _hashcode; + + return AcquireHashCode(); + } + + private int AcquireHashCode() + { + _hashcode = ComputeHashCode(); + return _hashcode; + } + + /// + /// Compute HashCode. Should only be overriden by a MethodDesc that represents an instantiated method. + /// + protected virtual int ComputeHashCode() + { + return TypeHashingAlgorithms.ComputeMethodHashCode(OwningType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(Name)); + } + + public override bool Equals(Object o) + { + // Its only valid to compare two MethodDescs in the same context + Debug.Assert(Object.ReferenceEquals(o, null) || !(o is MethodDesc) || Object.ReferenceEquals(((MethodDesc)o).Context, this.Context)); + return Object.ReferenceEquals(this, o); + } + + /// + /// Gets the type that owns this method. This will be a or + /// an . + /// + public abstract TypeDesc OwningType + { + get; + } + + /// + /// Gets the signature of the method. + /// + public abstract MethodSignature Signature + { + get; + } + + /// + /// Gets the generic instantiation information of this method. + /// For generic definitions, retrieves the generic parameters of the method. + /// For generic instantiation, retrieves the generic arguments of the method. + /// + public virtual Instantiation Instantiation + { + get + { + return Instantiation.Empty; + } + } + + /// + /// Gets a value indicating whether this method has a generic instantiation. + /// This will be true for generic method instantiations and generic definitions. + /// + public bool HasInstantiation + { + get + { + return this.Instantiation.Length != 0; + } + } + + /// + /// Gets a value indicating whether this method is an instance constructor. + /// + public bool IsConstructor + { + get + { + // TODO: Precise check + // TODO: Cache? + return this.Name == ".ctor"; + } + } + + /// + /// Gets a value indicating whether this is a public parameterless instance constructor + /// on a non-abstract type. + /// + public virtual bool IsDefaultConstructor + { + get + { + return OwningType.GetDefaultConstructor() == this; + } + } + + /// + /// Gets a value indicating whether this method is a static constructor. + /// + public bool IsStaticConstructor + { + get + { + return this == this.OwningType.GetStaticConstructor(); + } + } + + /// + /// Gets the name of the method as specified in the metadata. + /// + public virtual string Name + { + get + { + return null; + } + } + + /// + /// Gets a value indicating whether the method is virtual. + /// + public virtual bool IsVirtual + { + get + { + return false; + } + } + + /// + /// Gets a value indicating whether this virtual method should not override any + /// virtual methods defined in any of the base classes. + /// + public virtual bool IsNewSlot + { + get + { + return false; + } + } + + /// + /// Gets a value indicating whether this virtual method needs to be overriden + /// by all non-abstract classes deriving from the method's owning type. + /// + public virtual bool IsAbstract + { + get + { + return false; + } + } + + /// + /// Gets a value indicating that this method cannot be overriden. + /// + public virtual bool IsFinal + { + get + { + return false; + } + } + + public abstract bool HasCustomAttribute(string attributeNamespace, string attributeName); + + /// + /// Retrieves the uninstantiated form of the method on the method's . + /// For generic methods, this strips method instantiation. For non-generic methods, returns 'this'. + /// To also strip instantiation of the owning type, use . + /// + public virtual MethodDesc GetMethodDefinition() + { + return this; + } + + /// + /// Gets a value indicating whether this is a method definition. This property + /// is true for non-generic methods and for uninstantiated generic methods. + /// + public bool IsMethodDefinition + { + get + { + return GetMethodDefinition() == this; + } + } + + /// + /// Retrieves the generic definition of the method on the generic definition of the owning type. + /// To only uninstantiate the method without uninstantiating the owning type, use . + /// + public virtual MethodDesc GetTypicalMethodDefinition() + { + return this; + } + + /// + /// Gets a value indicating whether this is a typical definition. This property is true + /// if neither the owning type, nor the method are instantiated. + /// + public bool IsTypicalMethodDefinition + { + get + { + return GetTypicalMethodDefinition() == this; + } + } + + /// + /// Gets a value indicating whether this is an uninstantiated generic method. + /// + public bool IsGenericMethodDefinition + { + get + { + return HasInstantiation && IsMethodDefinition; + } + } + + public bool IsFinalizer + { + get + { + TypeDesc owningType = OwningType; + return (owningType.IsObject && Name == "Finalize") || (owningType.HasFinalizer && owningType.GetFinalizer() == this); + } + } + + public virtual MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + Instantiation instantiation = Instantiation; + TypeDesc[] clone = null; + + for (int i = 0; i < instantiation.Length; i++) + { + TypeDesc uninst = instantiation[i]; + TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); + if (inst != uninst) + { + if (clone == null) + { + clone = new TypeDesc[instantiation.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = instantiation[j]; + } + } + clone[i] = inst; + } + } + + MethodDesc method = this; + + TypeDesc owningType = method.OwningType; + TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); + if (owningType != instantiatedOwningType) + { + method = Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType); + if (clone == null && instantiation.Length != 0) + return Context.GetInstantiatedMethod(method, instantiation); + } + + return (clone == null) ? method : Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone)); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs new file mode 100644 index 00000000000..e1e18c7d70b --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs @@ -0,0 +1,17 @@ +// 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 +{ + public sealed partial class MethodForInstantiatedType + { + public override string DiagnosticName + { + get + { + return _typicalMethodDef.DiagnosticName; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs new file mode 100644 index 00000000000..98e3c0be119 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs @@ -0,0 +1,141 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public sealed partial class MethodForInstantiatedType : MethodDesc + { + private readonly MethodDesc _typicalMethodDef; + private readonly InstantiatedType _instantiatedType; + + private MethodSignature _signature; + + internal MethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) + { + Debug.Assert(typicalMethodDef.GetTypicalMethodDefinition() == typicalMethodDef); + _typicalMethodDef = typicalMethodDef; + _instantiatedType = instantiatedType; + } + + // This constructor is a performance optimization - it allows supplying the hash code if it has already + // been computed prior to the allocation of this type. The supplied hash code still has to match the + // hash code this type would compute on it's own (and we assert to enforce that). + internal MethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType, int hashcode) + : this(typicalMethodDef, instantiatedType) + { + SetHashCode(hashcode); + } + + public override TypeSystemContext Context + { + get + { + return _typicalMethodDef.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _instantiatedType; + } + } + + private TypeDesc Instantiate(TypeDesc type) + { + return type.InstantiateSignature(_instantiatedType.Instantiation, new Instantiation()); + } + + public override MethodSignature Signature + { + get + { + if (_signature == null) + { + MethodSignature template = _typicalMethodDef.Signature; + MethodSignatureBuilder builder = new MethodSignatureBuilder(template); + + builder.ReturnType = Instantiate(template.ReturnType); + for (int i = 0; i < template.Length; i++) + builder[i] = Instantiate(template[i]); + + _signature = builder.ToSignature(); + } + + return _signature; + } + } + + public override Instantiation Instantiation + { + get + { + return _typicalMethodDef.Instantiation; + } + } + + public override bool IsVirtual + { + get + { + return _typicalMethodDef.IsVirtual; + } + } + + public override bool IsNewSlot + { + get + { + return _typicalMethodDef.IsNewSlot; + } + } + + public override bool IsAbstract + { + get + { + return _typicalMethodDef.IsAbstract; + } + } + + public override bool IsFinal + { + get + { + return _typicalMethodDef.IsFinal; + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return _typicalMethodDef.HasCustomAttribute(attributeNamespace, attributeName); + } + + public override MethodDesc GetTypicalMethodDefinition() + { + return _typicalMethodDef; + } + + public override bool IsDefaultConstructor + { + get + { + return _typicalMethodDef.IsDefaultConstructor; + } + } + + public override string Name + { + get + { + return _typicalMethodDef.Name; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ModuleDesc.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ModuleDesc.cs new file mode 100644 index 00000000000..6be6de9b163 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ModuleDesc.cs @@ -0,0 +1,45 @@ +// 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.Collections.Generic; + +namespace Internal.TypeSystem +{ + public abstract partial class ModuleDesc : TypeSystemEntity + { + public override TypeSystemContext Context + { + get; + } + + /// + /// Gets the assembly this module is part of (the assembly manifest module). + /// + public virtual IAssemblyDesc Assembly + { + get; + } + + public ModuleDesc(TypeSystemContext context, IAssemblyDesc assembly) + { + Context = context; + Assembly = assembly; + } + + /// + /// Gets a type in this module with the specified name. + /// + public abstract MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true); + + /// + /// Gets the global <Module> type. + /// + public abstract MetadataType GetGlobalModuleType(); + + /// + /// Retrieves a collection of all types defined in the current module. This includes nested types. + /// + public abstract IEnumerable GetAllTypes(); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ParameterizedType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ParameterizedType.cs new file mode 100644 index 00000000000..33036e75888 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ParameterizedType.cs @@ -0,0 +1,34 @@ +// 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; + +namespace Internal.TypeSystem +{ + public abstract partial class ParameterizedType : TypeDesc + { + private TypeDesc _parameterType; + + internal ParameterizedType(TypeDesc parameterType) + { + _parameterType = parameterType; + } + + public TypeDesc ParameterType + { + get + { + return _parameterType; + } + } + + public override TypeSystemContext Context + { + get + { + return _parameterType.Context; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/PointerType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/PointerType.cs new file mode 100644 index 00000000000..15e8adbde4e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/PointerType.cs @@ -0,0 +1,43 @@ +// 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 +{ + /// + /// Represents an unmanaged pointer type. + /// + public sealed partial class PointerType : ParameterizedType + { + internal PointerType(TypeDesc parameterType) + : base(parameterType) + { + } + + public override int GetHashCode() + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputePointerTypeHashCode(this.ParameterType.GetHashCode()); + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc parameterType = this.ParameterType; + TypeDesc instantiatedParameterType = parameterType.InstantiateSignature(typeInstantiation, methodInstantiation); + if (instantiatedParameterType != parameterType) + return Context.GetPointerType(instantiatedParameterType); + + return this; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = TypeFlags.Pointer; + + flags |= TypeFlags.HasGenericVarianceComputed; + flags |= TypeFlags.HasFinalizerComputed; + flags |= TypeFlags.AttributeCacheComputed; + + return flags; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/PropertySignature.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/PropertySignature.cs new file mode 100644 index 00000000000..da59e609d41 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/PropertySignature.cs @@ -0,0 +1,39 @@ +// 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 +{ + public struct PropertySignature + { + private TypeDesc[] _parameters; + + public readonly bool IsStatic; + + public readonly TypeDesc ReturnType; + + [System.Runtime.CompilerServices.IndexerName("Parameter")] + public TypeDesc this[int index] + { + get + { + return _parameters[index]; + } + } + + public int Length + { + get + { + return _parameters.Length; + } + } + + public PropertySignature(bool isStatic, TypeDesc[] parameters, TypeDesc returnType) + { + IsStatic = isStatic; + _parameters = parameters; + ReturnType = returnType; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/RuntimeInterfacesAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/RuntimeInterfacesAlgorithm.cs new file mode 100644 index 00000000000..515d531da46 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/RuntimeInterfacesAlgorithm.cs @@ -0,0 +1,26 @@ +// 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 +{ + /// + /// Pluggable RuntimeInterfaces computation algorithm. Provides an abstraction to compute + /// the list of interfaces effectively implemented by a type at runtime. + /// The computed list is exposed as . + /// + /// + /// The algorithms are expected to be directly used by derivatives + /// only. The most obvious implementation of this algorithm that uses type's metadata to + /// compute the answers is in . + /// + public abstract class RuntimeInterfacesAlgorithm + { + /// + /// Compute the RuntimeInterfaces for a TypeDesc, is permitted to depend on + /// RuntimeInterfaces of base type, but must not depend on any other + /// details of the base type. + /// + public abstract DefType[] ComputeRuntimeInterfaces(TypeDesc type); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/SignatureVariable.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/SignatureVariable.cs new file mode 100644 index 00000000000..2fde3c53897 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/SignatureVariable.cs @@ -0,0 +1,119 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public abstract partial class SignatureVariable : TypeDesc + { + private TypeSystemContext _context; + private int _index; + + internal SignatureVariable(TypeSystemContext context, int index) + { + _context = context; + _index = index; + } + + public int Index + { + get + { + return _index; + } + } + + public override TypeSystemContext Context + { + get + { + return _context; + } + } + + public abstract bool IsMethodSignatureVariable + { + get; + } + } + + public sealed partial class SignatureTypeVariable : SignatureVariable + { + internal SignatureTypeVariable(TypeSystemContext context, int index) : base(context, index) + { + } + + public override bool IsMethodSignatureVariable + { + get + { + return false; + } + } + + public override int GetHashCode() + { + return TypeHashingAlgorithms.ComputeSignatureVariableHashCode(Index, false); + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + if ((mask & TypeFlags.CategoryMask) != 0) + { + flags |= TypeFlags.SignatureTypeVariable; + } + + return flags; + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + return typeInstantiation.IsNull ? this : typeInstantiation[Index]; + } + } + + public sealed partial class SignatureMethodVariable : SignatureVariable + { + internal SignatureMethodVariable(TypeSystemContext context, int index) : base(context, index) + { + } + + public override bool IsMethodSignatureVariable + { + get + { + return true; + } + } + + public override int GetHashCode() + { + return TypeHashingAlgorithms.ComputeSignatureVariableHashCode(Index, true); + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + if ((mask & TypeFlags.CategoryMask) != 0) + { + flags |= TypeFlags.SignatureMethodVariable; + } + + return flags; + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + return methodInstantiation.IsNull ? this : methodInstantiation[Index]; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.ToString.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.ToString.cs new file mode 100644 index 00000000000..822272c15e3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.ToString.cs @@ -0,0 +1,17 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + partial class TargetDetails + { + public override string ToString() + { + return $"{Architecture}-{OperatingSystem}-{Abi}"; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.cs new file mode 100644 index 00000000000..8e4207d9a41 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.cs @@ -0,0 +1,325 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Specifies the target CPU architecture. + /// + public enum TargetArchitecture + { + Unknown, + ARM, + ARM64, + X64, + X86, + Wasm32, + } + + /// + /// Specifies the target ABI. + /// + public enum TargetOS + { + Unknown, + Windows, + Linux, + OSX, + FreeBSD, + NetBSD, + WebAssembly, + } + + public enum TargetAbi + { + Unknown, + /// + /// Cross-platform console model + /// + CoreRT, + /// + /// Jit runtime ABI + /// + Jit, + /// + /// Cross-platform portable C++ codegen + /// + CppCodegen, + } + + /// + /// Represents various details about the compilation target that affect + /// layout, padding, allocations, or ABI. + /// + public partial class TargetDetails + { + /// + /// Gets the target CPU architecture. + /// + public TargetArchitecture Architecture + { + get; + } + + /// + /// Gets the target ABI. + /// + public TargetOS OperatingSystem + { + get; + } + + public TargetAbi Abi + { + get; + } + + /// + /// Gets the size of a pointer for the target of the compilation. + /// + public int PointerSize + { + get + { + switch (Architecture) + { + case TargetArchitecture.ARM64: + case TargetArchitecture.X64: + return 8; + case TargetArchitecture.ARM: + case TargetArchitecture.X86: + case TargetArchitecture.Wasm32: + return 4; + default: + throw new NotSupportedException(); + } + } + } + + public bool SupportsRelativePointers + { + get + { + return (Abi != TargetAbi.CppCodegen) && (Architecture != TargetArchitecture.Wasm32); + } + } + + /// + /// Gets the maximum alignment to which something can be aligned + /// + public int MaximumAlignment + { + get + { + if (Architecture == TargetArchitecture.ARM) + { + // Corresponds to alignment required for __m128 (there's no __m256) + return 8; + } + else if (Architecture == TargetArchitecture.ARM64) + { + // Corresponds to alignmet required for __m256 + return 16; + } + + // 256-bit vector is the type with the higest alignment we support + return 32; + } + } + + public LayoutInt LayoutPointerSize => new LayoutInt(PointerSize); + + /// + /// Gets the default field packing size. + /// + public int DefaultPackingSize + { + get + { + // We use default packing size of 32 irrespective of the platform. + return 32; + } + } + + /// + /// Gets the minimum required alignment for methods whose address is visible + /// to managed code. + /// + public int MinimumFunctionAlignment + { + get + { + // We use a minimum alignment of 4 irrespective of the platform. + // This is to prevent confusing the method address with a fat function pointer. + return 4; + } + } + + /// + /// Gets the alignment that is optimal for this platform. + /// + public int OptimumFunctionAlignment + { + get + { + // Matches the choice in the C++ compiler. + // We want a number that is optimized for micro-op caches in the processor. + return 16; + } + } + + public int MinimumCodeAlignment + { + get + { + switch (Architecture) + { + case TargetArchitecture.ARM: + return 2; + case TargetArchitecture.ARM64: + return 4; + default: + return 1; + } + } + } + + public TargetDetails(TargetArchitecture architecture, TargetOS targetOS, TargetAbi abi) + { + Architecture = architecture; + OperatingSystem = targetOS; + Abi = abi; + } + + /// + /// Gets the dyadic logarithm of the maximum size of a primitive type + /// + public static int MaximumLog2PrimitiveSize + { + get + { + return 3; + } + } + + /// + /// Gets the maximum size of a primitive type + /// + public static int MaximumPrimitiveSize + { + get + { + return 1 << MaximumLog2PrimitiveSize; + } + } + + /// + /// Retrieves the size of a well known type. + /// + public LayoutInt GetWellKnownTypeSize(DefType type) + { + switch (type.Category) + { + case TypeFlags.Void: + return new LayoutInt(PointerSize); + case TypeFlags.Boolean: + return new LayoutInt(1); + case TypeFlags.Char: + return new LayoutInt(2); + case TypeFlags.Byte: + case TypeFlags.SByte: + return new LayoutInt(1); + case TypeFlags.UInt16: + case TypeFlags.Int16: + return new LayoutInt(2); + case TypeFlags.UInt32: + case TypeFlags.Int32: + return new LayoutInt(4); + case TypeFlags.UInt64: + case TypeFlags.Int64: + return new LayoutInt(8); + case TypeFlags.Single: + return new LayoutInt(4); + case TypeFlags.Double: + return new LayoutInt(8); + case TypeFlags.UIntPtr: + case TypeFlags.IntPtr: + return new LayoutInt(PointerSize); + } + + // Add new well known types if necessary + + throw new InvalidOperationException(); + } + + /// + /// Retrieves the alignment required by a well known type. + /// + public LayoutInt GetWellKnownTypeAlignment(DefType type) + { + // Size == Alignment for all platforms. + return GetWellKnownTypeSize(type); + } + + /// + /// Given an alignment of the fields of a type, determine the alignment that is necessary for allocating the object on the GC heap + /// + /// + public LayoutInt GetObjectAlignment(LayoutInt fieldAlignment) + { + switch (Architecture) + { + case TargetArchitecture.ARM: + // ARM supports two alignments for objects on the GC heap (4 byte and 8 byte) + if (fieldAlignment.IsIndeterminate) + return LayoutInt.Indeterminate; + + if (fieldAlignment.AsInt <= 4) + return new LayoutInt(4); + else + return new LayoutInt(8); + case TargetArchitecture.X64: + case TargetArchitecture.ARM64: + return new LayoutInt(8); + case TargetArchitecture.X86: + case TargetArchitecture.Wasm32: + return new LayoutInt(4); + default: + throw new NotSupportedException(); + } + } + + /// + /// Returns True if compiling for Windows + /// + public bool IsWindows + { + get + { + return OperatingSystem == TargetOS.Windows; + } + } + + /// + /// Maximum number of elements in a HFA type. + /// + public int MaximumHfaElementCount + { + get + { + // There is a hard limit of 4 elements on an HFA type, see + // http://blogs.msdn.com/b/vcblog/archive/2013/07/12/introducing-vector-calling-convention.aspx + Debug.Assert(Architecture == TargetArchitecture.ARM || + Architecture == TargetArchitecture.ARM64 || + Architecture == TargetArchitecture.X64 || + Architecture == TargetArchitecture.X86); + + return 4; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ThreadSafeFlags.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ThreadSafeFlags.cs new file mode 100644 index 00000000000..70f0b22c40e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ThreadSafeFlags.cs @@ -0,0 +1,39 @@ +// 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.Runtime.CompilerServices; +using Interlocked = System.Threading.Interlocked; + +namespace Internal.TypeSystem +{ + public struct ThreadSafeFlags + { + private volatile int _value; + + public int Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return _value; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasFlags(int value) + { + return (_value & value) == value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddFlags(int flagsToAdd) + { + var originalFlags = _value; + while (Interlocked.CompareExchange(ref _value, originalFlags | flagsToAdd, originalFlags) != originalFlags) + { + originalFlags = _value; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.Common.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.Common.cs new file mode 100644 index 00000000000..40b5928d98e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.Common.cs @@ -0,0 +1,127 @@ +// 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.Text; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public static partial class ThrowHelper + { + [System.Diagnostics.DebuggerHidden] + public static void ThrowTypeLoadException(string nestedTypeName, ModuleDesc module) + { + ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, nestedTypeName, Format.Module(module)); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowTypeLoadException(string @namespace, string name, ModuleDesc module) + { + ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, Format.Type(@namespace, name), Format.Module(module)); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowTypeLoadException(TypeDesc type) + { + ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, Format.Type(type), Format.OwningModule(type)); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowTypeLoadException(ExceptionStringID id, MethodDesc method) + { + ThrowTypeLoadException(id, Format.Type(method.OwningType), Format.OwningModule(method), Format.Method(method)); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowTypeLoadException(ExceptionStringID id, TypeDesc type, string messageArg) + { + ThrowTypeLoadException(id, Format.Type(type), Format.OwningModule(type), messageArg); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowTypeLoadException(ExceptionStringID id, TypeDesc type) + { + ThrowTypeLoadException(id, Format.Type(type), Format.OwningModule(type)); + } + + private static partial class Format + { + public static string OwningModule(MethodDesc method) + { + return OwningModule(method.OwningType); + } + + public static string Module(ModuleDesc module) + { + if (module == null) + return "?"; + + IAssemblyDesc assembly = module as IAssemblyDesc; + if (assembly != null) + { + return assembly.GetName().FullName; + } + else + { + Debug.Fail("Multi-module assemblies"); + return module.ToString(); + } + } + + public static string Type(TypeDesc type) + { + return ExceptionTypeNameFormatter.Instance.FormatName(type); + } + + public static string Type(string @namespace, string name) + { + return String.IsNullOrEmpty(@namespace) ? name : @namespace + "." + name; + } + + public static string Field(TypeDesc owningType, string fieldName) + { + return Type(owningType) + "." + fieldName; + } + + public static string Method(MethodDesc method) + { + return Method(method.OwningType, method.Name, method.Signature); + } + + public static string Method(TypeDesc owningType, string methodName, MethodSignature signature) + { + StringBuilder sb = new StringBuilder(); + + if (signature != null) + { + sb.Append(ExceptionTypeNameFormatter.Instance.FormatName(signature.ReturnType)); + sb.Append(' '); + } + + sb.Append(ExceptionTypeNameFormatter.Instance.FormatName(owningType)); + sb.Append('.'); + sb.Append(methodName); + + if (signature != null) + { + sb.Append('('); + for (int i = 0; i < signature.Length; i++) + { + if (i > 0) + { + sb.Append(", "); + } + + sb.Append(ExceptionTypeNameFormatter.Instance.FormatName(signature[i])); + } + sb.Append(')'); + } + + return sb.ToString(); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.cs new file mode 100644 index 00000000000..46ff4cee5a2 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ThrowHelper.cs @@ -0,0 +1,65 @@ +// 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 +{ + public static partial class ThrowHelper + { + [System.Diagnostics.DebuggerHidden] + private static void ThrowTypeLoadException(ExceptionStringID id, string typeName, string assemblyName, string messageArg) + { + throw new TypeSystemException.TypeLoadException(id, typeName, assemblyName, messageArg); + } + + [System.Diagnostics.DebuggerHidden] + private static void ThrowTypeLoadException(ExceptionStringID id, string typeName, string assemblyName) + { + throw new TypeSystemException.TypeLoadException(id, typeName, assemblyName); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowMissingMethodException(TypeDesc owningType, string methodName, MethodSignature signature) + { + throw new TypeSystemException.MissingMethodException(ExceptionStringID.MissingMethod, Format.Method(owningType, methodName, signature)); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowMissingFieldException(TypeDesc owningType, string fieldName) + { + throw new TypeSystemException.MissingFieldException(ExceptionStringID.MissingField, Format.Field(owningType, fieldName)); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowFileNotFoundException(ExceptionStringID id, string fileName) + { + throw new TypeSystemException.FileNotFoundException(id, fileName); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowInvalidProgramException() + { + throw new TypeSystemException.InvalidProgramException(); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowInvalidProgramException(ExceptionStringID id, MethodDesc method) + { + throw new TypeSystemException.InvalidProgramException(id, Format.Method(method)); + } + + [System.Diagnostics.DebuggerHidden] + public static void ThrowBadImageFormatException() + { + throw new TypeSystemException.BadImageFormatException(); + } + + private static partial class Format + { + public static string OwningModule(TypeDesc type) + { + return Module((type as MetadataType)?.Module); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.Interfaces.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.Interfaces.cs new file mode 100644 index 00000000000..e28168c19a9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.Interfaces.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. + +using System; +using System.Threading; +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Api surface for TypeDesc that relates to interfaces + + public partial class TypeDesc + { + private DefType[] _runtimeInterfaces; + + /// + /// The interfaces implemented by this type at runtime. There may be duplicates in this list. + /// + /// + public DefType[] RuntimeInterfaces + { + get + { + if (_runtimeInterfaces == null) + { + return InitializeRuntimeInterfaces(); + } + + return _runtimeInterfaces; + } + } + + private DefType[] InitializeRuntimeInterfaces() + { + RuntimeInterfacesAlgorithm algorithm = this.Context.GetRuntimeInterfacesAlgorithmForType(this); + DefType[] computedInterfaces = algorithm != null ? algorithm.ComputeRuntimeInterfaces(this) : Array.Empty(); + Interlocked.CompareExchange(ref _runtimeInterfaces, computedInterfaces, null); + return _runtimeInterfaces; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.ToString.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.ToString.cs new file mode 100644 index 00000000000..34e616fae47 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.ToString.cs @@ -0,0 +1,14 @@ +// 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 +{ + partial class TypeDesc + { + public override string ToString() + { + return DebugNameFormatter.Instance.FormatName(this, DebugNameFormatter.FormatOptions.Default); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.cs new file mode 100644 index 00000000000..d9110d148e1 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.cs @@ -0,0 +1,633 @@ +// 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 System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Internal.TypeSystem +{ + /// + /// Represents the fundamental base type of all types within the type system. + /// + public abstract partial class TypeDesc : TypeSystemEntity + { + public static readonly TypeDesc[] EmptyTypes = new TypeDesc[0]; + + /// Inherited types are required to override, and should use the algorithms + /// in TypeHashingAlgorithms in their implementation. + public abstract override int GetHashCode(); + + public override bool Equals(Object o) + { + // Its only valid to compare two TypeDescs in the same context + Debug.Assert(o == null || !(o is TypeDesc) || Object.ReferenceEquals(((TypeDesc)o).Context, this.Context)); + return Object.ReferenceEquals(this, o); + } + +#if DEBUG + public static bool operator ==(TypeDesc left, TypeDesc right) + { + // Its only valid to compare two TypeDescs in the same context + Debug.Assert(Object.ReferenceEquals(left, null) || Object.ReferenceEquals(right, null) || Object.ReferenceEquals(left.Context, right.Context)); + return Object.ReferenceEquals(left, right); + } + + public static bool operator !=(TypeDesc left, TypeDesc right) + { + // Its only valid to compare two TypeDescs in the same context + Debug.Assert(Object.ReferenceEquals(left, null) || Object.ReferenceEquals(right, null) || Object.ReferenceEquals(left.Context, right.Context)); + return !Object.ReferenceEquals(left, right); + } +#endif + + // The most frequently used type properties are cached here to avoid excesive virtual calls + private TypeFlags _typeFlags; + + /// + /// Gets the generic instantiation information of this type. + /// For generic definitions, retrieves the generic parameters of the type. + /// For generic instantiation, retrieves the generic arguments of the type. + /// + public virtual Instantiation Instantiation + { + get + { + return Instantiation.Empty; + } + } + + /// + /// Gets a value indicating whether this type has a generic instantiation. + /// This will be true for generic type instantiations and generic definitions. + /// + public bool HasInstantiation + { + get + { + return this.Instantiation.Length != 0; + } + } + + internal void SetWellKnownType(WellKnownType wellKnownType) + { + TypeFlags flags; + + switch (wellKnownType) + { + case WellKnownType.Void: + case WellKnownType.Boolean: + case WellKnownType.Char: + case WellKnownType.SByte: + case WellKnownType.Byte: + case WellKnownType.Int16: + case WellKnownType.UInt16: + case WellKnownType.Int32: + case WellKnownType.UInt32: + case WellKnownType.Int64: + case WellKnownType.UInt64: + case WellKnownType.IntPtr: + case WellKnownType.UIntPtr: + case WellKnownType.Single: + case WellKnownType.Double: + flags = (TypeFlags)wellKnownType; + break; + + case WellKnownType.ValueType: + case WellKnownType.Enum: + flags = TypeFlags.Class; + break; + + case WellKnownType.Nullable: + flags = TypeFlags.Nullable; + break; + + case WellKnownType.Object: + case WellKnownType.String: + case WellKnownType.Array: + case WellKnownType.MulticastDelegate: + case WellKnownType.Exception: + flags = TypeFlags.Class; + break; + + case WellKnownType.RuntimeTypeHandle: + case WellKnownType.RuntimeMethodHandle: + case WellKnownType.RuntimeFieldHandle: + case WellKnownType.TypedReference: + case WellKnownType.ByReferenceOfT: + flags = TypeFlags.ValueType; + break; + + default: + throw new ArgumentException(); + } + + _typeFlags = flags; + } + + protected abstract TypeFlags ComputeTypeFlags(TypeFlags mask); + + [MethodImpl(MethodImplOptions.NoInlining)] + private TypeFlags InitializeTypeFlags(TypeFlags mask) + { + TypeFlags flags = ComputeTypeFlags(mask); + + if ((flags & mask) == 0) + flags = Context.ComputeTypeFlags(this, flags, mask); + + Debug.Assert((flags & mask) != 0); + _typeFlags |= flags; + + return flags & mask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected internal TypeFlags GetTypeFlags(TypeFlags mask) + { + TypeFlags flags = _typeFlags & mask; + if (flags != 0) + return flags; + return InitializeTypeFlags(mask); + } + + /// + /// Retrieves the category of the type. This is one of the possible values of + /// less than . + /// + public TypeFlags Category + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask); + } + } + + /// + /// Gets a value indicating whether this type is an interface type. + /// + public bool IsInterface + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Interface; + } + } + + /// + /// Gets a value indicating whether this type is a value type (not a reference type). + /// + public bool IsValueType + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) < TypeFlags.Class; + } + } + + /// + /// Gets a value indicating whether this is one of the primitive types (boolean, char, void, + /// a floating point, or an integer type). + /// + public bool IsPrimitive + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) < TypeFlags.ValueType; + } + } + + /// + /// Gets a value indicating whether this is an enum type. + /// Access to retrieve the underlying integral type. + /// + public bool IsEnum + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Enum; + } + } + + /// + /// Gets a value indicating whether this is a delegate type. + /// + public bool IsDelegate + { + get + { + var baseType = this.BaseType; + return (baseType != null) ? baseType.IsWellKnownType(WellKnownType.MulticastDelegate) : false; + } + } + + /// + /// Gets a value indicating whether this is System.Void type. + /// + public bool IsVoid + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Void; + } + } + + /// + /// Gets a value indicating whether this is System.String type. + /// + public bool IsString + { + get + { + return this.IsWellKnownType(WellKnownType.String); + } + } + + /// + /// Gets a value indicating whether this is System.Object type. + /// + public bool IsObject + { + get + { + return this.IsWellKnownType(WellKnownType.Object); + } + } + + /// + /// Gets a value indicating whether this is a generic definition, or + /// an instance of System.Nullable`1. + /// + public bool IsNullable + { + get + { + return this.GetTypeDefinition().IsWellKnownType(WellKnownType.Nullable); + } + } + + /// + /// Gets a value indicating whether this is a generic definition, or + /// an instance of System.ByReference`1. + /// + public bool IsByReferenceOfT + { + get + { + return this.GetTypeDefinition().IsWellKnownType(WellKnownType.ByReferenceOfT); + } + } + + /// + /// Gets a value indicating whether this is an array type (). + /// Note this will return true for both multidimensional array types and vector types. + /// Use to check for vector types. + /// + public bool IsArray + { + get + { + return this is ArrayType; + } + } + + /// + /// Gets a value indicating whether this is a vector type. A vector is a single-dimensional + /// array with a zero lower bound. To check for arrays in general, use . + /// + public bool IsSzArray + { + get + { + return this.IsArray && ((ArrayType)this).IsSzArray; + } + } + + /// + /// Gets a value indicating whether this is a non-vector array type. + /// To check for arrays in general, use . + /// + public bool IsMdArray + { + get + { + return this.IsArray && ((ArrayType)this).IsMdArray; + } + } + + /// + /// Gets a value indicating whether this is a managed pointer type (). + /// + public bool IsByRef + { + get + { + return this is ByRefType; + } + } + + /// + /// Gets a value indicating whether this is an unmanaged pointer type (). + /// + public bool IsPointer + { + get + { + return this is PointerType; + } + } + + /// + /// Gets a value indicating whether this is an unmanaged function pointer type (). + /// + public bool IsFunctionPointer + { + get + { + return this is FunctionPointerType; + } + } + + /// + /// Gets a value indicating whether this is a or . + /// + public bool IsSignatureVariable + { + get + { + return this is SignatureTypeVariable || this is SignatureMethodVariable; + } + } + + /// + /// Gets a value indicating whether this is a generic parameter (). + /// + public bool IsGenericParameter + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.GenericParameter; + } + } + + /// + /// Gets a value indicating whether this is a pointer, byref, array, or szarray type, + /// and can be used as a ParameterizedType. + /// + public bool IsParameterizedType + { + get + { + TypeFlags flags = GetTypeFlags(TypeFlags.CategoryMask); + Debug.Assert((flags >= TypeFlags.Array && flags <= TypeFlags.Pointer) == (this is ParameterizedType)); + return (flags >= TypeFlags.Array && flags <= TypeFlags.Pointer); + } + } + + /// + /// Gets a value indicating whether this is a class, an interface, a value type, or a + /// generic instance of one of them. + /// + public bool IsDefType + { + get + { + Debug.Assert(GetTypeFlags(TypeFlags.CategoryMask) <= TypeFlags.Interface == this is DefType); + return GetTypeFlags(TypeFlags.CategoryMask) <= TypeFlags.Interface; + } + } + + /// + /// Gets a value indicating whether locations of this type refer to an object on the GC heap. + /// + public bool IsGCPointer + { + get + { + TypeFlags category = GetTypeFlags(TypeFlags.CategoryMask); + return category == TypeFlags.Class + || category == TypeFlags.Array + || category == TypeFlags.SzArray + || category == TypeFlags.Interface; + } + } + + /// + /// Gets the type from which this type derives from, or null if there's no such type. + /// + public virtual DefType BaseType + { + get + { + return null; + } + } + + /// + /// Gets a value indicating whether this type has a base type. + /// + public bool HasBaseType + { + get + { + return BaseType != null; + } + } + + /// + /// If this is an enum type, gets the underlying integral type of the enum type. + /// For all other types, returns 'this'. + /// + public virtual TypeDesc UnderlyingType + { + get + { + if (!this.IsEnum) + return this; + + // TODO: Cache the result? + foreach (var field in this.GetFields()) + { + if (!field.IsStatic) + return field.FieldType; + } + + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, this); + return null; // Unreachable + } + } + + /// + /// Gets a value indicating whether this type has a class constructor method. + /// Use to retrieve it. + /// + public bool HasStaticConstructor + { + get + { + return (GetTypeFlags(TypeFlags.HasStaticConstructor | TypeFlags.HasStaticConstructorComputed) & TypeFlags.HasStaticConstructor) != 0; + } + } + + /// + /// Gets all methods on this type defined within the type's metadata. + /// This will not include methods injected by the type system context. + /// + public virtual IEnumerable GetMethods() + { + return MethodDesc.EmptyMethods; + } + + /// + /// Gets a named method on the type. This method only looks at methods defined + /// in type's metadata. The parameter can be null. + /// If signature is not specified and there are multiple matches, the first one + /// is returned. Returns null if method not found. + /// + // TODO: Substitutions, generics, modopts, ... + public virtual MethodDesc GetMethod(string name, MethodSignature signature) + { + foreach (var method in GetMethods()) + { + if (method.Name == name) + { + if (signature == null || signature.Equals(method.Signature)) + return method; + } + } + return null; + } + + /// + /// Retrieves the class constructor method of this type. + /// + /// + public virtual MethodDesc GetStaticConstructor() + { + return null; + } + + /// + /// Retrieves the public parameterless constructor method of the type, or null if there isn't one + /// or the type is abstract. + /// + public virtual MethodDesc GetDefaultConstructor() + { + return null; + } + + /// + /// Gets all fields on the type as defined in the metadata. + /// + public virtual IEnumerable GetFields() + { + return FieldDesc.EmptyFields; + } + + /// + /// Gets a named field on the type. Returns null if the field wasn't found. + /// + // TODO: Substitutions, generics, modopts, ... + // TODO: field signature + public virtual FieldDesc GetField(string name) + { + foreach (var field in GetFields()) + { + if (field.Name == name) + return field; + } + return null; + } + + public virtual TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + return this; + } + + /// + /// Gets the definition of the type. If this is a generic type instance, + /// this method strips the instantiation (E.g C<int> -> C<T>) + /// + public virtual TypeDesc GetTypeDefinition() + { + return this; + } + + /// + /// Gets a value indicating whether this is a type definition. Returns false + /// if this is an instantiated generic type. + /// + public bool IsTypeDefinition + { + get + { + return GetTypeDefinition() == this; + } + } + + /// + /// Determine if two types share the same type definition + /// + public bool HasSameTypeDefinition(TypeDesc otherType) + { + return GetTypeDefinition() == otherType.GetTypeDefinition(); + } + + /// + /// Gets a value indicating whether this type has a finalizer method. + /// Use to retrieve the method. + /// + public bool HasFinalizer + { + get + { + return (GetTypeFlags(TypeFlags.HasFinalizer | TypeFlags.HasFinalizerComputed) & TypeFlags.HasFinalizer) != 0; + } + } + + /// + /// Gets the finalizer method (an override of the System.Object::Finalize method) + /// if this type has one. Returns null if the type doesn't define one. + /// + public virtual MethodDesc GetFinalizer() + { + return null; + } + + /// + /// Gets a value indicating whether this type has generic variance (the definition of the type + /// has a generic parameter that is co- or contravariant). + /// + public bool HasVariance + { + get + { + return (GetTypeFlags(TypeFlags.HasGenericVariance | TypeFlags.HasGenericVarianceComputed) & TypeFlags.HasGenericVariance) != 0; + } + } + + /// + /// Gets a value indicating whether this type is an uninstantiated definition of a generic type. + /// + public bool IsGenericDefinition + { + get + { + return HasInstantiation && IsTypeDefinition; + } + } + + /// + /// Gets a value indicating whether this is a byref-like type + /// (a TypedReference, Span<T>, etc.). + /// + public bool IsByRefLike + { + get + { + return (GetTypeFlags(TypeFlags.IsByRefLike | TypeFlags.AttributeCacheComputed) & TypeFlags.IsByRefLike) != 0; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeFlags.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeFlags.cs new file mode 100644 index 00000000000..028a7356d21 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeFlags.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; + +namespace Internal.TypeSystem +{ + [Flags] + public enum TypeFlags + { + CategoryMask = 0x3F, + + // Primitive + Unknown = 0x00, + Void = 0x01, + Boolean = 0x02, + Char = 0x03, + SByte = 0x04, + Byte = 0x05, + Int16 = 0x06, + UInt16 = 0x07, + Int32 = 0x08, + UInt32 = 0x09, + Int64 = 0x0A, + UInt64 = 0x0B, + IntPtr = 0x0C, + UIntPtr = 0x0D, + Single = 0x0E, + Double = 0x0F, + + ValueType = 0x10, + Enum = 0x11, // Parent is enum + Nullable = 0x12, // Nullable instantiation + // Unused 0x13 + + Class = 0x14, + Interface = 0x15, + // Unused 0x16 + + Array = 0x17, + SzArray = 0x18, + ByRef = 0x19, + Pointer = 0x1A, + FunctionPointer = 0x1B, + + GenericParameter = 0x1C, + SignatureTypeVariable = 0x1D, + SignatureMethodVariable = 0x1E, + + HasGenericVariance = 0x100, + HasGenericVarianceComputed = 0x200, + + HasStaticConstructor = 0x400, + HasStaticConstructorComputed = 0x800, + + HasFinalizerComputed = 0x1000, + HasFinalizer = 0x2000, + + IsByRefLike = 0x04000, + AttributeCacheComputed = 0x08000, + IsIntrinsic = 0x10000, + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeHashingAlgorithms.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeHashingAlgorithms.cs new file mode 100644 index 00000000000..8e84efc26b6 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeHashingAlgorithms.cs @@ -0,0 +1,255 @@ +// 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. + +// --------------------------------------------------------------------------- +// Generic functions to compute the hashcode value of types +// --------------------------------------------------------------------------- + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Internal.NativeFormat +{ + public static class TypeHashingAlgorithms + { + public struct HashCodeBuilder + { + private int _hash1; + private int _hash2; + private int _numCharactersHashed; + + public HashCodeBuilder(string seed) + { + _hash1 = 0x6DA3B944; + _hash2 = 0; + _numCharactersHashed = 0; + + Append(seed); + } + + public void Append(string src) + { + if (src.Length == 0) + return; + + int startIndex = 0; + if ((_numCharactersHashed & 1) == 1) + { + _hash2 = (_hash2 + _rotl(_hash2, 5)) ^ src[0]; + startIndex = 1; + } + + for (int i = startIndex; i < src.Length; i += 2) + { + _hash1 = (_hash1 + _rotl(_hash1, 5)) ^ src[i]; + if ((i + 1) < src.Length) + _hash2 = (_hash2 + _rotl(_hash2, 5)) ^ src[i + 1]; + } + + _numCharactersHashed += src.Length; + } + + public int ToHashCode() + { + int hash1 = _hash1 + _rotl(_hash1, 8); + int hash2 = _hash2 + _rotl(_hash2, 8); + + return hash1 ^ hash2; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int _rotl(int value, int shift) + { + return (int)(((uint)value << shift) | ((uint)value >> (32 - shift))); + } + + // + // Returns the hashcode value of the 'src' string + // + public static int ComputeNameHashCode(string src) + { + int hash1 = 0x6DA3B944; + int hash2 = 0; + + for (int i = 0; i < src.Length; i += 2) + { + hash1 = (hash1 + _rotl(hash1, 5)) ^ src[i]; + if ((i + 1) < src.Length) + hash2 = (hash2 + _rotl(hash2, 5)) ^ src[i + 1]; + } + + hash1 += _rotl(hash1, 8); + hash2 += _rotl(hash2, 8); + + return hash1 ^ hash2; + } + + public static unsafe int ComputeASCIINameHashCode(byte* data, int length, out bool isAscii) + { + int hash1 = 0x6DA3B944; + int hash2 = 0; + int asciiMask = 0; + + for (int i = 0; i < length; i += 2) + { + int b1 = data[i]; + asciiMask |= b1; + hash1 = (hash1 + _rotl(hash1, 5)) ^ b1; + if ((i + 1) < length) + { + int b2 = data[i]; + asciiMask |= b2; + hash2 = (hash2 + _rotl(hash2, 5)) ^ b2; + } + } + + hash1 += _rotl(hash1, 8); + hash2 += _rotl(hash2, 8); + + isAscii = (asciiMask & 0x80) == 0; + + return hash1 ^ hash2; + } + + // This function may be needed in a portion of the codebase which is too low level to use + // globalization, ergo, we cannot call ToString on the integer. + private static string IntToString(int arg) + { + // This IntToString function is only expected to be used for MDArrayRanks, and therefore is only for positive numbers + Debug.Assert(arg > 0); + StringBuilder sb = new StringBuilder(1); + + while (arg != 0) + { + sb.Append((char)('0' + (arg % 10))); + arg = arg / 10; + } + + // Reverse the string + int sbLen = sb.Length; + int pivot = sbLen / 2; + for (int i = 0; i < pivot; i++) + { + int iToSwapWith = sbLen - i - 1; + char temp = sb[i]; + sb[i] = sb[iToSwapWith]; + sb[iToSwapWith] = temp; + } + + return sb.ToString(); + } + + public static int ComputeArrayTypeHashCode(int elementTypeHashCode, int rank) + { + // Arrays are treated as generic types in some parts of our system. The array hashcodes are + // carefully crafted to be the same as the hashcodes of their implementation generic types. + + int hashCode; + if (rank == -1) + { + hashCode = unchecked((int)0xd5313557u); + Debug.Assert(hashCode == ComputeNameHashCode("System.Array`1")); + } + else + { + hashCode = ComputeNameHashCode("System.MDArrayRank" + IntToString(rank) + "`1"); + } + + hashCode = (hashCode + _rotl(hashCode, 13)) ^ elementTypeHashCode; + return (hashCode + _rotl(hashCode, 15)); + } + + public static int ComputeArrayTypeHashCode(T elementType, int rank) + { + return ComputeArrayTypeHashCode(elementType.GetHashCode(), rank); + } + + + public static int ComputePointerTypeHashCode(int pointeeTypeHashCode) + { + return (pointeeTypeHashCode + _rotl(pointeeTypeHashCode, 5)) ^ 0x12D0; + } + + public static int ComputePointerTypeHashCode(T pointeeType) + { + return ComputePointerTypeHashCode(pointeeType.GetHashCode()); + } + + + public static int ComputeByrefTypeHashCode(int parameterTypeHashCode) + { + return (parameterTypeHashCode + _rotl(parameterTypeHashCode, 7)) ^ 0x4C85; + } + + public static int ComputeByrefTypeHashCode(T parameterType) + { + return ComputeByrefTypeHashCode(parameterType.GetHashCode()); + } + + + public static int ComputeNestedTypeHashCode(int enclosingTypeHashCode, int nestedTypeNameHash) + { + return (enclosingTypeHashCode + _rotl(enclosingTypeHashCode, 11)) ^ nestedTypeNameHash; + } + + + public static int ComputeGenericInstanceHashCode(int genericDefinitionHashCode, ARG[] genericTypeArguments) + { + int hashcode = genericDefinitionHashCode; + for (int i = 0; i < genericTypeArguments.Length; i++) + { + int argumentHashCode = genericTypeArguments[i].GetHashCode(); + hashcode = (hashcode + _rotl(hashcode, 13)) ^ argumentHashCode; + } + return (hashcode + _rotl(hashcode, 15)); + } + + public static int ComputeMethodSignatureHashCode(int returnTypeHashCode, ARG[] parameters) + { + // We're not taking calling conventions into consideration here mostly because there's no + // exchange enum type that would define them. We could define one, but the amount of additional + // information it would bring (16 or so possibilities) is likely not worth it. + int hashcode = returnTypeHashCode; + for (int i = 0; i < parameters.Length; i++) + { + int parameterHashCode = parameters[i].GetHashCode(); + hashcode = (hashcode + _rotl(hashcode, 13)) ^ parameterHashCode; + } + return (hashcode + _rotl(hashcode, 15)); + } + + /// + /// Produce a hashcode for a specific method + /// + /// HashCode of the type that owns the method + /// HashCode of either the name of the method (for non-generic methods) or the GenericInstanceHashCode of the name+generic arguments of the method. + /// + public static int ComputeMethodHashCode(int typeHashCode, int nameOrNameAndGenericArgumentsHashCode) + { + // TODO! This hash combining function isn't good, but it matches logic used in the past + // consider changing to a better combining function once all uses use this function + return typeHashCode ^ nameOrNameAndGenericArgumentsHashCode; + } + + /// + /// Produce a hashcode for a generic signature variable + /// + /// zero based index + /// true if the signature variable describes a method + public static int ComputeSignatureVariableHashCode(int index, bool method) + { + if (method) + { + return index * 0x7822381 + 0x54872645; + } + else + { + return index * 0x5498341 + 0x832424; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemContext.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemContext.cs new file mode 100644 index 00000000000..35f009c3687 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemContext.cs @@ -0,0 +1,784 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using System.Reflection; + +using Internal.NativeFormat; + +namespace Internal.TypeSystem +{ + public abstract partial class TypeSystemContext + { + public TypeSystemContext() : this(new TargetDetails(TargetArchitecture.Unknown, TargetOS.Unknown, TargetAbi.Unknown)) + { + } + + public TypeSystemContext(TargetDetails target) + { + Target = target; + + _instantiatedTypes = new InstantiatedTypeKey.InstantiatedTypeKeyHashtable(); + + _arrayTypes = new ArrayTypeKey.ArrayTypeKeyHashtable(); + + _byRefTypes = new ByRefHashtable(); + + _pointerTypes = new PointerHashtable(); + + _functionPointerTypes = new FunctionPointerHashtable(); + + _instantiatedMethods = new InstantiatedMethodKey.InstantiatedMethodKeyHashtable(); + + _methodForInstantiatedTypes = new MethodForInstantiatedTypeKey.MethodForInstantiatedTypeKeyHashtable(); + + _fieldForInstantiatedTypes = new FieldForInstantiatedTypeKey.FieldForInstantiatedTypeKeyHashtable(); + + _signatureVariables = new SignatureVariableHashtable(this); + } + + public TargetDetails Target + { + get; + } + + public ModuleDesc SystemModule + { + get; + private set; + } + + protected void InitializeSystemModule(ModuleDesc systemModule) + { + Debug.Assert(SystemModule == null); + SystemModule = systemModule; + } + + public abstract DefType GetWellKnownType(WellKnownType wellKnownType, bool throwIfNotFound = true); + + public virtual ModuleDesc ResolveAssembly(AssemblyName name, bool throwIfNotFound = true) + { + if (throwIfNotFound) + throw new NotSupportedException(); + return null; + } + + internal virtual ModuleDesc ResolveModule(IAssemblyDesc referencingModule, string fileName, bool throwIfNotFound = true) + { + if (throwIfNotFound) + throw new NotSupportedException(); + return null; + } + + // + // Array types + // + + public ArrayType GetArrayType(TypeDesc elementType) + { + return GetArrayType(elementType, -1); + } + + // + // MDArray types + // + + private struct ArrayTypeKey + { + private TypeDesc _elementType; + private int _rank; + + public ArrayTypeKey(TypeDesc elementType, int rank) + { + _elementType = elementType; + _rank = rank; + } + + public TypeDesc ElementType + { + get + { + return _elementType; + } + } + + public int Rank + { + get + { + return _rank; + } + } + + public class ArrayTypeKeyHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(ArrayTypeKey key) + { + return TypeHashingAlgorithms.ComputeArrayTypeHashCode(key._elementType, key._rank); + } + + protected override int GetValueHashCode(ArrayType value) + { + return TypeHashingAlgorithms.ComputeArrayTypeHashCode(value.ElementType, value.IsSzArray ? -1 : value.Rank); + } + + protected override bool CompareKeyToValue(ArrayTypeKey key, ArrayType value) + { + if (key._elementType != value.ElementType) + return false; + + if (value.IsSzArray) + return key._rank == -1; + + return key._rank == value.Rank; + } + + protected override bool CompareValueToValue(ArrayType value1, ArrayType value2) + { + return (value1.ElementType == value2.ElementType) && (value1.Rank == value2.Rank) && value1.IsSzArray == value2.IsSzArray; + } + + protected override ArrayType CreateValueFromKey(ArrayTypeKey key) + { + return new ArrayType(key.ElementType, key.Rank); + } + } + } + + private ArrayTypeKey.ArrayTypeKeyHashtable _arrayTypes; + + public ArrayType GetArrayType(TypeDesc elementType, int rank) + { + return _arrayTypes.GetOrCreateValue(new ArrayTypeKey(elementType, rank)); + } + + // + // ByRef types + // + public class ByRefHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(TypeDesc key) + { + return key.GetHashCode(); + } + + protected override int GetValueHashCode(ByRefType value) + { + return value.ParameterType.GetHashCode(); + } + + protected override bool CompareKeyToValue(TypeDesc key, ByRefType value) + { + return key == value.ParameterType; + } + + protected override bool CompareValueToValue(ByRefType value1, ByRefType value2) + { + return value1.ParameterType == value2.ParameterType; + } + + protected override ByRefType CreateValueFromKey(TypeDesc key) + { + return new ByRefType(key); + } + } + + private ByRefHashtable _byRefTypes; + + public ByRefType GetByRefType(TypeDesc parameterType) + { + return _byRefTypes.GetOrCreateValue(parameterType); + } + + // + // Pointer types + // + public class PointerHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(TypeDesc key) + { + return key.GetHashCode(); + } + + protected override int GetValueHashCode(PointerType value) + { + return value.ParameterType.GetHashCode(); + } + + protected override bool CompareKeyToValue(TypeDesc key, PointerType value) + { + return key == value.ParameterType; + } + + protected override bool CompareValueToValue(PointerType value1, PointerType value2) + { + return value1.ParameterType == value2.ParameterType; + } + + protected override PointerType CreateValueFromKey(TypeDesc key) + { + return new PointerType(key); + } + } + + private PointerHashtable _pointerTypes; + + public PointerType GetPointerType(TypeDesc parameterType) + { + return _pointerTypes.GetOrCreateValue(parameterType); + } + + // + // Function pointer types + // + public class FunctionPointerHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(MethodSignature key) + { + return key.GetHashCode(); + } + + protected override int GetValueHashCode(FunctionPointerType value) + { + return value.Signature.GetHashCode(); + } + + protected override bool CompareKeyToValue(MethodSignature key, FunctionPointerType value) + { + return key.Equals(value.Signature); + } + + protected override bool CompareValueToValue(FunctionPointerType value1, FunctionPointerType value2) + { + return value1.Signature.Equals(value2.Signature); + } + + protected override FunctionPointerType CreateValueFromKey(MethodSignature key) + { + return new FunctionPointerType(key); + } + } + + private FunctionPointerHashtable _functionPointerTypes; + + public FunctionPointerType GetFunctionPointerType(MethodSignature signature) + { + return _functionPointerTypes.GetOrCreateValue(signature); + } + + // + // Instantiated types + // + + private struct InstantiatedTypeKey + { + private TypeDesc _typeDef; + private Instantiation _instantiation; + + public InstantiatedTypeKey(TypeDesc typeDef, Instantiation instantiation) + { + _typeDef = typeDef; + _instantiation = instantiation; + } + + public TypeDesc TypeDef + { + get + { + return _typeDef; + } + } + + public Instantiation Instantiation + { + get + { + return _instantiation; + } + } + + public class InstantiatedTypeKeyHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(InstantiatedTypeKey key) + { + return key._instantiation.ComputeGenericInstanceHashCode(key._typeDef.GetHashCode()); + } + + protected override int GetValueHashCode(InstantiatedType value) + { + return value.Instantiation.ComputeGenericInstanceHashCode(value.GetTypeDefinition().GetHashCode()); + } + + protected override bool CompareKeyToValue(InstantiatedTypeKey key, InstantiatedType value) + { + if (key._typeDef != value.GetTypeDefinition()) + return false; + + Instantiation valueInstantiation = value.Instantiation; + + if (key._instantiation.Length != valueInstantiation.Length) + return false; + + for (int i = 0; i < key._instantiation.Length; i++) + { + if (key._instantiation[i] != valueInstantiation[i]) + return false; + } + + return true; + } + + protected override bool CompareValueToValue(InstantiatedType value1, InstantiatedType value2) + { + if (value1.GetTypeDefinition() != value2.GetTypeDefinition()) + return false; + + Instantiation value1Instantiation = value1.Instantiation; + Instantiation value2Instantiation = value2.Instantiation; + + if (value1Instantiation.Length != value2Instantiation.Length) + return false; + + for (int i = 0; i < value1Instantiation.Length; i++) + { + if (value1Instantiation[i] != value2Instantiation[i]) + return false; + } + + return true; + } + + protected override InstantiatedType CreateValueFromKey(InstantiatedTypeKey key) + { + return new InstantiatedType((MetadataType)key.TypeDef, key.Instantiation); + } + } + } + + private InstantiatedTypeKey.InstantiatedTypeKeyHashtable _instantiatedTypes; + + public InstantiatedType GetInstantiatedType(MetadataType typeDef, Instantiation instantiation) + { + return _instantiatedTypes.GetOrCreateValue(new InstantiatedTypeKey(typeDef, instantiation)); + } + + // + // Instantiated methods + // + + private struct InstantiatedMethodKey + { + private MethodDesc _methodDef; + private Instantiation _instantiation; + private int _hashcode; + + public InstantiatedMethodKey(MethodDesc methodDef, Instantiation instantiation) + { + _methodDef = methodDef; + _instantiation = instantiation; + _hashcode = TypeHashingAlgorithms.ComputeMethodHashCode(methodDef.OwningType.GetHashCode(), + instantiation.ComputeGenericInstanceHashCode(TypeHashingAlgorithms.ComputeNameHashCode(methodDef.Name))); + } + + public MethodDesc MethodDef + { + get + { + return _methodDef; + } + } + + public Instantiation Instantiation + { + get + { + return _instantiation; + } + } + + public class InstantiatedMethodKeyHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(InstantiatedMethodKey key) + { + return key._hashcode; + } + + protected override int GetValueHashCode(InstantiatedMethod value) + { + return value.GetHashCode(); + } + + protected override bool CompareKeyToValue(InstantiatedMethodKey key, InstantiatedMethod value) + { + if (key._methodDef != value.GetMethodDefinition()) + return false; + + Instantiation valueInstantiation = value.Instantiation; + + if (key._instantiation.Length != valueInstantiation.Length) + return false; + + for (int i = 0; i < key._instantiation.Length; i++) + { + if (key._instantiation[i] != valueInstantiation[i]) + return false; + } + + return true; + } + + protected override bool CompareValueToValue(InstantiatedMethod value1, InstantiatedMethod value2) + { + if (value1.GetMethodDefinition() != value2.GetMethodDefinition()) + return false; + + Instantiation value1Instantiation = value1.Instantiation; + Instantiation value2Instantiation = value2.Instantiation; + + if (value1Instantiation.Length != value2Instantiation.Length) + return false; + + for (int i = 0; i < value1Instantiation.Length; i++) + { + if (value1Instantiation[i] != value2Instantiation[i]) + return false; + } + + return true; + } + + protected override InstantiatedMethod CreateValueFromKey(InstantiatedMethodKey key) + { + return new InstantiatedMethod(key.MethodDef, key.Instantiation, key._hashcode); + } + } + } + + private InstantiatedMethodKey.InstantiatedMethodKeyHashtable _instantiatedMethods; + + public InstantiatedMethod GetInstantiatedMethod(MethodDesc methodDef, Instantiation instantiation) + { + Debug.Assert(!(methodDef is InstantiatedMethod)); + return _instantiatedMethods.GetOrCreateValue(new InstantiatedMethodKey(methodDef, instantiation)); + } + + // + // Methods for instantiated type + // + + private struct MethodForInstantiatedTypeKey + { + private MethodDesc _typicalMethodDef; + private InstantiatedType _instantiatedType; + private int _hashcode; + + public MethodForInstantiatedTypeKey(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) + { + _typicalMethodDef = typicalMethodDef; + _instantiatedType = instantiatedType; + _hashcode = TypeHashingAlgorithms.ComputeMethodHashCode(instantiatedType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(typicalMethodDef.Name)); + } + + public MethodDesc TypicalMethodDef + { + get + { + return _typicalMethodDef; + } + } + + public InstantiatedType InstantiatedType + { + get + { + return _instantiatedType; + } + } + + public class MethodForInstantiatedTypeKeyHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(MethodForInstantiatedTypeKey key) + { + return key._hashcode; + } + + protected override int GetValueHashCode(MethodForInstantiatedType value) + { + return value.GetHashCode(); + } + + protected override bool CompareKeyToValue(MethodForInstantiatedTypeKey key, MethodForInstantiatedType value) + { + if (key._typicalMethodDef != value.GetTypicalMethodDefinition()) + return false; + + return key._instantiatedType == value.OwningType; + } + + protected override bool CompareValueToValue(MethodForInstantiatedType value1, MethodForInstantiatedType value2) + { + return (value1.GetTypicalMethodDefinition() == value2.GetTypicalMethodDefinition()) && (value1.OwningType == value2.OwningType); + } + + protected override MethodForInstantiatedType CreateValueFromKey(MethodForInstantiatedTypeKey key) + { + return new MethodForInstantiatedType(key.TypicalMethodDef, key.InstantiatedType, key._hashcode); + } + } + } + + private MethodForInstantiatedTypeKey.MethodForInstantiatedTypeKeyHashtable _methodForInstantiatedTypes; + + public MethodDesc GetMethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) + { + Debug.Assert(!(typicalMethodDef is MethodForInstantiatedType)); + Debug.Assert(!(typicalMethodDef is InstantiatedMethod)); + + return _methodForInstantiatedTypes.GetOrCreateValue(new MethodForInstantiatedTypeKey(typicalMethodDef, instantiatedType)); + } + + // + // Fields for instantiated type + // + + private struct FieldForInstantiatedTypeKey + { + private FieldDesc _fieldDef; + private InstantiatedType _instantiatedType; + + public FieldForInstantiatedTypeKey(FieldDesc fieldDef, InstantiatedType instantiatedType) + { + _fieldDef = fieldDef; + _instantiatedType = instantiatedType; + } + + public FieldDesc TypicalFieldDef + { + get + { + return _fieldDef; + } + } + + public InstantiatedType InstantiatedType + { + get + { + return _instantiatedType; + } + } + + public class FieldForInstantiatedTypeKeyHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(FieldForInstantiatedTypeKey key) + { + return key._fieldDef.GetHashCode() ^ key._instantiatedType.GetHashCode(); + } + + protected override int GetValueHashCode(FieldForInstantiatedType value) + { + return value.GetTypicalFieldDefinition().GetHashCode() ^ value.OwningType.GetHashCode(); + } + + protected override bool CompareKeyToValue(FieldForInstantiatedTypeKey key, FieldForInstantiatedType value) + { + if (key._fieldDef != value.GetTypicalFieldDefinition()) + return false; + + return key._instantiatedType == value.OwningType; + } + + protected override bool CompareValueToValue(FieldForInstantiatedType value1, FieldForInstantiatedType value2) + { + return (value1.GetTypicalFieldDefinition() == value2.GetTypicalFieldDefinition()) && (value1.OwningType == value2.OwningType); + } + + protected override FieldForInstantiatedType CreateValueFromKey(FieldForInstantiatedTypeKey key) + { + return new FieldForInstantiatedType(key.TypicalFieldDef, key.InstantiatedType); + } + } + } + + private FieldForInstantiatedTypeKey.FieldForInstantiatedTypeKeyHashtable _fieldForInstantiatedTypes; + + public FieldDesc GetFieldForInstantiatedType(FieldDesc fieldDef, InstantiatedType instantiatedType) + { + return _fieldForInstantiatedTypes.GetOrCreateValue(new FieldForInstantiatedTypeKey(fieldDef, instantiatedType)); + } + + // + // Signature variables + // + private class SignatureVariableHashtable : LockFreeReaderHashtable + { + private TypeSystemContext _context; + public SignatureVariableHashtable(TypeSystemContext context) + { + _context = context; + } + + protected override int GetKeyHashCode(uint key) + { + return (int)key; + } + + protected override int GetValueHashCode(SignatureVariable value) + { + uint combinedIndex = value.IsMethodSignatureVariable ? ((uint)value.Index | 0x80000000) : (uint)value.Index; + return (int)combinedIndex; + } + + protected override bool CompareKeyToValue(uint key, SignatureVariable value) + { + uint combinedIndex = value.IsMethodSignatureVariable ? ((uint)value.Index | 0x80000000) : (uint)value.Index; + return key == combinedIndex; + } + + protected override bool CompareValueToValue(SignatureVariable value1, SignatureVariable value2) + { + uint combinedIndex1 = value1.IsMethodSignatureVariable ? ((uint)value1.Index | 0x80000000) : (uint)value1.Index; + uint combinedIndex2 = value2.IsMethodSignatureVariable ? ((uint)value2.Index | 0x80000000) : (uint)value2.Index; + + return combinedIndex1 == combinedIndex2; + } + + protected override SignatureVariable CreateValueFromKey(uint key) + { + bool method = ((key & 0x80000000) != 0); + int index = (int)(key & 0x7FFFFFFF); + if (method) + return new SignatureMethodVariable(_context, index); + else + return new SignatureTypeVariable(_context, index); + } + } + + private SignatureVariableHashtable _signatureVariables; + + public TypeDesc GetSignatureVariable(int index, bool method) + { + if (index < 0) + throw new BadImageFormatException(); + + uint combinedIndex = method ? ((uint)index | 0x80000000) : (uint)index; + return _signatureVariables.GetOrCreateValue(combinedIndex); + } + + protected internal virtual IEnumerable GetAllMethods(TypeDesc type) + { + return type.GetMethods(); + } + + /// + /// Abstraction to allow the type system context to affect the field layout + /// algorithm used by types to lay themselves out. + /// + public virtual FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) + { + // Type system contexts that support computing field layout need to override this. + throw new NotSupportedException(); + } + + /// + /// Abstraction to allow the type system context to control the interfaces + /// algorithm used by types. + /// + public RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForType(TypeDesc type) + { + if (type.IsDefType) + { + return GetRuntimeInterfacesAlgorithmForDefType((DefType)type); + } + else if (type.IsArray) + { + ArrayType arrType = (ArrayType)type; + TypeDesc elementType = arrType.ElementType; + if (arrType.IsSzArray && !elementType.IsPointer && !elementType.IsFunctionPointer) + { + return GetRuntimeInterfacesAlgorithmForNonPointerArrayType((ArrayType)type); + } + else + { + return BaseTypeRuntimeInterfacesAlgorithm.Instance; + } + } + + return null; + } + + /// + /// Abstraction to allow the type system context to control the interfaces + /// algorithm used by types. + /// + protected virtual RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) + { + // Type system contexts that support computing runtime interfaces need to override this. + throw new NotSupportedException(); + } + + /// + /// Abstraction to allow the type system context to control the interfaces + /// algorithm used by single dimensional array types. + /// + protected virtual RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) + { + // Type system contexts that support computing runtime interfaces need to override this. + throw new NotSupportedException(); + } + + public virtual VirtualMethodAlgorithm GetVirtualMethodAlgorithmForType(TypeDesc type) + { + // Type system contexts that support virtual method resolution need to override this. + throw new NotSupportedException(); + } + + // Abstraction to allow different runtimes to have different policy about which fields are + // in the GC static region, and which are not + protected internal virtual bool ComputeHasGCStaticBase(FieldDesc field) + { + // Type system contexts that support this need to override this. + throw new NotSupportedException(); + } + + /// + /// TypeSystemContext controlled type flags computation. This allows computation of flags which depend + /// on the particular TypeSystemContext in use + /// + internal TypeFlags ComputeTypeFlags(TypeDesc type, TypeFlags flags, TypeFlags mask) + { + // If we are looking to compute HasStaticConstructor, and we haven't yet assigned a value + if ((mask & TypeFlags.HasStaticConstructorComputed) == TypeFlags.HasStaticConstructorComputed) + { + TypeDesc typeDefinition = type.GetTypeDefinition(); + + if (typeDefinition != type) + { + // If the type definition is different, the code was working with an instantiated generic or some such. + // In that case, just query the HasStaticConstructor property, as it can cache the answer + if (typeDefinition.HasStaticConstructor) + flags |= TypeFlags.HasStaticConstructor; + } + else + { + if (ComputeHasStaticConstructor(typeDefinition)) + { + flags |= TypeFlags.HasStaticConstructor; + } + } + + flags |= TypeFlags.HasStaticConstructorComputed; + } + + return flags; + } + + /// + /// Algorithm to control which types are considered to have static constructors + /// + protected internal abstract bool ComputeHasStaticConstructor(TypeDesc type); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemEntity.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemEntity.cs new file mode 100644 index 00000000000..ad3d3739d16 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemEntity.cs @@ -0,0 +1,14 @@ +// 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 +{ + public abstract class TypeSystemEntity + { + /// + /// Gets the type system context this entity belongs to. + /// + public abstract TypeSystemContext Context { get; } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemException.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemException.cs new file mode 100644 index 00000000000..afe5ebf7bbb --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemException.cs @@ -0,0 +1,147 @@ +// 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.Collections.Generic; + +namespace Internal.TypeSystem +{ + /// + /// Base type for all type system exceptions. + /// + public abstract class TypeSystemException : Exception + { + private string[] _arguments; + + /// + /// Gets the resource string identifier. + /// + public ExceptionStringID StringID { get; } + + /// + /// Gets the formatting arguments for the exception string. + /// + public IReadOnlyList Arguments + { + get + { + return _arguments; + } + } + + public override string Message + { + get + { + return GetExceptionString(StringID, _arguments); + } + } + + internal TypeSystemException(ExceptionStringID id, params string[] args) + { + StringID = id; + _arguments = args; + } + + private static string GetExceptionString(ExceptionStringID id, string[] args) + { + // TODO: Share the strings and lookup logic with System.Private.CoreLib. + return "[TEMPORARY EXCEPTION MESSAGE] " + id.ToString() + ": " + String.Join(", ", args); + } + + /// + /// The exception that is thrown when type-loading failures occur. + /// + public class TypeLoadException : TypeSystemException + { + public string TypeName { get; } + + public string AssemblyName { get; } + + internal TypeLoadException(ExceptionStringID id, string typeName, string assemblyName, string messageArg) + : base(id, new string[] { typeName, assemblyName, messageArg }) + { + TypeName = typeName; + AssemblyName = assemblyName; + } + + internal TypeLoadException(ExceptionStringID id, string typeName, string assemblyName) + : base(id, new string[] { typeName, assemblyName }) + { + TypeName = typeName; + AssemblyName = assemblyName; + } + } + + /// + /// The exception that is thrown when there is an attempt to access a class member that does not exist + /// or that is not declared as public. + /// + public abstract class MissingMemberException : TypeSystemException + { + protected internal MissingMemberException(ExceptionStringID id, params string[] args) + : base(id, args) + { + } + } + + /// + /// The exception that is thrown when there is an attempt to access a method that does not exist. + /// + public class MissingMethodException : MissingMemberException + { + internal MissingMethodException(ExceptionStringID id, params string[] args) + : base(id, args) + { + } + } + + /// + /// The exception that is thrown when there is an attempt to access a field that does not exist. + /// + public class MissingFieldException : MissingMemberException + { + internal MissingFieldException(ExceptionStringID id, params string[] args) + : base(id, args) + { + } + } + + /// + /// The exception that is thrown when an attempt to access a file that does not exist on disk fails. + /// + public class FileNotFoundException : TypeSystemException + { + internal FileNotFoundException(ExceptionStringID id, string fileName) + : base(id, fileName) + { + } + } + + /// + /// The exception that is thrown when a program contains invalid Microsoft intermediate language (MSIL) or metadata. + /// Generally this indicates a bug in the compiler that generated the program. + /// + public class InvalidProgramException : TypeSystemException + { + internal InvalidProgramException(ExceptionStringID id, string method) + : base(id, method) + { + } + + internal InvalidProgramException() + : base(ExceptionStringID.InvalidProgramDefault) + { + } + } + + public class BadImageFormatException : TypeSystemException + { + internal BadImageFormatException() + : base(ExceptionStringID.BadImageFormatGeneric) + { + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemHelpers.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemHelpers.cs new file mode 100644 index 00000000000..e76f5e30870 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemHelpers.cs @@ -0,0 +1,415 @@ +// 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.Collections.Generic; +using System.Diagnostics; + +namespace Internal.TypeSystem +{ + public static class TypeSystemHelpers + { + public static bool IsWellKnownType(this TypeDesc type, WellKnownType wellKnownType) + { + return type == type.Context.GetWellKnownType(wellKnownType, false); + } + + public static InstantiatedType MakeInstantiatedType(this MetadataType typeDef, Instantiation instantiation) + { + return typeDef.Context.GetInstantiatedType(typeDef, instantiation); + } + + public static InstantiatedType MakeInstantiatedType(this MetadataType typeDef, params TypeDesc[] genericParameters) + { + return typeDef.Context.GetInstantiatedType(typeDef, new Instantiation(genericParameters)); + } + + + public static InstantiatedMethod MakeInstantiatedMethod(this MethodDesc methodDef, Instantiation instantiation) + { + return methodDef.Context.GetInstantiatedMethod(methodDef, instantiation); + } + + public static InstantiatedMethod MakeInstantiatedMethod(this MethodDesc methodDef, params TypeDesc[] genericParameters) + { + return methodDef.Context.GetInstantiatedMethod(methodDef, new Instantiation(genericParameters)); + } + + public static ArrayType MakeArrayType(this TypeDesc type) + { + return type.Context.GetArrayType(type); + } + + /// + /// Creates a multidimensional array type with the specified rank. + /// To create a vector, use the overload. + /// + public static ArrayType MakeArrayType(this TypeDesc type, int rank) + { + return type.Context.GetArrayType(type, rank); + } + + public static ByRefType MakeByRefType(this TypeDesc type) + { + return type.Context.GetByRefType(type); + } + + public static PointerType MakePointerType(this TypeDesc type) + { + return type.Context.GetPointerType(type); + } + + public static TypeDesc GetParameterType(this TypeDesc type) + { + ParameterizedType paramType = (ParameterizedType) type; + return paramType.ParameterType; + } + + public static bool HasLayout(this MetadataType mdType) + { + return mdType.IsSequentialLayout || mdType.IsExplicitLayout; + } + + public static LayoutInt GetElementSize(this TypeDesc type) + { + if (type.IsValueType) + { + return ((DefType)type).InstanceFieldSize; + } + else + { + return type.Context.Target.LayoutPointerSize; + } + } + + /// + /// Gets the parameterless instance constructor on the specified type. To get the default constructor, use . + /// + public static MethodDesc GetParameterlessConstructor(this TypeDesc type) + { + // TODO: Do we want check for specialname/rtspecialname? Maybe add another overload on GetMethod? + var sig = new MethodSignature(0, 0, type.Context.GetWellKnownType(WellKnownType.Void), TypeDesc.EmptyTypes); + return type.GetMethod(".ctor", sig); + } + + public static bool HasExplicitOrImplicitDefaultConstructor(this TypeDesc type) + { + return type.IsValueType || type.GetDefaultConstructor() != null; + } + + internal static MethodDesc FindMethodOnExactTypeWithMatchingTypicalMethod(this TypeDesc type, MethodDesc method) + { + MethodDesc methodTypicalDefinition = method.GetTypicalMethodDefinition(); + + var instantiatedType = type as InstantiatedType; + if (instantiatedType != null) + { + Debug.Assert(instantiatedType.GetTypeDefinition() == methodTypicalDefinition.OwningType); + return method.Context.GetMethodForInstantiatedType(methodTypicalDefinition, instantiatedType); + } + else if (type.IsArray) + { + Debug.Assert(method.OwningType.IsArray); + return ((ArrayType)type).GetArrayMethod(((ArrayMethod)method).Kind); + } + else + { + Debug.Assert(type == methodTypicalDefinition.OwningType); + return methodTypicalDefinition; + } + } + + /// + /// Returns method as defined on a non-generic base class or on a base + /// instantiation. + /// For example, If Foo<T> : Bar<T> and overrides method M, + /// if method is Bar<string>.M(), then this returns Bar<T>.M() + /// but if Foo : Bar<string>, then this returns Bar<string>.M() + /// + /// A potentially derived type + /// A base class's virtual method + public static MethodDesc FindMethodOnTypeWithMatchingTypicalMethod(this TypeDesc targetType, MethodDesc method) + { + // If method is nongeneric and on a nongeneric type, then it is the matching method + if (!method.HasInstantiation && !method.OwningType.HasInstantiation) + { + return method; + } + + // Since method is an instantiation that may or may not be the same as typeExamine's hierarchy, + // find a matching base class on an open type and then work from the instantiation in typeExamine's + // hierarchy + TypeDesc typicalTypeOfTargetMethod = method.GetTypicalMethodDefinition().OwningType; + TypeDesc targetOrBase = targetType; + do + { + TypeDesc openTargetOrBase = targetOrBase; + if (openTargetOrBase is InstantiatedType) + { + openTargetOrBase = openTargetOrBase.GetTypeDefinition(); + } + if (openTargetOrBase == typicalTypeOfTargetMethod) + { + // Found an open match. Now find an equivalent method on the original target typeOrBase + MethodDesc matchingMethod = targetOrBase.FindMethodOnExactTypeWithMatchingTypicalMethod(method); + return matchingMethod; + } + targetOrBase = targetOrBase.BaseType; + } while (targetOrBase != null); + + Debug.Fail("method has no related type in the type hierarchy of type"); + return null; + } + + /// + /// Attempts to resolve constrained call to into a concrete non-unboxing + /// method on . + /// The ability to resolve constraint methods is affected by the degree of code sharing we are performing + /// for generic code. + /// + /// The resolved method or null if the constraint couldn't be resolved. + public static MethodDesc TryResolveConstraintMethodApprox(this TypeDesc constrainedType, TypeDesc interfaceType, MethodDesc interfaceMethod, out bool forceRuntimeLookup) + { + forceRuntimeLookup = false; + + // We can't resolve constraint calls effectively for reference types, and there's + // not a lot of perf. benefit in doing it anyway. + if (!constrainedType.IsValueType) + { + return null; + } + + // Non-virtual methods called through constraints simply resolve to the specified method without constraint resolution. + if (!interfaceMethod.IsVirtual) + { + return null; + } + + MethodDesc method; + + MethodDesc genInterfaceMethod = interfaceMethod.GetMethodDefinition(); + if (genInterfaceMethod.OwningType.IsInterface) + { + // Sometimes (when compiling shared generic code) + // we don't have enough exact type information at JIT time + // even to decide whether we will be able to resolve to an unboxed entry point... + // To cope with this case we always go via the helper function if there's any + // chance of this happening by checking for all interfaces which might possibly + // be compatible with the call (verification will have ensured that + // at least one of them will be) + + // Enumerate all potential interface instantiations + + // TODO: this code assumes no shared generics + Debug.Assert(interfaceType == interfaceMethod.OwningType); + + method = constrainedType.ResolveInterfaceMethodToVirtualMethodOnType(genInterfaceMethod); + } + else if (genInterfaceMethod.IsVirtual) + { + method = constrainedType.FindVirtualFunctionTargetMethodOnObjectType(genInterfaceMethod); + } + else + { + // The method will be null if calling a non-virtual instance + // methods on System.Object, i.e. when these are used as a constraint. + method = null; + } + + if (method == null) + { + // Fall back to VSD + return null; + } + + //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod + // Only return a method if the value type itself declares the method, + // otherwise we might get a method from Object or System.ValueType + if (!method.OwningType.IsValueType) + { + // Fall back to VSD + return null; + } + + // We've resolved the method, ignoring its generic method arguments + // If the method is a generic method then go and get the instantiated descriptor + if (interfaceMethod.HasInstantiation) + { + method = method.MakeInstantiatedMethod(interfaceMethod.Instantiation); + } + + Debug.Assert(method != null); + //assert(!pMD->IsUnboxingStub()); + + return method; + } + + /// + /// Retrieves the namespace qualified name of a . + /// + public static string GetFullName(this DefType metadataType) + { + string ns = metadataType.Namespace; + return ns.Length > 0 ? String.Concat(ns, ".", metadataType.Name) : metadataType.Name; + } + + /// + /// Retrieves all methods on a type, including the ones injected by the type system context. + /// + public static IEnumerable GetAllMethods(this TypeDesc type) + { + return type.Context.GetAllMethods(type); + } + + public static IEnumerable EnumAllVirtualSlots(this TypeDesc type) + { + return type.Context.GetVirtualMethodAlgorithmForType(type).ComputeAllVirtualSlots(type); + } + + /// + /// Resolves interface method '' to a method on '' + /// that implements the the method. + /// + public static MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(this TypeDesc type, MethodDesc interfaceMethod) + { + return type.Context.GetVirtualMethodAlgorithmForType(type).ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, type); + } + + public static MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(this TypeDesc type, MethodDesc interfaceMethod) + { + return type.Context.GetVirtualMethodAlgorithmForType(type).ResolveVariantInterfaceMethodToVirtualMethodOnType(interfaceMethod, type); + } + + /// + /// Resolves a virtual method call. + /// + public static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(this TypeDesc type, MethodDesc targetMethod) + { + return type.Context.GetVirtualMethodAlgorithmForType(type).FindVirtualFunctionTargetMethodOnObjectType(targetMethod, type); + } + + /// + /// Creates an open instantiation of a type. Given Foo<T>, returns Foo<!0>. + /// If the type is not generic, returns the . + /// + public static TypeDesc InstantiateAsOpen(this TypeDesc type) + { + if (!type.IsGenericDefinition) + { + Debug.Assert(!type.HasInstantiation); + return type; + } + + TypeSystemContext context = type.Context; + + var inst = new TypeDesc[type.Instantiation.Length]; + for (int i = 0; i < inst.Length; i++) + { + inst[i] = context.GetSignatureVariable(i, false); + } + + return context.GetInstantiatedType((MetadataType)type, new Instantiation(inst)); + } + + /// + /// Creates an open instantiation of a field. Given Foo<T>.Field, returns + /// Foo<!0>.Field. If the owning type is not generic, returns the . + /// + public static FieldDesc InstantiateAsOpen(this FieldDesc field) + { + Debug.Assert(field.GetTypicalFieldDefinition() == field); + + TypeDesc owner = field.OwningType; + + if (owner.HasInstantiation) + { + var instantiatedOwner = (InstantiatedType)owner.InstantiateAsOpen(); + return field.Context.GetFieldForInstantiatedType(field, instantiatedOwner); + } + + return field; + } + + /// + /// Creates an open instantiation of a method. Given Foo<T>.Method, returns + /// Foo<!0>.Method. If the owning type is not generic, returns the . + /// + public static MethodDesc InstantiateAsOpen(this MethodDesc method) + { + Debug.Assert(method.IsMethodDefinition && !method.HasInstantiation); + + TypeDesc owner = method.OwningType; + + if (owner.HasInstantiation) + { + MetadataType instantiatedOwner = (MetadataType)owner.InstantiateAsOpen(); + return method.Context.GetMethodForInstantiatedType(method, (InstantiatedType)instantiatedOwner); + } + + return method; + } + + /// + /// Scan the type and its base types for an implementation of an interface method. Returns null if no + /// implementation is found. + /// + public static MethodDesc ResolveInterfaceMethodTarget(this TypeDesc thisType, MethodDesc interfaceMethodToResolve) + { + Debug.Assert(interfaceMethodToResolve.OwningType.IsInterface); + + MethodDesc result = null; + TypeDesc currentType = thisType; + do + { + result = currentType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethodToResolve); + currentType = currentType.BaseType; + } + while (result == null && currentType != null); + + return result; + } + + public static bool ContainsSignatureVariables(this TypeDesc thisType) + { + switch (thisType.Category) + { + case TypeFlags.Array: + case TypeFlags.SzArray: + case TypeFlags.ByRef: + case TypeFlags.Pointer: + return ((ParameterizedType)thisType).ParameterType.ContainsSignatureVariables(); + + case TypeFlags.FunctionPointer: + + var fptr = (FunctionPointerType)thisType; + if (fptr.Signature.ReturnType.ContainsSignatureVariables()) + return true; + + for (int i = 0; i < fptr.Signature.Length; i++) + { + if (fptr.Signature[i].ContainsSignatureVariables()) + return true; + } + return false; + + case TypeFlags.SignatureMethodVariable: + case TypeFlags.SignatureTypeVariable: + return true; + + case TypeFlags.GenericParameter: + throw new ArgumentException(); + + default: + Debug.Assert(thisType is DefType); + foreach (TypeDesc arg in thisType.Instantiation) + { + if (arg.ContainsSignatureVariables()) + return true; + } + + return false; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameFormatter.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameFormatter.cs new file mode 100644 index 00000000000..864a7b3220c --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameFormatter.cs @@ -0,0 +1,187 @@ +// 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.Text; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Formats type names in the 'SerString' format as defined by the ECMA-335 standard. + /// This is the inverse of what does. + /// + public sealed class CustomAttributeTypeNameFormatter : TypeNameFormatter + { + private readonly IAssemblyDesc _relativeHomeAssembly; + + public CustomAttributeTypeNameFormatter() + { + } + + public CustomAttributeTypeNameFormatter(IAssemblyDesc relativeHomeAssembly) + { + _relativeHomeAssembly = relativeHomeAssembly; + } + + private void AppendAssemblyName(StringBuilder sb, IAssemblyDesc assembly) + { + if (assembly == _relativeHomeAssembly || assembly == null) + return; + + sb.Append(','); + AppendEscapedIdentifier(sb, assembly.GetName().Name); + } + + public override IAssemblyDesc AppendName(StringBuilder sb, ArrayType type, bool assemblyQualify) + { + IAssemblyDesc homeAssembly = AppendName(sb, type.ElementType, false); + + if (type.IsSzArray) + { + sb.Append("[]"); + } + else if (type.Rank == 1) + { + sb.Append("[*]"); + } + else + { + sb.Append('['); + sb.Append(',', type.Rank - 1); + sb.Append(']'); + } + + if (assemblyQualify) + AppendAssemblyName(sb, homeAssembly); + + return homeAssembly; + } + + public override IAssemblyDesc AppendName(StringBuilder sb, ByRefType type, bool assemblyQualify) + { + IAssemblyDesc homeAssembly = AppendName(sb, type.ParameterType, false); + + sb.Append('&'); + + if (assemblyQualify) + AppendAssemblyName(sb, homeAssembly); + + return homeAssembly; + } + + public override IAssemblyDesc AppendName(StringBuilder sb, PointerType type, bool assemblyQualify) + { + IAssemblyDesc homeAssembly = AppendName(sb, type.ParameterType, false); + + sb.Append('*'); + + if (assemblyQualify) + AppendAssemblyName(sb, homeAssembly); + + return homeAssembly; + } + + public override IAssemblyDesc AppendName(StringBuilder sb, FunctionPointerType type, bool assemblyQualify) + { + throw new NotSupportedException(); + } + + public override IAssemblyDesc AppendName(StringBuilder sb, GenericParameterDesc type, bool assemblyQualify) + { + throw new NotSupportedException(); + } + + public override IAssemblyDesc AppendName(StringBuilder sb, SignatureMethodVariable type, bool assemblyQualify) + { + throw new NotSupportedException(); + } + + public override IAssemblyDesc AppendName(StringBuilder sb, SignatureTypeVariable type, bool assemblyQualify) + { + throw new NotSupportedException(); + } + + protected override IAssemblyDesc AppendNameForInstantiatedType(StringBuilder sb, DefType type, bool assemblyQualify) + { + IAssemblyDesc homeAssembly = AppendName(sb, type.GetTypeDefinition(), false); + + sb.Append('['); + + for (int i = 0; i < type.Instantiation.Length; i++) + { + if (i != 0) + sb.Append(','); + + sb.Append('['); + AppendName(sb, type.Instantiation[i], true); + sb.Append(']'); + } + + sb.Append(']'); + + if (assemblyQualify) + AppendAssemblyName(sb, homeAssembly); + + return homeAssembly; + } + + protected override IAssemblyDesc AppendNameForNamespaceType(StringBuilder sb, DefType type, bool assemblyQualify) + { + string ns = type.Namespace; + if (ns.Length > 0) + { + AppendEscapedIdentifier(sb, ns); + sb.Append('.'); + } + AppendEscapedIdentifier(sb, type.Name); + + if (type is MetadataType mdType) + { + Debug.Assert(mdType.Module is IAssemblyDesc, "Multi-module?"); + + if (assemblyQualify) + AppendAssemblyName(sb, (IAssemblyDesc)mdType.Module); + + return (IAssemblyDesc)mdType.Module; + } + + return null; + } + + protected override IAssemblyDesc AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType, bool assemblyQualify) + { + IAssemblyDesc homeAssembly = AppendName(sb, containingType, false); + + sb.Append('+'); + + AppendEscapedIdentifier(sb, nestedType.Name); + + if (assemblyQualify) + AppendAssemblyName(sb, homeAssembly); + + return homeAssembly; + } + + private static char[] s_escapedChars = new char[] { ',', '=', '"', ']', '[', '*', '&', '+', '\\' }; + private void AppendEscapedIdentifier(StringBuilder sb, string identifier) + { + if (identifier.IndexOfAny(s_escapedChars) < 0) + { + string escapedIdentifier = identifier; + foreach (char escapedChar in s_escapedChars) + { + string escapedCharString = new string(escapedChar, 1); + escapedIdentifier = escapedIdentifier.Replace(escapedCharString, "\\" + escapedCharString); + } + sb.Append(escapedIdentifier); + } + else + { + sb.Append(identifier); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs new file mode 100644 index 00000000000..1bea19a91a5 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs @@ -0,0 +1,453 @@ +// 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.Collections.Generic; +using System.Text; + +using AssemblyName = System.Reflection.AssemblyName; +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // TODO: This file is pretty much a line-by-line port of C++ code to parse CA type name strings from NUTC. + // It's a stopgap solution. + // This should be replaced with type name parser in System.Reflection.Metadata once it starts shipping. + + public static class CustomAttributeTypeNameParser + { + /// + /// Parses the string '' and returns the type corresponding to the parsed type name. + /// The type name string should be in the 'SerString' format as defined by the ECMA-335 standard. + /// This is the inverse of what does. + /// + public static TypeDesc GetTypeByCustomAttributeTypeName(this ModuleDesc module, string name, bool throwIfNotFound = true, Func resolver = null) + { + TypeDesc loadedType; + + StringBuilder genericTypeDefName = new StringBuilder(name.Length); + + var ch = name.Begin(); + var nameEnd = name.End(); + + for (; ch < nameEnd; ++ch) + { + // Always pass escaped characters through. + if (ch.Current == '\\') + { + genericTypeDefName.Append(ch.Current); + ++ch; + if (ch < nameEnd) + { + genericTypeDefName.Append(ch.Current); + } + continue; + } + + // The type def name ends if + + // The start of a generic argument list + if (ch.Current == '[') + break; + + // Indication that the type is a pointer + if (ch.Current == '*') + break; + + // Indication that the type is a reference + if (ch.Current == '&') + break; + + // A comma that indicates that the rest of the name is an assembly reference + if (ch.Current == ',') + break; + + genericTypeDefName.Append(ch.Current); + } + + ModuleDesc homeModule = module; + AssemblyName homeAssembly = FindAssemblyIfNamePresent(name); + if (homeAssembly != null) + { + homeModule = module.Context.ResolveAssembly(homeAssembly); + } + MetadataType typeDef = resolver != null ? resolver(genericTypeDefName.ToString(), homeModule, throwIfNotFound) : + ResolveCustomAttributeTypeDefinitionName(genericTypeDefName.ToString(), homeModule, throwIfNotFound); + if (typeDef == null) + return null; + + ArrayBuilder genericArgs = new ArrayBuilder(); + + // Followed by generic instantiation parameters (but check for the array case) + if (ch < nameEnd && ch.Current == '[' && (ch + 1) < nameEnd && (ch + 1).Current != ']' && (ch + 1).Current != ',') + { + ch++; // truncate the '[' + var genericInstantiationEnd = ch + ReadTypeArgument(ch, nameEnd, true); // find the end of the instantiation list + while (ch < genericInstantiationEnd) + { + if (ch.Current == ',') + ch++; + + int argLen = ReadTypeArgument(ch, name.End(), false); + string typeArgName; + if (ch.Current == '[') + { + // This type argument name is stringified, + // we need to remove the [] from around it + ch++; + typeArgName = StringIterator.Substring(ch, ch + (argLen - 2)); + ch += argLen - 1; + } + else + { + typeArgName = StringIterator.Substring(ch, ch + argLen); + ch += argLen; + } + + TypeDesc argType = module.GetTypeByCustomAttributeTypeName(typeArgName, throwIfNotFound, resolver); + if (argType == null) + return null; + genericArgs.Add(argType); + } + + Debug.Assert(ch == genericInstantiationEnd); + ch++; + + loadedType = typeDef.MakeInstantiatedType(genericArgs.ToArray()); + } + else + { + // Non-generic type + loadedType = typeDef; + } + + // At this point the characters following may be any number of * characters to indicate pointer depth + while (ch < nameEnd) + { + if (ch.Current == '*') + { + loadedType = loadedType.MakePointerType(); + } + else + { + break; + } + ch++; + } + + // Followed by any number of "[]" or "[,*]" pairs to indicate arrays + int commasSeen = 0; + bool bracketSeen = false; + while (ch < nameEnd) + { + if (ch.Current == '[') + { + ch++; + commasSeen = 0; + bracketSeen = true; + } + else if (ch.Current == ']') + { + if (!bracketSeen) + break; + + ch++; + if (commasSeen == 0) + { + loadedType = loadedType.MakeArrayType(); + } + else + { + loadedType = loadedType.MakeArrayType(commasSeen + 1); + } + + bracketSeen = false; + } + else if (ch.Current == ',') + { + if (!bracketSeen) + break; + ch++; + commasSeen++; + } + else + { + break; + } + } + + // Followed by at most one & character to indicate a byref. + if (ch < nameEnd) + { + if (ch.Current == '&') + { + loadedType = loadedType.MakeByRefType(); + ch++; + } + } + + return loadedType; + } + + + public static MetadataType ResolveCustomAttributeTypeDefinitionName(string name, ModuleDesc module, bool throwIfNotFound) + { + MetadataType containingType = null; + StringBuilder typeName = new StringBuilder(name.Length); + bool escaped = false; + for (var c = name.Begin(); c < name.End(); c++) + { + if (c.Current == '\\' && !escaped) + { + escaped = true; + continue; + } + + if (escaped) + { + escaped = false; + typeName.Append(c.Current); + continue; + } + + if (c.Current == ',') + { + break; + } + + if (c.Current == '[' || c.Current == '*' || c.Current == '&') + { + break; + } + + if (c.Current == '+') + { + if (containingType != null) + { + MetadataType outerType = containingType; + containingType = outerType.GetNestedType(typeName.ToString()); + if (containingType == null) + { + if (throwIfNotFound) + ThrowHelper.ThrowTypeLoadException(typeName.ToString(), outerType.Module); + + return null; + } + } + else + { + containingType = module.GetType(typeName.ToString(), throwIfNotFound); + if (containingType == null) + return null; + } + typeName.Length = 0; + continue; + } + + typeName.Append(c.Current); + } + + if (containingType != null) + { + MetadataType type = containingType.GetNestedType(typeName.ToString()); + if ((type == null) && throwIfNotFound) + ThrowHelper.ThrowTypeLoadException(typeName.ToString(), containingType.Module); + + return type; + } + + return module.GetType(typeName.ToString(), throwIfNotFound); + } + + private static MetadataType GetType(this ModuleDesc module, string fullName, bool throwIfNotFound = true) + { + string namespaceName; + string typeName; + int split = fullName.LastIndexOf('.'); + if (split < 0) + { + namespaceName = ""; + typeName = fullName; + } + else + { + namespaceName = fullName.Substring(0, split); + typeName = fullName.Substring(split + 1); + } + return module.GetType(namespaceName, typeName, throwIfNotFound); + } + + private static AssemblyName FindAssemblyIfNamePresent(string name) + { + AssemblyName result = null; + var endOfType = name.Begin() + ReadTypeArgument(name.Begin(), name.End(), false); + if (endOfType < name.End() && endOfType.Current == ',') + { + // There is an assembly name here + int foundCommas = 0; + var endOfAssemblyName = endOfType; + for (var ch = endOfType + 1; ch < name.End(); ch++) + { + if (foundCommas == 3) + { + // We're now eating the public key token, looking for the end of the name, + // or a right bracket + if (ch.Current == ']' || ch.Current == ',') + { + endOfAssemblyName = ch - 1; + break; + } + } + + if (ch.Current == ',') + { + foundCommas++; + } + } + if (endOfAssemblyName == endOfType) + { + endOfAssemblyName = name.End(); + } + + // eat the comma + endOfType++; + for (; endOfType < endOfAssemblyName; ++endOfType) + { + // trim off spaces + if (endOfType.Current != ' ') + break; + } + result = new AssemblyName(StringIterator.Substring(endOfType, endOfAssemblyName)); + } + return result; + } + + private static int ReadTypeArgument(StringIterator strBegin, StringIterator strEnd, bool ignoreComma) + { + int level = 0; + int length = 0; + for (var c = strBegin; c < strEnd; c++) + { + if (c.Current == '\\') + { + length++; + if ((c + 1) < strEnd) + { + c++; + length++; + } + continue; + } + if (c.Current == '[') + { + level++; + } + else if (c.Current == ']') + { + if (level == 0) + break; + level--; + } + else if (!ignoreComma && (c.Current == ',')) + { + if (level == 0) + break; + } + + length++; + } + + return length; + } + + #region C++ string iterator compatibility shim + + private static StringIterator Begin(this string s) + { + return new StringIterator(s, 0); + } + + private static StringIterator End(this string s) + { + return new StringIterator(s, s.Length); + } + + struct StringIterator + { + private string _string; + private int _index; + + public char Current + { + get + { + return _string[_index]; + } + } + + public StringIterator(string s, int index) + { + Debug.Assert(index <= s.Length); + _string = s; + _index = index; + } + + public static string Substring(StringIterator it1, StringIterator it2) + { + Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); + return it1._string.Substring(it1._index, it2._index - it1._index); + } + + public static StringIterator operator++(StringIterator it) + { + return new StringIterator(it._string, ++it._index); + } + + public static bool operator <(StringIterator it1, StringIterator it2) + { + Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); + return it1._index < it2._index; + } + + public static bool operator >(StringIterator it1, StringIterator it2) + { + Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); + return it1._index > it2._index; + } + + public static StringIterator operator+(StringIterator it, int val) + { + return new StringIterator(it._string, it._index + val); + } + + public static StringIterator operator-(StringIterator it, int val) + { + return new StringIterator(it._string, it._index - val); + } + + public static bool operator==(StringIterator it1, StringIterator it2) + { + Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); + return it1._index == it2._index; + } + + public static bool operator !=(StringIterator it1, StringIterator it2) + { + Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); + return it1._index != it2._index; + } + + public override bool Equals(object obj) + { + throw new NotImplementedException(); + } + + public override int GetHashCode() + { + throw new NotImplementedException(); + } + } + #endregion + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/DebugNameFormatter.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/DebugNameFormatter.cs new file mode 100644 index 00000000000..ea8dfb77288 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/DebugNameFormatter.cs @@ -0,0 +1,275 @@ +// 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.Text; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public partial class DebugNameFormatter : TypeNameFormatter + { + public static readonly DebugNameFormatter Instance = new DebugNameFormatter(); + + public override Void AppendName(StringBuilder sb, ArrayType type, FormatOptions options) + { + AppendName(sb, type.ElementType, options); + + if (!type.IsSzArray && type.Rank == 1) + { + sb.Append("[*]"); + } + else + { + sb.Append('['); + sb.Append(',', type.Rank - 1); + sb.Append(']'); + } + + return Void.Value; + } + + public override Void AppendName(StringBuilder sb, ByRefType type, FormatOptions options) + { + AppendName(sb, type.ParameterType, options); + sb.Append('&'); + + return Void.Value; + } + + public override Void AppendName(StringBuilder sb, PointerType type, FormatOptions options) + { + AppendName(sb, type.ParameterType, options); + sb.Append('*'); + + return Void.Value; + } + + public override Void AppendName(StringBuilder sb, FunctionPointerType type, FormatOptions options) + { + MethodSignature signature = type.Signature; + + sb.Append("(*"); + AppendName(sb, signature.ReturnType, options); + sb.Append(")("); + for (int i = 0; i < signature.Length; i++) + { + if (i > 0) + sb.Append(','); + AppendName(sb, signature[i], options); + } + sb.Append(')'); + + return Void.Value; + } + + public override Void AppendName(StringBuilder sb, GenericParameterDesc type, FormatOptions options) + { + sb.Append(type.DiagnosticName); + return Void.Value; + } + + public override Void AppendName(StringBuilder sb, SignatureMethodVariable type, FormatOptions options) + { + sb.Append("!!"); + sb.Append(type.Index.ToStringInvariant()); + + return Void.Value; + } + + public override Void AppendName(StringBuilder sb, SignatureTypeVariable type, FormatOptions options) + { + sb.Append("!"); + sb.Append(type.Index.ToStringInvariant()); + + return Void.Value; + } + + protected override Void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType, FormatOptions options) + { + if ((options & FormatOptions.NamespaceQualify) != 0) + { + AppendName(sb, containingType, options); + sb.Append('+'); + } + + sb.Append(nestedType.DiagnosticName); + + return Void.Value; + } + + protected override Void AppendNameForNamespaceType(StringBuilder sb, DefType type, FormatOptions options) + { + int initialLen = sb.Length; + try + { + // Shortcut some of the well known types + switch (type.Category) + { + case TypeFlags.Void: + sb.Append("void"); + return Void.Value; + case TypeFlags.Boolean: + sb.Append("bool"); + return Void.Value; + case TypeFlags.Char: + sb.Append("char"); + return Void.Value; + case TypeFlags.SByte: + sb.Append("int8"); + return Void.Value; + case TypeFlags.Byte: + sb.Append("uint8"); + return Void.Value; + case TypeFlags.Int16: + sb.Append("int16"); + return Void.Value; + case TypeFlags.UInt16: + sb.Append("uint16"); + return Void.Value; + case TypeFlags.Int32: + sb.Append("int32"); + return Void.Value; + case TypeFlags.UInt32: + sb.Append("uint32"); + return Void.Value; + case TypeFlags.Int64: + sb.Append("int64"); + return Void.Value; + case TypeFlags.UInt64: + sb.Append("uint64"); + return Void.Value; + case TypeFlags.IntPtr: + sb.Append("native int"); + return Void.Value; + case TypeFlags.UIntPtr: + sb.Append("native uint"); + return Void.Value; + case TypeFlags.Single: + sb.Append("float32"); + return Void.Value; + case TypeFlags.Double: + sb.Append("float64"); + return Void.Value; + } + + if (type.IsString) + { + sb.Append("string"); + return Void.Value; + } + + if (type.IsObject) + { + sb.Append("object"); + return Void.Value; + } + + AssemblyQualify(sb, type, options); + NamespaceQualify(sb, type, options); + sb.Append(type.DiagnosticName); + } + catch + { + sb.Length = initialLen; + + // + AssemblyQualify(sb, type, options); + NamespaceQualify(sb, type, options); + sb.Append(type.DiagnosticName); + } + + return Void.Value; + } + + private void AssemblyQualify(StringBuilder sb, DefType type, FormatOptions options) + { + if (((options & FormatOptions.AssemblyQualify) != 0) + && type is MetadataType mdType + && mdType.Module is IAssemblyDesc) + { + sb.Append('['); + + // Trim the "System.Private." prefix + string assemblyName; + try + { + assemblyName = ((IAssemblyDesc)mdType.Module).GetName().Name; + } + catch + { + assemblyName = "Unknown"; + } + + if (assemblyName.StartsWith("System.Private", StringComparison.Ordinal)) + assemblyName = "S.P" + assemblyName.Substring(14); + + sb.Append(assemblyName); + sb.Append(']'); + } + } + + private void NamespaceQualify(StringBuilder sb, DefType type, FormatOptions options) + { + if ((options & FormatOptions.NamespaceQualify) != 0) + { + string ns = type.DiagnosticNamespace; + if (!string.IsNullOrEmpty(ns)) + { + sb.Append(ns); + sb.Append('.'); + } + } + } + + protected override Void AppendNameForInstantiatedType(StringBuilder sb, DefType type, FormatOptions options) + { + AppendName(sb, type.GetTypeDefinition(), options); + + FormatOptions parameterOptions = options & ~FormatOptions.AssemblyQualify; + + sb.Append('<'); + + for (int i = 0; i < type.Instantiation.Length; i++) + { + if (i != 0) + sb.Append(','); + + AppendName(sb, type.Instantiation[i], parameterOptions); + } + + sb.Append('>'); + + return Void.Value; + } + + protected override DefType GetContainingType(DefType possibleInnerType, FormatOptions options) + { + try + { + return possibleInnerType.ContainingType; + } + catch + { + return null; + } + } + + public struct Void + { + public static Void Value => default(Void); + } + + [Flags] + public enum FormatOptions + { + None = 0, + AssemblyQualify = 0x1, + NamespaceQualify = 0x2, + + Default = AssemblyQualify | NamespaceQualify, + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.Metadata.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.Metadata.cs new file mode 100644 index 00000000000..f79364bfd1d --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.Metadata.cs @@ -0,0 +1,20 @@ +// 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 +{ + // Type name formatting functionality that relies on metadata. + partial class ExceptionTypeNameFormatter + { + private string GetTypeName(DefType type) + { + return type.Name; + } + + private string GetTypeNamespace(DefType type) + { + return type.Namespace; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.cs new file mode 100644 index 00000000000..4e7447cc4a3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.cs @@ -0,0 +1,118 @@ +// 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.Text; + +namespace Internal.TypeSystem +{ + /// + /// Provides a name formatter that is compatible with SigFormat.cpp in the CLR. + /// + public partial class ExceptionTypeNameFormatter : TypeNameFormatter + { + public static ExceptionTypeNameFormatter Instance { get; } = new ExceptionTypeNameFormatter(); + + public override void AppendName(StringBuilder sb, PointerType type) + { + AppendName(sb, type.ParameterType); + sb.Append('*'); + } + + public override void AppendName(StringBuilder sb, GenericParameterDesc type) + { + string prefix = type.Kind == GenericParameterKind.Type ? "!" : "!!"; + sb.Append(prefix); + sb.Append(type.Name); + } + + public override void AppendName(StringBuilder sb, SignatureTypeVariable type) + { + sb.Append("!"); + sb.Append(type.Index.ToStringInvariant()); + } + + public override void AppendName(StringBuilder sb, SignatureMethodVariable type) + { + sb.Append("!!"); + sb.Append(type.Index.ToStringInvariant()); + } + + public override void AppendName(StringBuilder sb, FunctionPointerType type) + { + MethodSignature signature = type.Signature; + + AppendName(sb, signature.ReturnType); + + sb.Append(" ("); + for (int i = 0; i < signature.Length; i++) + { + if (i > 0) + sb.Append(", "); + AppendName(sb, signature[i]); + } + + // TODO: Append '...' for vararg methods + + sb.Append(')'); + } + + public override void AppendName(StringBuilder sb, ByRefType type) + { + AppendName(sb, type.ParameterType); + sb.Append(" ByRef"); + } + + public override void AppendName(StringBuilder sb, ArrayType type) + { + AppendName(sb, type.ElementType); + sb.Append('['); + + // NOTE: We're ignoring difference between SzArray and MdArray rank 1 for SigFormat.cpp compat. + sb.Append(',', type.Rank - 1); + + sb.Append(']'); + } + + protected override void AppendNameForInstantiatedType(StringBuilder sb, DefType type) + { + AppendName(sb, type.GetTypeDefinition()); + sb.Append('<'); + + for (int i = 0; i < type.Instantiation.Length; i++) + { + if (i > 0) + sb.Append(", "); + AppendName(sb, type.Instantiation[i]); + } + + sb.Append('>'); + } + + protected override void AppendNameForNamespaceType(StringBuilder sb, DefType type) + { + if (type.IsPrimitive) + { + sb.Append(GetTypeName(type)); + } + else + { + string ns = GetTypeNamespace(type); + if (ns.Length > 0) + { + sb.Append(ns); + sb.Append('.'); + } + sb.Append(GetTypeName(type)); + } + } + + protected override void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType) + { + // NOTE: We're ignoring the containing type for compatiblity with SigFormat.cpp + sb.Append(GetTypeName(nestedType)); + } + } +} + diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs new file mode 100644 index 00000000000..f9b929546c3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs @@ -0,0 +1,600 @@ +// 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.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// A hash table which is lock free for readers and up to 1 writer at a time. + /// It must be possible to compute the key's hashcode from a value. + /// All values must be reference types. + /// It must be possible to perform an equality check between a key and a value. + /// It must be possible to perform an equality check between a value and a value. + /// A LockFreeReaderKeyValueComparer must be provided to perform these operations. + /// + /// + /// + abstract public class LockFreeReaderHashtable where TValue : class + { + private const int _initialSize = 16; + private const int _fillPercentageBeforeResize = 60; + + /// + /// _hashtable is the currently visible underlying array for the hashtable + /// Any modifications to this array must be additive only, and there must + /// never be a situation where the visible _hashtable has less data than + /// it did at an earlier time. This value is initialized to an array of size + /// 1. (That array is never mutated as any additions will trigger an Expand + /// operation, but we don't use an empty array as the + /// initial step, as this approach allows the TryGetValue logic to always + /// succeed without needing any length or null checks.) + /// + private volatile TValue[] _hashtable = new TValue[_initialSize]; + + /// + /// Tracks the hashtable being used by expansion. Used as a sentinel + /// to threads trying to add to the old hashtable that an expansion is + /// in progress. + /// + private volatile TValue[] _newHashTable; + + /// + /// _count represents the current count of elements in the hashtable + /// _count is used in combination with _resizeCount to control when the + /// hashtable should expand + /// + private volatile int _count = 0; + + /// + /// Represents _count plus the number of potential adds currently happening. + /// If this reaches _hashTable.Length-1, an expansion is required (because + /// one slot must always be null for seeks to complete). + /// + private int _reserve = 0; + + /// + /// _resizeCount represents the size at which the hashtable should resize. + /// While this doesn't strictly need to be volatile, having threads read stale values + /// triggers a lot of unneeded attempts to expand. + /// + private volatile int _resizeCount = _initialSize * _fillPercentageBeforeResize / 100; + + /// + /// Get the underlying array for the hashtable at this time. + /// + private TValue[] GetCurrentHashtable() + { + return _hashtable; + } + + /// + /// Set the newly visible hashtable underlying array. Used by writers after + /// the new array is fully constructed. The volatile write is used to ensure + /// that all writes to the contents of hashtable are completed before _hashtable + /// is visible to readers. + /// + private void SetCurrentHashtable(TValue[] hashtable) + { + _hashtable = hashtable; + } + + /// + /// Used to ensure that the hashtable can function with + /// fairly poor initial hash codes. + /// + public static int HashInt1(int key) + { + unchecked + { + int a = (int)0x9e3779b9 + key; + int b = (int)0x9e3779b9; + int c = 16777619; + a -= b; a -= c; a ^= (c >> 13); + b -= c; b -= a; b ^= (a << 8); + c -= a; c -= b; c ^= (b >> 13); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 16); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 3); + b -= c; b -= a; b ^= (a << 10); + c -= a; c -= b; c ^= (b >> 15); + return c; + } + } + + /// + /// Generate a somewhat independent hash value from another integer. This is used + /// as part of a double hashing scheme. By being relatively prime with powers of 2 + /// this hash function can be reliably used as part of a double hashing scheme as it + /// is guaranteed to eventually probe every slot in the table. (Table sizes are + /// constrained to be a power of two) + /// + public static int HashInt2(int key) + { + unchecked + { + int hash = unchecked((int)0xB1635D64) + key; + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + hash |= 0x00000001; // To make sure that this is relatively prime with power of 2 + return hash; + } + } + + /// + /// Create the LockFreeReaderHashtable. This hash table is designed for GetOrCreateValue + /// to be a generally lock free api (unless an add is necessary) + /// + public LockFreeReaderHashtable() + { +#if DEBUG + // Ensure the initial value is a power of 2 + bool foundAOne = false; + for (int i = 0; i < 32; i++) + { + int lastBit = _initialSize >> i; + if ((lastBit & 0x1) == 0x1) + { + Debug.Assert(!foundAOne); + foundAOne = true; + } + } +#endif // DEBUG + _newHashTable = _hashtable; + } + + /// + /// The current count of elements in the hashtable + /// + public int Count { get { return _count; } } + + /// + /// Gets the value associated with the specified key. + /// + /// The key of the value to get. + /// When this method returns, contains the value associated with + /// the specified key, if the key is found; otherwise, the default value for the type + /// of the value parameter. This parameter is passed uninitialized. This function is threadsafe, + /// and wait-free + /// true if a value was found + public bool TryGetValue(TKey key, out TValue value) + { + TValue[] hashTableLocal = GetCurrentHashtable(); + Debug.Assert(hashTableLocal.Length > 0); + int mask = hashTableLocal.Length - 1; + int hashCode = GetKeyHashCode(key); + int tableIndex = HashInt1(hashCode) & mask; + + if (hashTableLocal[tableIndex] == null) + { + value = null; + return false; + } + + if (CompareKeyToValue(key, hashTableLocal[tableIndex])) + { + value = hashTableLocal[tableIndex]; + return true; + } + + int hash2 = HashInt2(hashCode); + tableIndex = (tableIndex + hash2) & mask; + + while (hashTableLocal[tableIndex] != null) + { + if (CompareKeyToValue(key, hashTableLocal[tableIndex])) + { + value = hashTableLocal[tableIndex]; + return true; + } + tableIndex = (tableIndex + hash2) & mask; + } + value = null; + return false; + } + + /// + /// Make the underlying array of the hashtable bigger. This function + /// does not change the contents of the hashtable. This entire function locks. + /// + private void Expand(TValue[] oldHashtable) + { + lock(this) + { + // If somebody else already resized, don't try to do it based on an old table + if(oldHashtable != _hashtable) + { + return; + } + + // The checked statement here protects against both the hashTable size and _reserve overflowing. That does mean + // the maximum size of _hashTable is 0x70000000 + int newSize = checked(oldHashtable.Length * 2); + + // The hashtable only functions well when it has a certain minimum size + const int minimumUsefulSize = 16; + if (newSize < minimumUsefulSize) + newSize = minimumUsefulSize; + + // Work in a local variable to avoid lots of unnecessary volatile reads of _newHashTable since only this method can + // change it and we're under a lock + TValue[] newHashTable = new TValue[newSize]; + _newHashTable = newHashTable; + // Due to the volatile write above, any adds on other threads after this point will + // fail and be redone, thus writing to the new hash table. + + int mask = newHashTable.Length - 1; + foreach (TValue value in oldHashtable) + { + if (value == null) + continue; + + // If there's a deadlock at this point, GetValueHashCode is re-entering Add, which it must not do. + int hashCode = GetValueHashCode(value); + int tableIndex = HashInt1(hashCode) & mask; + + // Initial probe into hashtable found empty spot + if (newHashTable[tableIndex] == null) + { + // Add to hash + newHashTable[tableIndex] = value; + continue; + } + + int hash2 = HashInt2(hashCode); + tableIndex = (tableIndex + hash2) & mask; + + while (newHashTable[tableIndex] != null) + { + tableIndex = (tableIndex + hash2) & mask; + } + + // We've probed to find an empty spot + // Add to hash + newHashTable[tableIndex] = value; + } + + _resizeCount = checked((newSize * _fillPercentageBeforeResize) / 100); + SetCurrentHashtable(newHashTable); + } + } + + /// + /// Adds a value to the hashtable if it is not already present. + /// Note that the key is not specified as it is implicit in the value. This function is thread-safe, + /// but must only take locks around internal operations and GetValueHashCode. + /// + /// Value to attempt to add to the hashtable, must not be null + /// True if the value was added. False if it was already present. + public bool TryAdd(TValue value) + { + bool addedValue; + AddOrGetExistingInner(value, out addedValue); + return addedValue; + } + + /// + /// Add a value to the hashtable, or find a value which is already present in the hashtable. + /// Note that the key is not specified as it is implicit in the value. This function is thread-safe, + /// but must only take locks around internal operations and GetValueHashCode. + /// + /// Value to attempt to add to the hashtable, must not be null + /// Newly added value, or a value which was already present in the hashtable which is equal to it. + public TValue AddOrGetExisting(TValue value) + { + bool unused; + return AddOrGetExistingInner(value, out unused); + } + + private TValue AddOrGetExistingInner(TValue value, out bool addedValue) + { + if (value == null) + throw new ArgumentNullException(); + + // Optimistically check to see if adding this value may require an expansion. If so, expand + // the table now. This isn't required to ensure space for the write, but helps keep + // the ratio in a good range. + if (_count >= _resizeCount) + { + Expand(_hashtable); + } + + TValue result; + do + { + result = TryAddOrGetExisting(value, out addedValue); + } while (result == null); + return result; + } + + /// + /// Attemps to add a value to the hashtable, or find a value which is already present in the hashtable. + /// In some cases, this will fail due to contention with other additions and must be retried. + /// Note that the key is not specified as it is implicit in the value. This function is thread-safe, + /// but must only take locks around internal operations and GetValueHashCode. + /// + /// Value to attempt to add to the hashtable, must not be null + /// Set to true if was added to the table. False if the value + /// was already present. Not defined if adding was attempted but failed. + /// Newly added value if adding succeds, a value which was already present in the hashtable which is equal to it, + /// or null if adding fails and must be retried. + private TValue TryAddOrGetExisting(TValue value, out bool addedValue) + { + // The table must be captured into a local to ensure reads/writes + // don't get torn by expansions + TValue[] hashTableLocal = _hashtable; + + addedValue = true; + int mask = hashTableLocal.Length - 1; + int hashCode = GetValueHashCode(value); + int tableIndex = HashInt1(hashCode) & mask; + + // Find an empty spot, starting with the initial tableIndex + if (hashTableLocal[tableIndex] != null) + { + if (CompareValueToValue(value, hashTableLocal[tableIndex])) + { + // Value is already present in hash, do not add + addedValue = false; + return hashTableLocal[tableIndex]; + } + + int hash2 = HashInt2(hashCode); + tableIndex = (tableIndex + hash2) & mask; + + while (hashTableLocal[tableIndex] != null) + { + if (CompareValueToValue(value, hashTableLocal[tableIndex])) + { + // Value is already present in hash, do not add + addedValue = false; + return hashTableLocal[tableIndex]; + } + tableIndex = (tableIndex + hash2) & mask; + } + } + + // Ensure there's enough space for at least one null slot after this write + if (Interlocked.Increment(ref _reserve) >= hashTableLocal.Length - 1) + { + Interlocked.Decrement(ref _reserve); + Expand(hashTableLocal); + + // Since we expanded, our index won't work, restart + return null; + } + + // We've probed to find an empty spot, add to hash + if (!TryWriteValueToLocation(value, hashTableLocal, tableIndex)) + { + Interlocked.Decrement(ref _reserve); + return null; + } + + // Now that we've written to the local array, find out if that array has been + // replaced by expansion. If it has, we need to restart and write to the new array. + if (_newHashTable != hashTableLocal) + { + // Pulse the lock so we don't spin during an expansion + lock(this) { } + Interlocked.Decrement(ref _reserve); + return null; + } + + // If the write succeeded, increment _count + Interlocked.Increment(ref _count); + return value; + } + + /// + /// Attampts to write a value into the table. May fail if another value has been added. + /// + /// True if the value was successfully written + private bool TryWriteValueToLocation(TValue value, TValue[] hashTableLocal, int tableIndex) + { + // Add to hash, use a volatile write to ensure that + // the contents of the value are fully published to all + // threads before adding to the hashtable + if (Interlocked.CompareExchange(ref hashTableLocal[tableIndex], value, null) == null) + { + return true; + } + + return false; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private TValue CreateValueAndEnsureValueIsInTable(TKey key) + { + TValue newValue = CreateValueFromKey(key); + Debug.Assert(GetValueHashCode(newValue) == GetKeyHashCode(key)); + + return AddOrGetExisting(newValue); + } + + /// + /// Get the value associated with a key. If value is not present in dictionary, use the creator delegate passed in + /// at object construction time to create the value, and attempt to add it to the table. (Create the value while not + /// under the lock, but add it to the table while under the lock. This may result in a throw away object being constructed) + /// This function is thread-safe, but will take a lock to perform its operations. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TValue GetOrCreateValue(TKey key) + { + TValue existingValue; + if (TryGetValue(key, out existingValue)) + return existingValue; + + return CreateValueAndEnsureValueIsInTable(key); + } + + /// + /// Determine if this collection contains a value associated with a key. This function is thread-safe, and wait-free. + /// + public bool Contains(TKey key) + { + TValue dummyExistingValue; + return TryGetValue(key, out dummyExistingValue); + } + + /// + /// Determine if this collection contains a given value, and returns the value in the hashtable if found. This function is thread-safe, and wait-free. + /// + /// Value to search for in the hashtable, must not be null + /// Value from the hashtable if found, otherwise null. + public TValue GetValueIfExists(TValue value) + { + if (value == null) + throw new ArgumentNullException(); + + TValue[] hashTableLocal = GetCurrentHashtable(); + Debug.Assert(hashTableLocal.Length > 0); + int mask = hashTableLocal.Length - 1; + int hashCode = GetValueHashCode(value); + int tableIndex = HashInt1(hashCode) & mask; + + if (hashTableLocal[tableIndex] == null) + return null; + + if (CompareValueToValue(value, hashTableLocal[tableIndex])) + return hashTableLocal[tableIndex]; + + int hash2 = HashInt2(hashCode); + tableIndex = (tableIndex + hash2) & mask; + + while (hashTableLocal[tableIndex] != null) + { + if (CompareValueToValue(value, hashTableLocal[tableIndex])) + return hashTableLocal[tableIndex]; + + tableIndex = (tableIndex + hash2) & mask; + } + + return null; + } + + /// + /// Enumerator type for the LockFreeReaderHashtable + /// This is threadsafe, but is not garaunteed to avoid torn state. + /// In particular, the enumerator may report some newly added values + /// but not others. All values in the hashtable as of enumerator + /// creation will always be enumerated. + /// + public struct Enumerator : IEnumerator + { + private TValue[] _hashtableContentsToEnumerate; + private int _index; + private TValue _current; + + /// + /// Use this to get an enumerable collection from a LockFreeReaderHashtable. + /// Used instead of a GetEnumerator method on the LockFreeReaderHashtable to + /// reduce excess type creation. (By moving the method here, the generic dictionary for + /// LockFreeReaderHashtable does not need to contain a reference to the + /// enumerator type. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Enumerator Get(LockFreeReaderHashtable hashtable) + { + return new Enumerator(hashtable); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Enumerator GetEnumerator() + { + return this; + } + + internal Enumerator(LockFreeReaderHashtable hashtable) + { + _hashtableContentsToEnumerate = hashtable._hashtable; + _index = 0; + _current = default(TValue); + } + + public bool MoveNext() + { + if ((_hashtableContentsToEnumerate != null) && (_index < _hashtableContentsToEnumerate.Length)) + { + for (; _index < _hashtableContentsToEnumerate.Length; _index++) + { + if (_hashtableContentsToEnumerate[_index] != null) + { + _current = _hashtableContentsToEnumerate[_index]; + _index++; + return true; + } + } + } + + _current = default(TValue); + return false; + } + + public void Dispose() + { + } + + public void Reset() + { + throw new NotSupportedException(); + } + + public TValue Current + { + get + { + return _current; + } + } + + object IEnumerator.Current + { + get + { + throw new NotSupportedException(); + } + } + } + + /// + /// Given a key, compute a hash code. This function must be thread safe. + /// + protected abstract int GetKeyHashCode(TKey key); + + /// + /// Given a value, compute a hash code which would be identical to the hash code + /// for a key which should look up this value. This function must be thread safe. + /// This function must also not cause additional hashtable adds. + /// + protected abstract int GetValueHashCode(TValue value); + + /// + /// Compare a key and value. If the key refers to this value, return true. + /// This function must be thread safe. + /// + protected abstract bool CompareKeyToValue(TKey key, TValue value); + + /// + /// Compare a value with another value. Return true if values are equal. + /// This function must be thread safe. + /// + protected abstract bool CompareValueToValue(TValue value1, TValue value2); + + /// + /// Create a new value from a key. Must be threadsafe. Value may or may not be added + /// to collection. Return value must not be null. + /// + protected abstract TValue CreateValueFromKey(TKey key); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/TypeNameFormatter.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/TypeNameFormatter.cs new file mode 100644 index 00000000000..1f946786cb9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/TypeNameFormatter.cs @@ -0,0 +1,146 @@ +// 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.Text; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Provides services to convert types to strings. + /// + public abstract class TypeNameFormatter + { + public void AppendName(StringBuilder sb, TypeDesc type) + { + switch (type.Category) + { + case TypeFlags.Array: + case TypeFlags.SzArray: + AppendName(sb, (ArrayType)type); + return; + case TypeFlags.ByRef: + AppendName(sb, (ByRefType)type); + return; + case TypeFlags.Pointer: + AppendName(sb, (PointerType)type); + return; + case TypeFlags.FunctionPointer: + AppendName(sb, (FunctionPointerType)type); + return; + case TypeFlags.GenericParameter: + AppendName(sb, (GenericParameterDesc)type); + return; + case TypeFlags.SignatureTypeVariable: + AppendName(sb, (SignatureTypeVariable)type); + return; + case TypeFlags.SignatureMethodVariable: + AppendName(sb, (SignatureMethodVariable)type); + return; + default: + Debug.Assert(type.IsDefType); + AppendName(sb, (DefType)type); + return; + } + } + + public void AppendName(StringBuilder sb, DefType type) + { + if (!type.IsTypeDefinition) + { + AppendNameForInstantiatedType(sb, type); + } + else + { + DefType containingType = type.ContainingType; + if (containingType != null) + AppendNameForNestedType(sb, type, containingType); + else + AppendNameForNamespaceType(sb, type); + } + } + + public abstract void AppendName(StringBuilder sb, ArrayType type); + public abstract void AppendName(StringBuilder sb, ByRefType type); + public abstract void AppendName(StringBuilder sb, PointerType type); + public abstract void AppendName(StringBuilder sb, FunctionPointerType type); + public abstract void AppendName(StringBuilder sb, GenericParameterDesc type); + public abstract void AppendName(StringBuilder sb, SignatureMethodVariable type); + public abstract void AppendName(StringBuilder sb, SignatureTypeVariable type); + + protected abstract void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType); + protected abstract void AppendNameForNamespaceType(StringBuilder sb, DefType type); + protected abstract void AppendNameForInstantiatedType(StringBuilder sb, DefType type); + + public string FormatName(TypeDesc type) + { + StringBuilder sb = new StringBuilder(); + AppendName(sb, type); + return sb.ToString(); + } + } + + public abstract class TypeNameFormatter + { + public TState AppendName(StringBuilder sb, TypeDesc type, TOptions options) + { + // Don't use Category to switch here as it may fail for some types, and the DebugNameFormatter + // which is derived from that type cannot tolerate those failures + return type switch + { + ArrayType arrayType => AppendName(sb, arrayType, options), + ByRefType byRefType => AppendName(sb, byRefType, options), + PointerType pointerType => AppendName(sb, pointerType, options), + FunctionPointerType functionPointerType => AppendName(sb, functionPointerType, options), + GenericParameterDesc genericPointerType => AppendName(sb, genericPointerType, options), + SignatureTypeVariable sigTypeVar => AppendName(sb, sigTypeVar, options), + SignatureMethodVariable sigMethodVar => AppendName(sb, sigMethodVar, options), + _ => AppendName(sb, (DefType)type, options) + }; + } + + public TState AppendName(StringBuilder sb, DefType type, TOptions options) + { + if (!type.IsTypeDefinition) + { + return AppendNameForInstantiatedType(sb, type, options); + } + else + { + DefType containingType = GetContainingType(type, options); + + if (containingType != null) + return AppendNameForNestedType(sb, type, containingType, options); + else + return AppendNameForNamespaceType(sb, type, options); + } + } + + public abstract TState AppendName(StringBuilder sb, ArrayType type, TOptions options); + public abstract TState AppendName(StringBuilder sb, ByRefType type, TOptions options); + public abstract TState AppendName(StringBuilder sb, PointerType type, TOptions options); + public abstract TState AppendName(StringBuilder sb, FunctionPointerType type, TOptions options); + public abstract TState AppendName(StringBuilder sb, GenericParameterDesc type, TOptions options); + public abstract TState AppendName(StringBuilder sb, SignatureMethodVariable type, TOptions options); + public abstract TState AppendName(StringBuilder sb, SignatureTypeVariable type, TOptions options); + + protected abstract TState AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType, TOptions options); + protected abstract TState AppendNameForNamespaceType(StringBuilder sb, DefType type, TOptions options); + protected abstract TState AppendNameForInstantiatedType(StringBuilder sb, DefType type, TOptions options); + + protected virtual DefType GetContainingType(DefType possibleInnerType, TOptions options) + { + return possibleInnerType.ContainingType; + } + + public string FormatName(TypeDesc type, TOptions options) + { + StringBuilder sb = new StringBuilder(); + AppendName(sb, type, options); + return sb.ToString(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs new file mode 100644 index 00000000000..4f22881d4a9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs @@ -0,0 +1,38 @@ +// 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.Collections.Generic; + +namespace Internal.TypeSystem +{ + /// + /// Pluggable virtual method computation algorithm. Provides an abstraction to resolve + /// virtual and interface methods on types. + /// + /// + /// The algorithms are expected to be directly used by derivatives + /// only. The most obvious implementation of this algorithm that uses type's metadata to + /// compute the answers is in . + /// + public abstract class VirtualMethodAlgorithm + { + /// + /// Resolves interface method '' to a method on '' + /// that implements the the method. + /// + public abstract MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType); + + public abstract MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType); + + /// + /// Resolves a virtual method call. + /// + public abstract MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, TypeDesc objectType); + + /// + /// Enumerates all virtual slots on ''. + /// + public abstract IEnumerable ComputeAllVirtualSlots(TypeDesc type); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/WellKnownType.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/WellKnownType.cs new file mode 100644 index 00000000000..1f0e22c8411 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/WellKnownType.cs @@ -0,0 +1,52 @@ +// 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; + +namespace Internal.TypeSystem +{ + // The following enum is required for interop with the VS Debugger + // Prior to making any changes to this enum, please reach out to the VS Debugger + // team to make sure that your changes are not going to prevent the debugger + // from working. + public enum WellKnownType + { + Unknown, + + // Primitive types are first - keep in sync with type flags + Void, + Boolean, + Char, + SByte, + Byte, + Int16, + UInt16, + Int32, + UInt32, + Int64, + UInt64, + IntPtr, + UIntPtr, + Single, + Double, + + ValueType, + Enum, + Nullable, + + Object, + String, + Array, + MulticastDelegate, + + RuntimeTypeHandle, + RuntimeMethodHandle, + RuntimeFieldHandle, + + Exception, + + TypedReference, + ByReferenceOfT, + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/CachingMetadataStringDecoder.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/CachingMetadataStringDecoder.cs new file mode 100644 index 00000000000..f965a8bce32 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/CachingMetadataStringDecoder.cs @@ -0,0 +1,195 @@ +// 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.Reflection.Metadata; +using System.Runtime.CompilerServices; +using Debug = System.Diagnostics.Debug; + +using Internal.NativeFormat; + +namespace Internal.TypeSystem.Ecma +{ + /// + /// MetadataReader string decoder that caches and reuses strings rather than allocating + /// on each call to MetadataReader.GetString(handle). + /// Safe to use from multiple threads and lock free. + /// + public sealed class CachingMetadataStringDecoder : MetadataStringDecoder + { + private struct Entry + { + // hash code of the entry + public int HashCode; + + // full text of the item + public string Text; + } + + // TODO: Tune the bucket size + private const int BucketSize = 4; + + // The table of cached entries. The size of the table has to be power of 2. + private Entry[] _table; + + // The next candidate in the bucket range for eviction + private int _evictionHint; + + public CachingMetadataStringDecoder(int size) + : base(System.Text.Encoding.UTF8) + { + Debug.Assert((size & (size - 1)) == 0, "The cache size must be power of 2"); + + _table = new Entry[size]; + } + + private string Find(int hashCode, string s) + { + var arr = _table; + int mask = _table.Length - 1; + + int idx = hashCode & mask; + + // we use quadratic probing here + // bucket positions are (n^2 + n)/2 relative to the masked hashcode + for (int i = 1; i < BucketSize + 1; i++) + { + string e = arr[idx].Text; + int hash = arr[idx].HashCode; + + if (e == null) + { + // once we see unfilled entry, the rest of the bucket will be empty + break; + } + + if (hash == hashCode && s == e) + { + return e; + } + + idx = (idx + i) & mask; + } + return null; + } + + private unsafe string FindASCII(int hashCode, byte* bytes, int byteCount) + { + var arr = _table; + int mask = _table.Length - 1; + + int idx = hashCode & mask; + + // we use quadratic probing here + // bucket positions are (n^2 + n)/2 relative to the masked hashcode + for (int i = 1; i < BucketSize + 1; i++) + { + string e = arr[idx].Text; + int hash = arr[idx].HashCode; + + if (e == null) + { + // once we see unfilled entry, the rest of the bucket will be empty + break; + } + + if (hash == hashCode && TextEqualsASCII(e, bytes, byteCount)) + { + return e; + } + + idx = (idx + i) & mask; + } + return null; + } + + private static unsafe bool TextEqualsASCII(string text, byte* ascii, int length) + { +#if DEBUG + for (var i = 0; i < length; i++) + { + Debug.Assert((ascii[i] & 0x80) == 0, "The byte* input to this method must be valid ASCII."); + } +#endif + + if (length != text.Length) + { + return false; + } + + for (var i = 0; i < length; i++) + { + if (ascii[i] != text[i]) + { + return false; + } + } + + return true; + } + + private string Add(int hashCode, string s) + { + var arr = _table; + int mask = _table.Length - 1; + + int idx = hashCode & mask; + + // try finding an empty spot in the bucket + // we use quadratic probing here + // bucket positions are (n^2 + n)/2 relative to the masked hashcode + int curIdx = idx; + for (int i = 1; i < BucketSize + 1; i++) + { + if (arr[curIdx].Text == null) + { + idx = curIdx; + goto foundIdx; + } + + curIdx = (curIdx + i) & BucketSize; + } + + // or pick a victim within the bucket range + // and replace with new entry + var i1 = _evictionHint++ & (BucketSize - 1); + idx = (idx + ((i1 * i1 + i1) / 2)) & mask; + + foundIdx: + arr[idx].HashCode = hashCode; + arr[idx].Text = s; + + return s; + } + + public string Lookup(string s) + { + int hashCode = TypeHashingAlgorithms.ComputeNameHashCode(s); + + string existing = Find(hashCode, s); + if (existing != null) + return existing; + + return Add(hashCode, s); + } + + public unsafe override string GetString(byte* bytes, int byteCount) + { + bool isAscii; + int hashCode = TypeHashingAlgorithms.ComputeASCIINameHashCode(bytes, byteCount, out isAscii); + + if (isAscii) + { + string existing = FindASCII(hashCode, bytes, byteCount); + if (existing != null) + return existing; + return Add(hashCode, Encoding.GetString(bytes, byteCount)); + } + else + { + return Lookup(Encoding.GetString(bytes, byteCount)); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/CustomAttributeTypeProvider.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/CustomAttributeTypeProvider.cs new file mode 100644 index 00000000000..2e9d88e3d8f --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/CustomAttributeTypeProvider.cs @@ -0,0 +1,97 @@ +// 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.Reflection.Metadata; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem.Ecma +{ + public struct CustomAttributeTypeProvider : ICustomAttributeTypeProvider + { + private EcmaModule _module; + + public CustomAttributeTypeProvider(EcmaModule module) + { + _module = module; + } + + public TypeDesc GetPrimitiveType(PrimitiveTypeCode typeCode) + { + return PrimitiveTypeProvider.GetPrimitiveType(_module.Context, typeCode); + } + + public TypeDesc GetSystemType() + { + MetadataType systemType = _module.Context.SystemModule.GetType("System", "Type"); + return systemType; + } + + public TypeDesc GetSZArrayType(TypeDesc elementType) + { + return elementType.MakeArrayType(); + } + + public TypeDesc GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) + { + Debug.Assert(reader == _module.MetadataReader); + return _module.GetType(handle); + } + + public TypeDesc GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) + { + Debug.Assert(reader == _module.MetadataReader); + return _module.GetType(handle); + } + + public TypeDesc GetTypeFromSpecification(MetadataReader reader, TypeSpecificationHandle handle, byte rawTypeKind) + { + Debug.Assert(reader == _module.MetadataReader); + return _module.GetType(handle); + } + + public TypeDesc GetTypeFromSerializedName(string name) + { + if (name == null) + return null; + + return _module.GetTypeByCustomAttributeTypeName(name); + } + + public PrimitiveTypeCode GetUnderlyingEnumType(TypeDesc type) + { + switch (type.UnderlyingType.Category) + { + case TypeFlags.Byte: + return PrimitiveTypeCode.Byte; + case TypeFlags.SByte: + return PrimitiveTypeCode.SByte; + case TypeFlags.UInt16: + return PrimitiveTypeCode.UInt16; + case TypeFlags.Int16: + return PrimitiveTypeCode.Int16; + case TypeFlags.UInt32: + return PrimitiveTypeCode.UInt32; + case TypeFlags.Int32: + return PrimitiveTypeCode.Int32; + case TypeFlags.UInt64: + return PrimitiveTypeCode.UInt64; + case TypeFlags.Int64: + return PrimitiveTypeCode.Int64; + default: + throw new BadImageFormatException(); + } + } + + public bool IsSystemType(TypeDesc type) + { + var metadataType = type as MetadataType; + return metadataType != null + && metadataType.Name == "Type" + && metadataType.Module == _module.Context.SystemModule + && metadataType.Namespace == "System"; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.Symbols.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.Symbols.cs new file mode 100644 index 00000000000..11f66f171c3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.Symbols.cs @@ -0,0 +1,19 @@ +// 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.Reflection.Metadata; +using System.Reflection.PortableExecutable; + +namespace Internal.TypeSystem.Ecma +{ + // Pluggable file that adds PDB handling functionality to EcmaAssembly + partial class EcmaAssembly + { + internal EcmaAssembly(TypeSystemContext context, PEReader peReader, MetadataReader metadataReader, PdbSymbolReader pdbReader) + : base(context, peReader, metadataReader, containingAssembly: null, pdbReader) + { + _assemblyDefinition = metadataReader.GetAssemblyDefinition(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs new file mode 100644 index 00000000000..e14056fdd26 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs @@ -0,0 +1,75 @@ +// 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.Reflection; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; + +namespace Internal.TypeSystem.Ecma +{ + public sealed partial class EcmaAssembly : EcmaModule, IAssemblyDesc + { + private AssemblyName _assemblyName; + private AssemblyDefinition _assemblyDefinition; + + public AssemblyDefinition AssemblyDefinition + { + get + { + return _assemblyDefinition; + } + } + + public override IAssemblyDesc Assembly + { + get + { + return this; + } + } + + public EcmaAssembly(TypeSystemContext context, PEReader peReader, MetadataReader metadataReader) + : base(context, peReader, metadataReader, containingAssembly: null) + { + if (!metadataReader.IsAssembly) + { + ThrowHelper.ThrowBadImageFormatException(); + } + + _assemblyDefinition = metadataReader.GetAssemblyDefinition(); + } + + // Returns cached copy of the name. Caller has to create a clone before mutating the name. + public AssemblyName GetName() + { + if (_assemblyName == null) + { + MetadataReader metadataReader = this.MetadataReader; + + AssemblyName an = new AssemblyName(); + an.Name = metadataReader.GetString(_assemblyDefinition.Name); + an.Version = _assemblyDefinition.Version; + an.SetPublicKey(metadataReader.GetBlobBytes(_assemblyDefinition.PublicKey)); + + an.CultureName = metadataReader.GetString(_assemblyDefinition.Culture); + an.ContentType = GetContentTypeFromAssemblyFlags(_assemblyDefinition.Flags); + + _assemblyName = an; + } + + return _assemblyName; + } + + public override string ToString() + { + return GetName().Name; + } + + public bool HasAssemblyCustomAttribute(string attributeNamespace, string attributeName) + { + return _metadataReader.GetCustomAttributeHandle(_assemblyDefinition.GetCustomAttributes(), + attributeNamespace, attributeName).IsNil; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.CodeGen.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.CodeGen.cs new file mode 100644 index 00000000000..a964d40111f --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.CodeGen.cs @@ -0,0 +1,17 @@ +// 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.Ecma +{ + partial class EcmaField + { + public override bool IsIntrinsic + { + get + { + return (GetFieldFlags(FieldFlags.AttributeMetadataCache | FieldFlags.Intrinsic) & FieldFlags.Intrinsic) != 0; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.Serialization.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.Serialization.cs new file mode 100644 index 00000000000..24b6da5a07d --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.Serialization.cs @@ -0,0 +1,17 @@ +// 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.Ecma +{ + partial class EcmaField + { + public override bool IsNotSerialized + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.NotSerialized) & FieldFlags.NotSerialized) != 0; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.Sorting.cs new file mode 100644 index 00000000000..79c5a28b0fc --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.Sorting.cs @@ -0,0 +1,28 @@ +// 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.Reflection.Metadata.Ecma335; + +namespace Internal.TypeSystem.Ecma +{ + // Functionality related to deterministic ordering of types and members + partial class EcmaField + { + protected internal override int ClassCode => 44626835; + + protected internal override int CompareToImpl(FieldDesc other, TypeSystemComparer comparer) + { + var otherField = (EcmaField)other; + + EcmaModule module = _type.EcmaModule; + EcmaModule otherModule = otherField._type.EcmaModule; + + int result = module.MetadataReader.GetToken(_handle) - otherModule.MetadataReader.GetToken(otherField._handle); + if (result != 0) + return result; + + return module.CompareTo(otherModule); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.cs new file mode 100644 index 00000000000..ee492d03de3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaField.cs @@ -0,0 +1,299 @@ +// 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 System.Reflection; +using System.Reflection.Metadata; +using System.Runtime.CompilerServices; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + public sealed partial class EcmaField : FieldDesc, EcmaModule.IEntityHandleObject + { + private static class FieldFlags + { + public const int BasicMetadataCache = 0x0001; + public const int Static = 0x0002; + public const int InitOnly = 0x0004; + public const int Literal = 0x0008; + public const int HasRva = 0x0010; + public const int NotSerialized = 0x0020; + + public const int AttributeMetadataCache = 0x0100; + public const int ThreadStatic = 0x0200; + public const int Intrinsic = 0x0400; + }; + + private EcmaType _type; + private FieldDefinitionHandle _handle; + + // Cached values + private ThreadSafeFlags _fieldFlags; + private TypeDesc _fieldType; + private string _name; + + internal EcmaField(EcmaType type, FieldDefinitionHandle handle) + { + _type = type; + _handle = handle; + +#if DEBUG + // Initialize name eagerly in debug builds for convenience + InitializeName(); +#endif + } + + EntityHandle EcmaModule.IEntityHandleObject.Handle + { + get + { + return _handle; + } + } + + + public override TypeSystemContext Context + { + get + { + return _type.Module.Context; + } + } + + public override DefType OwningType + { + get + { + return _type; + } + } + + public EcmaModule Module + { + get + { + return _type.EcmaModule; + } + } + + public MetadataReader MetadataReader + { + get + { + return _type.MetadataReader; + } + } + + public FieldDefinitionHandle Handle + { + get + { + return _handle; + } + } + + private TypeDesc InitializeFieldType() + { + var metadataReader = MetadataReader; + BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetFieldDefinition(_handle).Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader); + var fieldType = parser.ParseFieldSignature(); + return (_fieldType = fieldType); + } + + public override TypeDesc FieldType + { + get + { + if (_fieldType == null) + return InitializeFieldType(); + return _fieldType; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private int InitializeFieldFlags(int mask) + { + int flags = 0; + + if ((mask & FieldFlags.BasicMetadataCache) != 0) + { + var fieldAttributes = Attributes; + + if ((fieldAttributes & FieldAttributes.Static) != 0) + flags |= FieldFlags.Static; + + if ((fieldAttributes & FieldAttributes.InitOnly) != 0) + flags |= FieldFlags.InitOnly; + + if ((fieldAttributes & FieldAttributes.Literal) != 0) + flags |= FieldFlags.Literal; + + if ((fieldAttributes & FieldAttributes.HasFieldRVA) != 0) + flags |= FieldFlags.HasRva; + + if ((fieldAttributes & FieldAttributes.NotSerialized) != 0) + flags |= FieldFlags.NotSerialized; + + flags |= FieldFlags.BasicMetadataCache; + } + + // Fetching custom attribute based properties is more expensive, so keep that under + // a separate cache that might not be accessed very frequently. + if ((mask & FieldFlags.AttributeMetadataCache) != 0) + { + var metadataReader = this.MetadataReader; + var fieldDefinition = metadataReader.GetFieldDefinition(_handle); + + foreach (var attributeHandle in fieldDefinition.GetCustomAttributes()) + { + StringHandle namespaceHandle, nameHandle; + if (!metadataReader.GetAttributeNamespaceAndName(attributeHandle, out namespaceHandle, out nameHandle)) + continue; + + if (metadataReader.StringComparer.Equals(nameHandle, "ThreadStaticAttribute") + && metadataReader.StringComparer.Equals(namespaceHandle, "System")) + { + flags |= FieldFlags.ThreadStatic; + } + else if (metadataReader.StringComparer.Equals(nameHandle, "IntrinsicAttribute") + && metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices")) + { + flags |= FieldFlags.Intrinsic; + } + } + + flags |= FieldFlags.AttributeMetadataCache; + } + + Debug.Assert((flags & mask) != 0); + + _fieldFlags.AddFlags(flags); + + Debug.Assert((flags & mask) != 0); + return flags & mask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetFieldFlags(int mask) + { + int flags = _fieldFlags.Value & mask; + if (flags != 0) + return flags; + return InitializeFieldFlags(mask); + } + + public override bool IsStatic + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.Static) & FieldFlags.Static) != 0; + } + } + + public override bool IsThreadStatic + { + get + { + return IsStatic && + (GetFieldFlags(FieldFlags.AttributeMetadataCache | FieldFlags.ThreadStatic) & FieldFlags.ThreadStatic) != 0; + } + } + + public override bool IsInitOnly + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.InitOnly) & FieldFlags.InitOnly) != 0; + } + } + + public override bool HasRva + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.HasRva) & FieldFlags.HasRva) != 0; + } + } + + public override bool IsLiteral + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.Literal) & FieldFlags.Literal) != 0; + } + } + + public FieldAttributes Attributes + { + get + { + return MetadataReader.GetFieldDefinition(_handle).Attributes; + } + } + + private string InitializeName() + { + var metadataReader = MetadataReader; + var name = metadataReader.GetString(metadataReader.GetFieldDefinition(_handle).Name); + return (_name = name); + } + + public override string Name + { + get + { + if (_name == null) + return InitializeName(); + return _name; + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return !MetadataReader.GetCustomAttributeHandle(MetadataReader.GetFieldDefinition(_handle).GetCustomAttributes(), + attributeNamespace, attributeName).IsNil; + } + + public override MarshalAsDescriptor GetMarshalAsDescriptor() + { + MetadataReader reader = MetadataReader; + FieldDefinition definition = reader.GetFieldDefinition(_handle); + if ((definition.Attributes & FieldAttributes.HasFieldMarshal) != 0) + { + BlobReader marshalAsReader = reader.GetBlobReader(definition.GetMarshallingDescriptor()); + EcmaSignatureParser parser = new EcmaSignatureParser(_type.EcmaModule, marshalAsReader); + return parser.ParseMarshalAsDescriptor(); + } + + return null; + } + } + + public static class EcmaFieldExtensions + { + /// + /// Retrieves the data associated with an RVA mapped field from the PE module. + /// + public static byte[] GetFieldRvaData(this EcmaField field) + { + Debug.Assert(field.HasRva); + int addr = field.MetadataReader.GetFieldDefinition(field.Handle).GetRelativeVirtualAddress(); + var memBlock = field.Module.PEReader.GetSectionData(addr).GetContent(); + + int size = field.FieldType.GetElementSize().AsInt; + if (size > memBlock.Length) + throw new BadImageFormatException(); + + byte[] result = new byte[size]; + memBlock.CopyTo(0, result, 0, result.Length); + + return result; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs new file mode 100644 index 00000000000..2def7d24cf5 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs @@ -0,0 +1,26 @@ +// 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.Reflection.Metadata.Ecma335; + +namespace Internal.TypeSystem.Ecma +{ + public sealed partial class EcmaGenericParameter + { + public override string DiagnosticName + { + get + { + try + { + return Name; + } + catch + { + return $"GenericParam({MetadataReader.GetToken(Handle):x8})"; + } + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.Sorting.cs new file mode 100644 index 00000000000..b1c4bbce6e0 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.Sorting.cs @@ -0,0 +1,24 @@ +// 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.Reflection.Metadata.Ecma335; + +namespace Internal.TypeSystem.Ecma +{ + // Functionality related to determinstic ordering of types + partial class EcmaGenericParameter + { + protected internal override int ClassCode => -1548417824; + + protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + var otherType = (EcmaGenericParameter)other; + int result = _module.MetadataReader.GetToken(_handle) - otherType._module.MetadataReader.GetToken(otherType._handle); + if (result != 0) + return result; + + return _module.CompareTo(otherType._module); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.cs new file mode 100644 index 00000000000..28a43f0424c --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.cs @@ -0,0 +1,137 @@ +// 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.Collections.Generic; +using System.Reflection.Metadata; +using Internal.NativeFormat; + +using Debug = System.Diagnostics.Debug; +using GenericParameterAttributes = System.Reflection.GenericParameterAttributes; + +namespace Internal.TypeSystem.Ecma +{ + public sealed partial class EcmaGenericParameter : GenericParameterDesc + { + private EcmaModule _module; + private GenericParameterHandle _handle; + + internal EcmaGenericParameter(EcmaModule module, GenericParameterHandle handle) + { + _module = module; + _handle = handle; + } + + public GenericParameterHandle Handle + { + get + { + return _handle; + } + } + + public MetadataReader MetadataReader + { + get + { + return _module.MetadataReader; + } + } + + public EcmaModule Module + { + get + { + return _module; + } + } + + public override TypeSystemContext Context + { + get + { + return _module.Context; + } + } + + public override string Name + { + get + { + MetadataReader reader = _module.MetadataReader; + return reader.GetString(reader.GetGenericParameter(_handle).Name); + } + } + + public override GenericParameterKind Kind + { + get + { + GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle); + if (parameter.Parent.Kind == HandleKind.MethodDefinition) + { + return GenericParameterKind.Method; + } + else + { + Debug.Assert(parameter.Parent.Kind == HandleKind.TypeDefinition); + return GenericParameterKind.Type; + } + } + } + + public override int Index + { + get + { + GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle); + return parameter.Index; + } + } + + public override GenericVariance Variance + { + get + { + Debug.Assert((int)GenericVariance.Contravariant == (int)GenericParameterAttributes.Contravariant); + GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle); + return (GenericVariance)(parameter.Attributes & GenericParameterAttributes.VarianceMask); + } + } + + public override GenericConstraints Constraints + { + get + { + Debug.Assert((int)GenericConstraints.DefaultConstructorConstraint == (int)GenericParameterAttributes.DefaultConstructorConstraint); + GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle); + return (GenericConstraints)(parameter.Attributes & GenericParameterAttributes.SpecialConstraintMask); + } + } + + public override IEnumerable TypeConstraints + { + get + { + MetadataReader reader = _module.MetadataReader; + + GenericParameter parameter = reader.GetGenericParameter(_handle); + GenericParameterConstraintHandleCollection constraintHandles = parameter.GetConstraints(); + + if (constraintHandles.Count == 0) + return TypeDesc.EmptyTypes; + + TypeDesc[] constraintTypes = new TypeDesc[constraintHandles.Count]; + + for (int i = 0; i < constraintTypes.Length; i++) + { + GenericParameterConstraint constraint = reader.GetGenericParameterConstraint(constraintHandles[i]); + constraintTypes[i] = _module.GetType(constraint.Type); + }; + + return constraintTypes; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs new file mode 100644 index 00000000000..88ff3ca78c3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs @@ -0,0 +1,26 @@ +// 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.Reflection.Metadata.Ecma335; + +namespace Internal.TypeSystem.Ecma +{ + public sealed partial class EcmaMethod + { + public override string DiagnosticName + { + get + { + try + { + return Name; + } + catch + { + return $"MethodDef({MetadataReader.GetToken(Handle):x8})"; + } + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs new file mode 100644 index 00000000000..b9cfbda2859 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs @@ -0,0 +1,28 @@ +// 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.Reflection.Metadata.Ecma335; + +namespace Internal.TypeSystem.Ecma +{ + // Functionality related to deterministic ordering of types + partial class EcmaMethod + { + protected internal override int ClassCode => 1419431046; + + protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) + { + var otherMethod = (EcmaMethod)other; + + EcmaModule module = _type.EcmaModule; + EcmaModule otherModule = otherMethod._type.EcmaModule; + + int result = module.MetadataReader.GetToken(_handle) - otherModule.MetadataReader.GetToken(otherMethod._handle); + if (result != 0) + return result; + + return module.CompareTo(otherModule); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.cs new file mode 100644 index 00000000000..6d1aa8a59bc --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.cs @@ -0,0 +1,585 @@ +// 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; +using System.Runtime.CompilerServices; +using System.Reflection; +using System.Reflection.Metadata; +using System.Threading; + +namespace Internal.TypeSystem.Ecma +{ + public sealed partial class EcmaMethod : MethodDesc, EcmaModule.IEntityHandleObject + { + private static class MethodFlags + { + public const int BasicMetadataCache = 0x00001; + public const int Virtual = 0x00002; + public const int NewSlot = 0x00004; + public const int Abstract = 0x00008; + public const int Final = 0x00010; + public const int NoInlining = 0x00020; + public const int AggressiveInlining = 0x00040; + public const int RuntimeImplemented = 0x00080; + public const int InternalCall = 0x00100; + public const int Synchronized = 0x00200; + public const int AggressiveOptimization = 0x00400; + public const int NoOptimization = 0x00800; + public const int RequireSecObject = 0x01000; + + public const int AttributeMetadataCache = 0x02000; + public const int Intrinsic = 0x04000; + public const int NativeCallable = 0x08000; + public const int RuntimeExport = 0x10000; + }; + + private EcmaType _type; + private MethodDefinitionHandle _handle; + + // Cached values + private ThreadSafeFlags _methodFlags; + private MethodSignature _signature; + private string _name; + private TypeDesc[] _genericParameters; // TODO: Optional field? + + internal EcmaMethod(EcmaType type, MethodDefinitionHandle handle) + { + _type = type; + _handle = handle; + +#if DEBUG + // Initialize name eagerly in debug builds for convenience + InitializeName(); +#endif + } + + EntityHandle EcmaModule.IEntityHandleObject.Handle + { + get + { + return _handle; + } + } + + public override TypeSystemContext Context + { + get + { + return _type.Module.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _type; + } + } + + private MethodSignature InitializeSignature() + { + var metadataReader = MetadataReader; + BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetMethodDefinition(_handle).Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader); + var signature = parser.ParseMethodSignature(); + return (_signature = signature); + } + + public override MethodSignature Signature + { + get + { + if (_signature == null) + return InitializeSignature(); + return _signature; + } + } + + public EcmaModule Module + { + get + { + return _type.EcmaModule; + } + } + + public MetadataReader MetadataReader + { + get + { + return _type.MetadataReader; + } + } + + public MethodDefinitionHandle Handle + { + get + { + return _handle; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private int InitializeMethodFlags(int mask) + { + int flags = 0; + + if ((mask & MethodFlags.BasicMetadataCache) != 0) + { + var methodAttributes = Attributes; + var methodImplAttributes = ImplAttributes; + + if ((methodAttributes & MethodAttributes.Virtual) != 0) + flags |= MethodFlags.Virtual; + + if ((methodAttributes & MethodAttributes.NewSlot) != 0) + flags |= MethodFlags.NewSlot; + + if ((methodAttributes & MethodAttributes.Abstract) != 0) + flags |= MethodFlags.Abstract; + + if ((methodAttributes & MethodAttributes.Final) != 0) + flags |= MethodFlags.Final; + + if ((methodAttributes & MethodAttributes.RequireSecObject) != 0) + flags |= MethodFlags.RequireSecObject; + + if ((methodImplAttributes & MethodImplAttributes.NoInlining) != 0) + flags |= MethodFlags.NoInlining; + + // System.Reflection.Primitives we build against doesn't define AggressiveOptimization + const MethodImplAttributes MethodImplAttributes_AggressiveOptimization = (MethodImplAttributes)0x0200; + + // No optimization bit beats aggressive optimization bit (CLR compatible behavior) + if ((methodImplAttributes & MethodImplAttributes.NoOptimization) != 0) + flags |= MethodFlags.NoOptimization; + else if ((methodImplAttributes & MethodImplAttributes_AggressiveOptimization) != 0) + flags |= MethodFlags.AggressiveOptimization; + + if ((methodImplAttributes & MethodImplAttributes.AggressiveInlining) != 0) + flags |= MethodFlags.AggressiveInlining; + + if ((methodImplAttributes & MethodImplAttributes.Runtime) != 0) + flags |= MethodFlags.RuntimeImplemented; + + if ((methodImplAttributes & MethodImplAttributes.InternalCall) != 0) + flags |= MethodFlags.InternalCall; + + if ((methodImplAttributes & MethodImplAttributes.Synchronized) != 0) + flags |= MethodFlags.Synchronized; + + flags |= MethodFlags.BasicMetadataCache; + } + + // Fetching custom attribute based properties is more expensive, so keep that under + // a separate cache that might not be accessed very frequently. + if ((mask & MethodFlags.AttributeMetadataCache) != 0) + { + var metadataReader = this.MetadataReader; + var methodDefinition = metadataReader.GetMethodDefinition(_handle); + + foreach (var attributeHandle in methodDefinition.GetCustomAttributes()) + { + StringHandle namespaceHandle, nameHandle; + if (!metadataReader.GetAttributeNamespaceAndName(attributeHandle, out namespaceHandle, out nameHandle)) + continue; + + if (metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices")) + { + if (metadataReader.StringComparer.Equals(nameHandle, "IntrinsicAttribute")) + { + flags |= MethodFlags.Intrinsic; + } + } + else + if (metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime.InteropServices")) + { + if (metadataReader.StringComparer.Equals(nameHandle, "NativeCallableAttribute")) + { + flags |= MethodFlags.NativeCallable; + } + } + else + if (metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime")) + { + if (metadataReader.StringComparer.Equals(nameHandle, "RuntimeExportAttribute")) + { + flags |= MethodFlags.RuntimeExport; + } + } + } + + flags |= MethodFlags.AttributeMetadataCache; + } + + Debug.Assert((flags & mask) != 0); + _methodFlags.AddFlags(flags); + + return flags & mask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetMethodFlags(int mask) + { + int flags = _methodFlags.Value & mask; + if (flags != 0) + return flags; + return InitializeMethodFlags(mask); + } + + public override bool IsVirtual + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Virtual) & MethodFlags.Virtual) != 0; + } + } + + public override bool IsNewSlot + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NewSlot) & MethodFlags.NewSlot) != 0; + } + } + + public override bool IsAbstract + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Abstract) & MethodFlags.Abstract) != 0; + } + } + + public override bool IsFinal + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Final) & MethodFlags.Final) != 0; + } + } + + public override bool IsNoInlining + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NoInlining) & MethodFlags.NoInlining) != 0; + } + } + + public override bool RequireSecObject + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.RequireSecObject) & MethodFlags.RequireSecObject) != 0; + } + } + + public override bool IsAggressiveOptimization + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.AggressiveOptimization) & MethodFlags.AggressiveOptimization) != 0; + } + } + + public override bool IsNoOptimization + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NoOptimization) & MethodFlags.NoOptimization) != 0; + } + } + + public override bool IsAggressiveInlining + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.AggressiveInlining) & MethodFlags.AggressiveInlining) != 0; + } + } + + public override bool IsRuntimeImplemented + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.RuntimeImplemented) & MethodFlags.RuntimeImplemented) != 0; + } + } + + public override bool IsIntrinsic + { + get + { + return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.Intrinsic) & MethodFlags.Intrinsic) != 0; + } + } + + public override bool IsInternalCall + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.InternalCall) & MethodFlags.InternalCall) != 0; + } + } + + public override bool IsSynchronized + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Synchronized) & MethodFlags.Synchronized) != 0; + } + } + + public override bool IsNativeCallable + { + get + { + return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.NativeCallable) & MethodFlags.NativeCallable) != 0; + } + } + + public override bool IsRuntimeExport + { + get + { + return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.RuntimeExport) & MethodFlags.RuntimeExport) != 0; + } + } + + public override bool IsSpecialName + { + get + { + return (Attributes & MethodAttributes.SpecialName) != 0; + } + } + + public override bool IsDefaultConstructor + { + get + { + MethodAttributes attributes = Attributes; + return attributes.IsRuntimeSpecialName() + && attributes.IsPublic() + && Signature.Length == 0 + && Name == ".ctor" + && !_type.IsAbstract; + } + } + + public MethodAttributes Attributes + { + get + { + return MetadataReader.GetMethodDefinition(_handle).Attributes; + } + } + + public MethodImplAttributes ImplAttributes + { + get + { + return MetadataReader.GetMethodDefinition(_handle).ImplAttributes; + } + } + + private string InitializeName() + { + var metadataReader = MetadataReader; + var name = metadataReader.GetString(metadataReader.GetMethodDefinition(_handle).Name); + return (_name = name); + } + + public override string Name + { + get + { + if (_name == null) + return InitializeName(); + return _name; + } + } + + private void ComputeGenericParameters() + { + var genericParameterHandles = MetadataReader.GetMethodDefinition(_handle).GetGenericParameters(); + int count = genericParameterHandles.Count; + if (count > 0) + { + TypeDesc[] genericParameters = new TypeDesc[count]; + int i = 0; + foreach (var genericParameterHandle in genericParameterHandles) + { + genericParameters[i++] = new EcmaGenericParameter(Module, genericParameterHandle); + } + Interlocked.CompareExchange(ref _genericParameters, genericParameters, null); + } + else + { + _genericParameters = TypeDesc.EmptyTypes; + } + } + + public override Instantiation Instantiation + { + get + { + if (_genericParameters == null) + ComputeGenericParameters(); + return new Instantiation(_genericParameters); + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return !MetadataReader.GetCustomAttributeHandle(MetadataReader.GetMethodDefinition(_handle).GetCustomAttributes(), + attributeNamespace, attributeName).IsNil; + } + + public override bool IsPInvoke + { + get + { + return (((int)Attributes & (int)MethodAttributes.PinvokeImpl) != 0); + } + } + + public override PInvokeMetadata GetPInvokeMethodMetadata() + { + if (!IsPInvoke) + return default(PInvokeMetadata); + + MetadataReader metadataReader = MetadataReader; + MethodDefinition methodDef = metadataReader.GetMethodDefinition(_handle); + MethodImport import = methodDef.GetImport(); + string name = metadataReader.GetString(import.Name); + + ModuleReference moduleRef = metadataReader.GetModuleReference(import.Module); + string moduleName = metadataReader.GetString(moduleRef.Name); + + MethodImportAttributes importAttributes = import.Attributes; + + // If either BestFitMapping or ThrowOnUnmappable wasn't set on the p/invoke, + // look for the value in the owning type or assembly. + if ((importAttributes & MethodImportAttributes.BestFitMappingMask) == 0 || + (importAttributes & MethodImportAttributes.ThrowOnUnmappableCharMask) == 0) + { + TypeDefinition declaringType = metadataReader.GetTypeDefinition(methodDef.GetDeclaringType()); + + // Start with owning type + MethodImportAttributes fromCA = GetImportAttributesFromBestFitMappingAttribute(declaringType.GetCustomAttributes()); + if ((importAttributes & MethodImportAttributes.BestFitMappingMask) == 0) + importAttributes |= fromCA & MethodImportAttributes.BestFitMappingMask; + if ((importAttributes & MethodImportAttributes.ThrowOnUnmappableCharMask) == 0) + importAttributes |= fromCA & MethodImportAttributes.ThrowOnUnmappableCharMask; + + // If we still don't know, check the assembly + if ((importAttributes & MethodImportAttributes.BestFitMappingMask) == 0 || + (importAttributes & MethodImportAttributes.ThrowOnUnmappableCharMask) == 0) + { + fromCA = GetImportAttributesFromBestFitMappingAttribute(metadataReader.GetAssemblyDefinition().GetCustomAttributes()); + if ((importAttributes & MethodImportAttributes.BestFitMappingMask) == 0) + importAttributes |= fromCA & MethodImportAttributes.BestFitMappingMask; + if ((importAttributes & MethodImportAttributes.ThrowOnUnmappableCharMask) == 0) + importAttributes |= fromCA & MethodImportAttributes.ThrowOnUnmappableCharMask; + } + } + + // Spot check the enums match + Debug.Assert((int)MethodImportAttributes.CallingConventionStdCall == (int)PInvokeAttributes.CallingConventionStdCall); + Debug.Assert((int)MethodImportAttributes.CharSetAuto == (int)PInvokeAttributes.CharSetAuto); + Debug.Assert((int)MethodImportAttributes.CharSetUnicode == (int)PInvokeAttributes.CharSetUnicode); + Debug.Assert((int)MethodImportAttributes.SetLastError == (int)PInvokeAttributes.SetLastError); + + PInvokeAttributes attributes = (PInvokeAttributes)importAttributes; + + if ((ImplAttributes & MethodImplAttributes.PreserveSig) != 0) + attributes |= PInvokeAttributes.PreserveSig; + + return new PInvokeMetadata(moduleName, name, attributes); + } + + private MethodImportAttributes GetImportAttributesFromBestFitMappingAttribute(CustomAttributeHandleCollection attributeHandles) + { + // Look for the [BestFitMapping(BestFitMapping: x, ThrowOnUnmappableChar = y)] attribute and + // translate that to MethodImportAttributes + + MethodImportAttributes result = 0; + MetadataReader reader = MetadataReader; + + CustomAttributeHandle attributeHandle = reader.GetCustomAttributeHandle( + attributeHandles, "System.Runtime.InteropServices", "BestFitMappingAttribute"); + if (!attributeHandle.IsNil) + { + CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); + CustomAttributeValue decoded = attribute.DecodeValue( + new CustomAttributeTypeProvider(_type.EcmaModule)); + + if (decoded.FixedArguments.Length != 1 || !(decoded.FixedArguments[0].Value is bool)) + ThrowHelper.ThrowBadImageFormatException(); + if ((bool)decoded.FixedArguments[0].Value) + result |= MethodImportAttributes.BestFitMappingEnable; + else + result |= MethodImportAttributes.BestFitMappingDisable; + + foreach (CustomAttributeNamedArgument namedArg in decoded.NamedArguments) + { + if (namedArg.Name == "ThrowOnUnmappableChar") + { + if (!(namedArg.Value is bool)) + ThrowHelper.ThrowBadImageFormatException(); + if ((bool)namedArg.Value) + result |= MethodImportAttributes.ThrowOnUnmappableCharEnable; + else + result |= MethodImportAttributes.ThrowOnUnmappableCharDisable; + break; + } + } + } + + return result; + } + + public override ParameterMetadata[] GetParameterMetadata() + { + MetadataReader metadataReader = MetadataReader; + + // Spot check the enums match + Debug.Assert((int)ParameterAttributes.In == (int)ParameterMetadataAttributes.In); + Debug.Assert((int)ParameterAttributes.Out == (int)ParameterMetadataAttributes.Out); + Debug.Assert((int)ParameterAttributes.Optional == (int)ParameterMetadataAttributes.Optional); + Debug.Assert((int)ParameterAttributes.HasDefault == (int)ParameterMetadataAttributes.HasDefault); + Debug.Assert((int)ParameterAttributes.HasFieldMarshal == (int)ParameterMetadataAttributes.HasFieldMarshal); + + ParameterHandleCollection parameterHandles = metadataReader.GetMethodDefinition(_handle).GetParameters(); + ParameterMetadata[] parameterMetadataArray = new ParameterMetadata[parameterHandles.Count]; + int index = 0; + foreach (ParameterHandle parameterHandle in parameterHandles) + { + Parameter parameter = metadataReader.GetParameter(parameterHandle); + MarshalAsDescriptor marshalAsDescriptor = GetMarshalAsDescriptor(parameter); + ParameterMetadata data = new ParameterMetadata(parameter.SequenceNumber, (ParameterMetadataAttributes)parameter.Attributes, marshalAsDescriptor); + parameterMetadataArray[index++] = data; + } + return parameterMetadataArray; + } + + private MarshalAsDescriptor GetMarshalAsDescriptor(Parameter parameter) + { + if ((parameter.Attributes & ParameterAttributes.HasFieldMarshal) == ParameterAttributes.HasFieldMarshal) + { + MetadataReader metadataReader = MetadataReader; + BlobReader marshalAsReader = metadataReader.GetBlobReader(parameter.GetMarshallingDescriptor()); + EcmaSignatureParser parser = new EcmaSignatureParser(Module, marshalAsReader); + MarshalAsDescriptor marshalAs = parser.ParseMarshalAsDescriptor(); + Debug.Assert(marshalAs != null); + return marshalAs; + } + return null; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.Sorting.cs new file mode 100644 index 00000000000..3549c767ffa --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.Sorting.cs @@ -0,0 +1,25 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem.Ecma +{ + partial class EcmaModule + { + public int CompareTo(EcmaModule other) + { + if (this == other) + return 0; + + Guid thisMvid = _metadataReader.GetGuid(_metadataReader.GetModuleDefinition().Mvid); + Guid otherMvid = other._metadataReader.GetGuid(other.MetadataReader.GetModuleDefinition().Mvid); + + Debug.Assert(thisMvid.CompareTo(otherMvid) != 0, "Different instance of EcmaModule but same MVID?"); + return thisMvid.CompareTo(otherMvid); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.Symbols.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.Symbols.cs new file mode 100644 index 00000000000..5b6d3b732f1 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.Symbols.cs @@ -0,0 +1,34 @@ +// 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.Reflection.Metadata; +using System.Reflection.PortableExecutable; + +namespace Internal.TypeSystem.Ecma +{ + // Pluggable file that adds PDB handling functionality to EcmaModule + partial class EcmaModule + { + public PdbSymbolReader PdbReader + { + get; + } + + internal EcmaModule(TypeSystemContext context, PEReader peReader, MetadataReader metadataReader, IAssemblyDesc containingAssembly, PdbSymbolReader pdbReader) + : this(context, peReader, metadataReader, containingAssembly) + { + PdbReader = pdbReader; + } + + public static EcmaModule Create(TypeSystemContext context, PEReader peReader, IAssemblyDesc containingAssembly, PdbSymbolReader pdbReader) + { + MetadataReader metadataReader = CreateMetadataReader(context, peReader); + + if (containingAssembly == null) + return new EcmaAssembly(context, peReader, metadataReader, pdbReader); + else + return new EcmaModule(context, peReader, metadataReader, containingAssembly, pdbReader); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.cs new file mode 100644 index 00000000000..9f9705c7e2c --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaModule.cs @@ -0,0 +1,553 @@ +// 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.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; + +namespace Internal.TypeSystem.Ecma +{ + public partial class EcmaModule : ModuleDesc + { + private PEReader _peReader; + protected MetadataReader _metadataReader; + + internal interface IEntityHandleObject + { + EntityHandle Handle + { + get; + } + } + + private sealed class EcmaObjectLookupWrapper : IEntityHandleObject + { + private EntityHandle _handle; + private object _obj; + + public EcmaObjectLookupWrapper(EntityHandle handle, object obj) + { + _obj = obj; + _handle = handle; + } + + public EntityHandle Handle + { + get + { + return _handle; + } + } + + public object Object + { + get + { + return _obj; + } + } + } + + internal class EcmaObjectLookupHashtable : LockFreeReaderHashtable + { + private EcmaModule _module; + + public EcmaObjectLookupHashtable(EcmaModule module) + { + _module = module; + } + + protected override int GetKeyHashCode(EntityHandle key) + { + return key.GetHashCode(); + } + + protected override int GetValueHashCode(IEntityHandleObject value) + { + return value.Handle.GetHashCode(); + } + + protected override bool CompareKeyToValue(EntityHandle key, IEntityHandleObject value) + { + return key.Equals(value.Handle); + } + + protected override bool CompareValueToValue(IEntityHandleObject value1, IEntityHandleObject value2) + { + if (Object.ReferenceEquals(value1, value2)) + return true; + else + return value1.Handle.Equals(value2.Handle); + } + + protected override IEntityHandleObject CreateValueFromKey(EntityHandle handle) + { + object item; + switch (handle.Kind) + { + case HandleKind.TypeDefinition: + item = new EcmaType(_module, (TypeDefinitionHandle)handle); + break; + + case HandleKind.MethodDefinition: + { + MethodDefinitionHandle methodDefinitionHandle = (MethodDefinitionHandle)handle; + TypeDefinitionHandle typeDefinitionHandle = _module._metadataReader.GetMethodDefinition(methodDefinitionHandle).GetDeclaringType(); + EcmaType type = (EcmaType)_module.GetObject(typeDefinitionHandle); + item = new EcmaMethod(type, methodDefinitionHandle); + } + break; + + case HandleKind.FieldDefinition: + { + FieldDefinitionHandle fieldDefinitionHandle = (FieldDefinitionHandle)handle; + TypeDefinitionHandle typeDefinitionHandle = _module._metadataReader.GetFieldDefinition(fieldDefinitionHandle).GetDeclaringType(); + EcmaType type = (EcmaType)_module.GetObject(typeDefinitionHandle); + item = new EcmaField(type, fieldDefinitionHandle); + } + break; + + case HandleKind.TypeReference: + item = _module.ResolveTypeReference((TypeReferenceHandle)handle); + break; + + case HandleKind.MemberReference: + item = _module.ResolveMemberReference((MemberReferenceHandle)handle); + break; + + case HandleKind.AssemblyReference: + item = _module.ResolveAssemblyReference((AssemblyReferenceHandle)handle); + break; + + case HandleKind.TypeSpecification: + item = _module.ResolveTypeSpecification((TypeSpecificationHandle)handle); + break; + + case HandleKind.MethodSpecification: + item = _module.ResolveMethodSpecification((MethodSpecificationHandle)handle); + break; + + case HandleKind.ExportedType: + item = _module.ResolveExportedType((ExportedTypeHandle)handle); + break; + + case HandleKind.StandaloneSignature: + item = _module.ResolveStandaloneSignature((StandaloneSignatureHandle)handle); + break; + + case HandleKind.ModuleDefinition: + // ECMA-335 Partition 2 II.22.38 1d: This should not occur in a CLI ("compressed metadata") module, + // but resolves to "current module". + item = _module; + break; + + case HandleKind.ModuleReference: + item = _module.ResolveModuleReference((ModuleReferenceHandle)handle); + break; + + default: + throw new BadImageFormatException("Unknown metadata token type: " + handle.Kind); + } + + switch (handle.Kind) + { + case HandleKind.TypeDefinition: + case HandleKind.MethodDefinition: + case HandleKind.FieldDefinition: + // type/method/field definitions directly correspond to their target item. + return (IEntityHandleObject)item; + default: + // Everything else is some form of reference which cannot be self-describing + return new EcmaObjectLookupWrapper(handle, item); + } + } + } + + private object ResolveModuleReference(ModuleReferenceHandle handle) + { + ModuleReference moduleReference = _metadataReader.GetModuleReference(handle); + string fileName = _metadataReader.GetString(moduleReference.Name); + return Context.ResolveModule(this.Assembly, fileName); + } + + private LockFreeReaderHashtable _resolvedTokens; + + internal EcmaModule(TypeSystemContext context, PEReader peReader, MetadataReader metadataReader, IAssemblyDesc containingAssembly) + : base(context, containingAssembly) + { + _peReader = peReader; + _metadataReader = metadataReader; + _resolvedTokens = new EcmaObjectLookupHashtable(this); + } + + public static EcmaModule Create(TypeSystemContext context, PEReader peReader, IAssemblyDesc containingAssembly) + { + MetadataReader metadataReader = CreateMetadataReader(context, peReader); + + if (containingAssembly == null) + return new EcmaAssembly(context, peReader, metadataReader); + else + return new EcmaModule(context, peReader, metadataReader, containingAssembly); + } + + private static MetadataReader CreateMetadataReader(TypeSystemContext context, PEReader peReader) + { + if (!peReader.HasMetadata) + { + ThrowHelper.ThrowBadImageFormatException(); + } + + var stringDecoderProvider = context as IMetadataStringDecoderProvider; + + MetadataReader metadataReader = peReader.GetMetadataReader(MetadataReaderOptions.None /* MetadataReaderOptions.ApplyWindowsRuntimeProjections */, + (stringDecoderProvider != null) ? stringDecoderProvider.GetMetadataStringDecoder() : null); + + return metadataReader; + } + + public PEReader PEReader + { + get + { + return _peReader; + } + } + + public MetadataReader MetadataReader + { + get + { + return _metadataReader; + } + } + + /// + /// Gets the managed entrypoint method of this module or null if the module has no managed entrypoint. + /// + public MethodDesc EntryPoint + { + get + { + CorHeader corHeader = _peReader.PEHeaders.CorHeader; + if ((corHeader.Flags & CorFlags.NativeEntryPoint) != 0) + { + // Entrypoint is an RVA to an unmanaged method + return null; + } + + int entryPointToken = corHeader.EntryPointTokenOrRelativeVirtualAddress; + if (entryPointToken == 0) + { + // No entrypoint + return null; + } + + EntityHandle handle = MetadataTokens.EntityHandle(entryPointToken); + + if (handle.Kind == HandleKind.MethodDefinition) + { + return GetMethod(handle); + } + else if (handle.Kind == HandleKind.AssemblyFile) + { + // Entrypoint not in the manifest assembly + throw new NotImplementedException(); + } + + // Bad metadata + throw new BadImageFormatException(); + } + } + + public sealed override MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true) + { + var stringComparer = _metadataReader.StringComparer; + + // TODO: More efficient implementation? + foreach (var typeDefinitionHandle in _metadataReader.TypeDefinitions) + { + var typeDefinition = _metadataReader.GetTypeDefinition(typeDefinitionHandle); + if (stringComparer.Equals(typeDefinition.Name, name) && + stringComparer.Equals(typeDefinition.Namespace, nameSpace)) + { + return (MetadataType)GetType((EntityHandle)typeDefinitionHandle); + } + } + + foreach (var exportedTypeHandle in _metadataReader.ExportedTypes) + { + var exportedType = _metadataReader.GetExportedType(exportedTypeHandle); + if (stringComparer.Equals(exportedType.Name, name) && + stringComparer.Equals(exportedType.Namespace, nameSpace)) + { + if (exportedType.IsForwarder) + { + Object implementation = GetObject(exportedType.Implementation); + + if (implementation is ModuleDesc) + { + return ((ModuleDesc)(implementation)).GetType(nameSpace, name); + } + + // TODO + throw new NotImplementedException(); + } + // TODO: + throw new NotImplementedException(); + } + } + + if (throwIfNotFound) + ThrowHelper.ThrowTypeLoadException(nameSpace, name, this); + + return null; + } + + public TypeDesc GetType(EntityHandle handle) + { + TypeDesc type = GetObject(handle) as TypeDesc; + if (type == null) + throw new BadImageFormatException("Type expected"); + return type; + } + + public MethodDesc GetMethod(EntityHandle handle) + { + MethodDesc method = GetObject(handle) as MethodDesc; + if (method == null) + throw new BadImageFormatException("Method expected"); + return method; + } + + public FieldDesc GetField(EntityHandle handle) + { + FieldDesc field = GetObject(handle) as FieldDesc; + if (field == null) + throw new BadImageFormatException("Field expected"); + return field; + } + + public Object GetObject(EntityHandle handle) + { + IEntityHandleObject obj = _resolvedTokens.GetOrCreateValue(handle); + if (obj is EcmaObjectLookupWrapper) + { + return ((EcmaObjectLookupWrapper)obj).Object; + } + else + { + return obj; + } + } + + private Object ResolveMethodSpecification(MethodSpecificationHandle handle) + { + MethodSpecification methodSpecification = _metadataReader.GetMethodSpecification(handle); + + MethodDesc methodDef = GetMethod(methodSpecification.Method); + + BlobReader signatureReader = _metadataReader.GetBlobReader(methodSpecification.Signature); + EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); + + TypeDesc[] instantiation = parser.ParseMethodSpecSignature(); + return Context.GetInstantiatedMethod(methodDef, new Instantiation(instantiation)); + } + + private Object ResolveStandaloneSignature(StandaloneSignatureHandle handle) + { + StandaloneSignature signature = _metadataReader.GetStandaloneSignature(handle); + BlobReader signatureReader = _metadataReader.GetBlobReader(signature.Signature); + EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); + + MethodSignature methodSig = parser.ParseMethodSignature(); + return methodSig; + } + + private Object ResolveTypeSpecification(TypeSpecificationHandle handle) + { + TypeSpecification typeSpecification = _metadataReader.GetTypeSpecification(handle); + + BlobReader signatureReader = _metadataReader.GetBlobReader(typeSpecification.Signature); + EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); + + return parser.ParseType(); + } + + private Object ResolveMemberReference(MemberReferenceHandle handle) + { + MemberReference memberReference = _metadataReader.GetMemberReference(handle); + + Object parent = GetObject(memberReference.Parent); + + TypeDesc parentTypeDesc = parent as TypeDesc; + if (parentTypeDesc != null) + { + BlobReader signatureReader = _metadataReader.GetBlobReader(memberReference.Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); + + string name = _metadataReader.GetString(memberReference.Name); + + if (parser.IsFieldSignature) + { + FieldDesc field = parentTypeDesc.GetField(name); + if (field != null) + return field; + + ThrowHelper.ThrowMissingFieldException(parentTypeDesc, name); + } + else + { + MethodSignature sig = parser.ParseMethodSignature(); + TypeDesc typeDescToInspect = parentTypeDesc; + + // Try to resolve the name and signature in the current type, or any of the base types. + do + { + // TODO: handle substitutions + MethodDesc method = typeDescToInspect.GetMethod(name, sig); + if (method != null) + { + // If this resolved to one of the base types, make sure it's not a constructor. + // Instance constructors are not inherited. + if (typeDescToInspect != parentTypeDesc && method.IsConstructor) + break; + + return method; + } + typeDescToInspect = typeDescToInspect.BaseType; + } while (typeDescToInspect != null); + + ThrowHelper.ThrowMissingMethodException(parentTypeDesc, name, sig); + } + } + else if (parent is MethodDesc) + { + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramVararg, (MethodDesc)parent); + } + else if (parent is ModuleDesc) + { + throw new NotImplementedException("MemberRef to a global function or variable."); + } + + throw new BadImageFormatException(); + } + + private Object ResolveTypeReference(TypeReferenceHandle handle) + { + TypeReference typeReference = _metadataReader.GetTypeReference(handle); + + Object resolutionScope = GetObject(typeReference.ResolutionScope); + + if (resolutionScope is ModuleDesc) + { + return ((ModuleDesc)(resolutionScope)).GetType(_metadataReader.GetString(typeReference.Namespace), _metadataReader.GetString(typeReference.Name)); + } + else + if (resolutionScope is MetadataType) + { + string typeName = _metadataReader.GetString(typeReference.Name); + if (!typeReference.Namespace.IsNil) + typeName = _metadataReader.GetString(typeReference.Namespace) + "." + typeName; + MetadataType result = ((MetadataType)(resolutionScope)).GetNestedType(typeName); + if (result != null) + return result; + + ThrowHelper.ThrowTypeLoadException(typeName, ((MetadataType)resolutionScope).Module); + } + + // TODO + throw new NotImplementedException(); + } + + private Object ResolveAssemblyReference(AssemblyReferenceHandle handle) + { + AssemblyReference assemblyReference = _metadataReader.GetAssemblyReference(handle); + + AssemblyName an = new AssemblyName(); + an.Name = _metadataReader.GetString(assemblyReference.Name); + an.Version = assemblyReference.Version; + + var publicKeyOrToken = _metadataReader.GetBlobBytes(assemblyReference.PublicKeyOrToken); + if ((assemblyReference.Flags & AssemblyFlags.PublicKey) != 0) + { + an.SetPublicKey(publicKeyOrToken); + } + else + { + an.SetPublicKeyToken(publicKeyOrToken); + } + + an.CultureName = _metadataReader.GetString(assemblyReference.Culture); + an.ContentType = GetContentTypeFromAssemblyFlags(assemblyReference.Flags); + + return Context.ResolveAssembly(an); + } + + private Object ResolveExportedType(ExportedTypeHandle handle) + { + ExportedType exportedType = _metadataReader.GetExportedType(handle); + + var implementation = GetObject(exportedType.Implementation); + if (implementation is ModuleDesc) + { + var module = (ModuleDesc)implementation; + string nameSpace = _metadataReader.GetString(exportedType.Namespace); + string name = _metadataReader.GetString(exportedType.Name); + return module.GetType(nameSpace, name); + } + else + if (implementation is MetadataType) + { + var type = (MetadataType)implementation; + string name = _metadataReader.GetString(exportedType.Name); + var nestedType = type.GetNestedType(name); + if (nestedType == null) + ThrowHelper.ThrowTypeLoadException(name, this); + return nestedType; + } + else + { + throw new BadImageFormatException("Unknown metadata token type for exported type"); + } + } + + public sealed override IEnumerable GetAllTypes() + { + foreach (var typeDefinitionHandle in _metadataReader.TypeDefinitions) + { + yield return (MetadataType)GetType(typeDefinitionHandle); + } + } + + public sealed override MetadataType GetGlobalModuleType() + { + int typeDefinitionsCount = _metadataReader.TypeDefinitions.Count; + if (typeDefinitionsCount == 0) + return null; + + return (MetadataType)GetType(MetadataTokens.EntityHandle(0x02000001 /* COR_GLOBAL_PARENT_TOKEN */)); + } + + protected static AssemblyContentType GetContentTypeFromAssemblyFlags(AssemblyFlags flags) + { + return (AssemblyContentType)(((int)flags & 0x0E00) >> 9); + } + + public string GetUserString(UserStringHandle userStringHandle) + { + // String literals are not cached + return _metadataReader.GetUserString(userStringHandle); + } + + public override string ToString() + { + ModuleDefinition moduleDefinition = _metadataReader.GetModuleDefinition(); + return _metadataReader.GetString(moduleDefinition.Name); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs new file mode 100644 index 00000000000..c4bfbfda8fb --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs @@ -0,0 +1,499 @@ +// 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.Reflection.Metadata; +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Linq; + +using Internal.TypeSystem; +using System.Collections.Generic; + +namespace Internal.TypeSystem.Ecma +{ + public struct EcmaSignatureParser + { + private EcmaModule _module; + private BlobReader _reader; + + private Stack _indexStack; + private List _embeddedSignatureDataList; + + + public EcmaSignatureParser(EcmaModule module, BlobReader reader) + { + _module = module; + _reader = reader; + _indexStack = null; + _embeddedSignatureDataList = null; + } + + private TypeDesc GetWellKnownType(WellKnownType wellKnownType) + { + return _module.Context.GetWellKnownType(wellKnownType); + } + + private TypeDesc ParseType(SignatureTypeCode typeCode) + { + + if (_indexStack != null) + { + int was = _indexStack.Pop(); + _indexStack.Push(was + 1); + _indexStack.Push(0); + } + TypeDesc result = ParseTypeImpl(typeCode); + if (_indexStack != null) + { + _indexStack.Pop(); + } + return result; + } + + private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode) + { + // Switch on the type. + switch (typeCode) + { + case SignatureTypeCode.Void: + return GetWellKnownType(WellKnownType.Void); + case SignatureTypeCode.Boolean: + return GetWellKnownType(WellKnownType.Boolean); + case SignatureTypeCode.SByte: + return GetWellKnownType(WellKnownType.SByte); + case SignatureTypeCode.Byte: + return GetWellKnownType(WellKnownType.Byte); + case SignatureTypeCode.Int16: + return GetWellKnownType(WellKnownType.Int16); + case SignatureTypeCode.UInt16: + return GetWellKnownType(WellKnownType.UInt16); + case SignatureTypeCode.Int32: + return GetWellKnownType(WellKnownType.Int32); + case SignatureTypeCode.UInt32: + return GetWellKnownType(WellKnownType.UInt32); + case SignatureTypeCode.Int64: + return GetWellKnownType(WellKnownType.Int64); + case SignatureTypeCode.UInt64: + return GetWellKnownType(WellKnownType.UInt64); + case SignatureTypeCode.Single: + return GetWellKnownType(WellKnownType.Single); + case SignatureTypeCode.Double: + return GetWellKnownType(WellKnownType.Double); + case SignatureTypeCode.Char: + return GetWellKnownType(WellKnownType.Char); + case SignatureTypeCode.String: + return GetWellKnownType(WellKnownType.String); + case SignatureTypeCode.IntPtr: + return GetWellKnownType(WellKnownType.IntPtr); + case SignatureTypeCode.UIntPtr: + return GetWellKnownType(WellKnownType.UIntPtr); + case SignatureTypeCode.Object: + return GetWellKnownType(WellKnownType.Object); + case SignatureTypeCode.TypeHandle: + return _module.GetType(_reader.ReadTypeHandle()); + case SignatureTypeCode.SZArray: + return _module.Context.GetArrayType(ParseType()); + case SignatureTypeCode.Array: + { + var elementType = ParseType(); + var rank = _reader.ReadCompressedInteger(); + + // TODO: Bounds for multi-dimmensional arrays + var boundsCount = _reader.ReadCompressedInteger(); + for (int i = 0; i < boundsCount; i++) + _reader.ReadCompressedInteger(); + var lowerBoundsCount = _reader.ReadCompressedInteger(); + for (int j = 0; j < lowerBoundsCount; j++) + _reader.ReadCompressedInteger(); + + return _module.Context.GetArrayType(elementType, rank); + } + case SignatureTypeCode.ByReference: + return ParseType().MakeByRefType(); + case SignatureTypeCode.Pointer: + return _module.Context.GetPointerType(ParseType()); + case SignatureTypeCode.GenericTypeParameter: + return _module.Context.GetSignatureVariable(_reader.ReadCompressedInteger(), false); + case SignatureTypeCode.GenericMethodParameter: + return _module.Context.GetSignatureVariable(_reader.ReadCompressedInteger(), true); + case SignatureTypeCode.GenericTypeInstance: + { + TypeDesc typeDef = ParseType(); + MetadataType metadataTypeDef = typeDef as MetadataType; + if (metadataTypeDef == null) + throw new BadImageFormatException(); + + TypeDesc[] instance = new TypeDesc[_reader.ReadCompressedInteger()]; + for (int i = 0; i < instance.Length; i++) + instance[i] = ParseType(); + return _module.Context.GetInstantiatedType(metadataTypeDef, new Instantiation(instance)); + } + case SignatureTypeCode.TypedReference: + return GetWellKnownType(WellKnownType.TypedReference); + case SignatureTypeCode.FunctionPointer: + return _module.Context.GetFunctionPointerType(ParseMethodSignatureInternal(skipEmbeddedSignatureData: true)); + default: + throw new BadImageFormatException(); + } + } + + private SignatureTypeCode ParseTypeCode(bool skipPinned = true) + { + if (_indexStack != null) + { + int was = _indexStack.Pop(); + _indexStack.Push(was + 1); + _indexStack.Push(0); + } + SignatureTypeCode result = ParseTypeCodeImpl(skipPinned); + if (_indexStack != null) + { + _indexStack.Pop(); + } + return result; + } + + private SignatureTypeCode ParseTypeCodeImpl(bool skipPinned = true) + { + for (; ; ) + { + SignatureTypeCode typeCode = _reader.ReadSignatureTypeCode(); + + if (typeCode == SignatureTypeCode.RequiredModifier) + { + EntityHandle typeHandle = _reader.ReadTypeHandle(); + if (_embeddedSignatureDataList != null) + { + _embeddedSignatureDataList.Add(new EmbeddedSignatureData { index = string.Join(".", _indexStack), kind = EmbeddedSignatureDataKind.RequiredCustomModifier, type = _module.GetType(typeHandle) }); + } + continue; + } + + if (typeCode == SignatureTypeCode.OptionalModifier) + { + EntityHandle typeHandle = _reader.ReadTypeHandle(); + if (_embeddedSignatureDataList != null) + { + _embeddedSignatureDataList.Add(new EmbeddedSignatureData { index = string.Join(".", _indexStack), kind = EmbeddedSignatureDataKind.OptionalCustomModifier, type = _module.GetType(typeHandle) }); + } + continue; + } + + // TODO: treat PINNED in the signature same as modopts (it matters + // in signature matching - you can actually define overloads on this) + if (skipPinned && typeCode == SignatureTypeCode.Pinned) + { + continue; + } + + return typeCode; + } + } + + public TypeDesc ParseType() + { + if (_indexStack != null) + { + int was = _indexStack.Pop(); + _indexStack.Push(was + 1); + _indexStack.Push(0); + } + TypeDesc result = ParseTypeImpl(); + if (_indexStack != null) + { + _indexStack.Pop(); + } + return result; + } + + private TypeDesc ParseTypeImpl() + { + return ParseType(ParseTypeCode()); + } + + public bool IsFieldSignature + { + get + { + BlobReader peek = _reader; + return peek.ReadSignatureHeader().Kind == SignatureKind.Field; + } + } + + public MethodSignature ParseMethodSignature() + { + try + { + _indexStack = new Stack(); + _indexStack.Push(0); + _embeddedSignatureDataList = new List(); + return ParseMethodSignatureInternal(skipEmbeddedSignatureData: false); + } + finally + { + _indexStack = null; + _embeddedSignatureDataList = null; + } + + } + + private MethodSignature ParseMethodSignatureInternal(bool skipEmbeddedSignatureData) + { + if (_indexStack != null) + { + int was = _indexStack.Pop(); + _indexStack.Push(was + 1); + _indexStack.Push(0); + } + MethodSignature result = ParseMethodSignatureImpl(skipEmbeddedSignatureData); + if (_indexStack != null) + { + _indexStack.Pop(); + } + return result; + } + + private MethodSignature ParseMethodSignatureImpl(bool skipEmbeddedSignatureData) + { + SignatureHeader header = _reader.ReadSignatureHeader(); + + MethodSignatureFlags flags = 0; + + SignatureCallingConvention signatureCallConv = header.CallingConvention; + if (signatureCallConv != SignatureCallingConvention.Default) + { + // Verify that it is safe to convert CallingConvention to MethodSignatureFlags via a simple cast + Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionCdecl == (int)SignatureCallingConvention.CDecl); + Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionStdCall == (int)SignatureCallingConvention.StdCall); + Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionThisCall == (int)SignatureCallingConvention.ThisCall); + Debug.Assert((int)MethodSignatureFlags.CallingConventionVarargs == (int)SignatureCallingConvention.VarArgs); + + flags = (MethodSignatureFlags)signatureCallConv; + } + + if (!header.IsInstance) + flags |= MethodSignatureFlags.Static; + + int arity = header.IsGeneric ? _reader.ReadCompressedInteger() : 0; + + int count = _reader.ReadCompressedInteger(); + + TypeDesc returnType = ParseType(); + TypeDesc[] parameters; + + if (count > 0) + { + // Get all of the parameters. + parameters = new TypeDesc[count]; + for (int i = 0; i < count; i++) + { + parameters[i] = ParseType(); + } + } + else + { + parameters = TypeDesc.EmptyTypes; + } + + EmbeddedSignatureData[] embeddedSignatureDataArray = (_embeddedSignatureDataList == null || _embeddedSignatureDataList.Count == 0 || skipEmbeddedSignatureData) ? null : _embeddedSignatureDataList.ToArray(); + + return new MethodSignature(flags, arity, returnType, parameters, embeddedSignatureDataArray); + + } + + public PropertySignature ParsePropertySignature() + { + SignatureHeader header = _reader.ReadSignatureHeader(); + if (header.Kind != SignatureKind.Property) + throw new BadImageFormatException(); + + bool isStatic = !header.IsInstance; + + int count = _reader.ReadCompressedInteger(); + + TypeDesc returnType = ParseType(); + TypeDesc[] parameters; + + if (count > 0) + { + // Get all of the parameters. + parameters = new TypeDesc[count]; + for (int i = 0; i < count; i++) + { + parameters[i] = ParseType(); + } + } + else + { + parameters = TypeDesc.EmptyTypes; + } + + return new PropertySignature(isStatic, parameters, returnType); + } + + public TypeDesc ParseFieldSignature() + { + if (_reader.ReadSignatureHeader().Kind != SignatureKind.Field) + throw new BadImageFormatException(); + + return ParseType(); + } + + public LocalVariableDefinition[] ParseLocalsSignature() + { + if (_reader.ReadSignatureHeader().Kind != SignatureKind.LocalVariables) + throw new BadImageFormatException(); + + int count = _reader.ReadCompressedInteger(); + + LocalVariableDefinition[] locals; + + if (count > 0) + { + locals = new LocalVariableDefinition[count]; + for (int i = 0; i < count; i++) + { + bool isPinned = false; + + SignatureTypeCode typeCode = ParseTypeCode(skipPinned: false); + if (typeCode == SignatureTypeCode.Pinned) + { + isPinned = true; + typeCode = ParseTypeCode(); + } + + locals[i] = new LocalVariableDefinition(ParseType(typeCode), isPinned); + } + } + else + { + locals = Array.Empty(); + } + return locals; + } + + public TypeDesc[] ParseMethodSpecSignature() + { + if (_reader.ReadSignatureHeader().Kind != SignatureKind.MethodSpecification) + throw new BadImageFormatException(); + + int count = _reader.ReadCompressedInteger(); + + if (count <= 0) + throw new BadImageFormatException(); + + TypeDesc[] arguments = new TypeDesc[count]; + for (int i = 0; i < count; i++) + { + arguments[i] = ParseType(); + } + return arguments; + } + + public MarshalAsDescriptor ParseMarshalAsDescriptor() + { + Debug.Assert(_reader.RemainingBytes != 0); + + NativeTypeKind type = (NativeTypeKind)_reader.ReadByte(); + NativeTypeKind arraySubType = NativeTypeKind.Default; + uint? paramNum = null, numElem = null; + + switch (type) + { + case NativeTypeKind.Array: + { + if (_reader.RemainingBytes != 0) + { + arraySubType = (NativeTypeKind)_reader.ReadByte(); + } + + if (_reader.RemainingBytes != 0) + { + paramNum = (uint)_reader.ReadCompressedInteger(); + } + + if (_reader.RemainingBytes != 0) + { + numElem = (uint)_reader.ReadCompressedInteger(); + } + + if (_reader.RemainingBytes != 0) + { + int flag = _reader.ReadCompressedInteger(); + if (flag == 0) + { + paramNum = null; //paramNum is just a place holder so that numElem can be present + } + } + + } + break; + case NativeTypeKind.ByValArray: + { + if (_reader.RemainingBytes != 0) + { + numElem = (uint)_reader.ReadCompressedInteger(); + } + + if (_reader.RemainingBytes != 0) + { + arraySubType = (NativeTypeKind)_reader.ReadByte(); + } + } + break; + case NativeTypeKind.ByValTStr: + { + if (_reader.RemainingBytes != 0) + { + numElem = (uint)_reader.ReadCompressedInteger(); + } + } + break; + case NativeTypeKind.SafeArray: + { + // There's nobody to consume SafeArrays, so let's just parse the data + // to avoid asserting later. + + // Get optional VARTYPE for the element + if (_reader.RemainingBytes != 0) + { + _reader.ReadCompressedInteger(); + } + + // VARTYPE can be followed by optional type name + if (_reader.RemainingBytes != 0) + { + _reader.ReadSerializedString(); + } + } + break; + case NativeTypeKind.CustomMarshaler: + { + // There's nobody to consume CustomMarshaller, so let's just parse the data + // to avoid asserting later. + + // Read typelib guid + _reader.ReadSerializedString(); + + // Read native type name + _reader.ReadSerializedString(); + + // Read managed marshaler name + _reader.ReadSerializedString(); + + // Read cookie + _reader.ReadSerializedString(); + } + break; + default: + break; + } + + Debug.Assert(_reader.RemainingBytes == 0); + + return new MarshalAsDescriptor(type, arraySubType, paramNum, numElem); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs new file mode 100644 index 00000000000..4a00ef9d71d --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs @@ -0,0 +1,51 @@ +// 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.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Threading; +using Debug = System.Diagnostics.Debug; + +using Internal.NativeFormat; + +namespace Internal.TypeSystem.Ecma +{ + /// + /// Override of MetadataType that uses actual Ecma335 metadata. + /// + public sealed partial class EcmaType + { + public override string DiagnosticName + { + get + { + try + { + return Name; + } + catch + { + return $"TypeDef({MetadataReader.GetToken(Handle):x8})"; + } + } + } + public override string DiagnosticNamespace + { + get + { + try + { + return Namespace; + } + catch + { + return ""; // If namespace throws, then Name will as well, and it will attach the token as the name instead. + } + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Interfaces.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Interfaces.cs new file mode 100644 index 00000000000..c118df190fc --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Interfaces.cs @@ -0,0 +1,54 @@ +// 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.Reflection; +using System.Reflection.Metadata; +using System.Threading; +using Debug = System.Diagnostics.Debug; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + // This file has implementations of the .Interfaces.cs logic from its base type. + + public sealed partial class EcmaType : MetadataType + { + private DefType[] _implementedInterfaces; + + public override DefType[] ExplicitlyImplementedInterfaces + { + get + { + if (_implementedInterfaces == null) + return InitializeImplementedInterfaces(); + return _implementedInterfaces; + } + } + + private DefType[] InitializeImplementedInterfaces() + { + var interfaceHandles = _typeDefinition.GetInterfaceImplementations(); + + int count = interfaceHandles.Count; + if (count == 0) + return (_implementedInterfaces = Array.Empty()); + + DefType[] implementedInterfaces = new DefType[count]; + int i = 0; + foreach (var interfaceHandle in interfaceHandles) + { + var interfaceImplementation = this.MetadataReader.GetInterfaceImplementation(interfaceHandle); + DefType interfaceType = _module.GetType(interfaceImplementation.Interface) as DefType; + if (interfaceType == null) + ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, this); + + implementedInterfaces[i++] = interfaceType; + } + + return (_implementedInterfaces = implementedInterfaces); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.MethodImpls.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.MethodImpls.cs new file mode 100644 index 00000000000..4348f6c8ed9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.MethodImpls.cs @@ -0,0 +1,132 @@ +// 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.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Threading; +using Debug = System.Diagnostics.Debug; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + // This file has implementations of the .MethodImpl.cs logic from its base type. + + public sealed partial class EcmaType : MetadataType + { + // Virtual function related functionality + public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string declName) + { + MetadataReader metadataReader = _module.MetadataReader; + var stringComparer = metadataReader.StringComparer; + ArrayBuilder foundRecords = new ArrayBuilder(); + + foreach (var methodImplHandle in _typeDefinition.GetMethodImplementations()) + { + MethodImplementation methodImpl = metadataReader.GetMethodImplementation(methodImplHandle); + + EntityHandle methodDeclCheckHandle = methodImpl.MethodDeclaration; + HandleKind methodDeclHandleKind = methodDeclCheckHandle.Kind; + + // We want to check that the method name matches before actually getting the MethodDesc. For MethodSpecifications + // we need to dereference that handle to the underlying member reference to look at name matching. + if (methodDeclHandleKind == HandleKind.MethodSpecification) + { + methodDeclCheckHandle = metadataReader.GetMethodSpecification((MethodSpecificationHandle)methodDeclCheckHandle).Method; + methodDeclHandleKind = methodDeclCheckHandle.Kind; + } + + bool foundRecord = false; + + switch (methodDeclHandleKind) + { + case HandleKind.MethodDefinition: + if (stringComparer.Equals(metadataReader.GetMethodDefinition((MethodDefinitionHandle)methodDeclCheckHandle).Name, declName)) + { + foundRecord = true; + } + break; + + case HandleKind.MemberReference: + if (stringComparer.Equals(metadataReader.GetMemberReference((MemberReferenceHandle)methodDeclCheckHandle).Name, declName)) + { + foundRecord = true; + } + break; + + default: + Debug.Fail("unexpected methodDeclHandleKind"); + break; + } + + if (foundRecord) + { + MethodImplRecord newRecord = new MethodImplRecord( + (MethodDesc)_module.GetObject(methodImpl.MethodDeclaration), + (MethodDesc)_module.GetObject(methodImpl.MethodBody)); + + foundRecords.Add(newRecord); + } + } + + if (foundRecords.Count != 0) + return foundRecords.ToArray(); + + return null; + } + + protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() + { + ArrayBuilder records = new ArrayBuilder(); + + MetadataReader metadataReader = _module.MetadataReader; + + foreach (var methodImplHandle in _typeDefinition.GetMethodImplementations()) + { + MethodImplementation methodImpl = metadataReader.GetMethodImplementation(methodImplHandle); + + EntityHandle methodDeclCheckHandle = methodImpl.MethodDeclaration; + HandleKind methodDeclHandleKind = methodDeclCheckHandle.Kind; + + // We want to check that the type is not an interface matches before actually getting the MethodDesc. + // For MethodSpecifications we need to dereference that handle to the underlying member reference to + // look at the owning type. + if (methodDeclHandleKind == HandleKind.MethodSpecification) + { + methodDeclCheckHandle = metadataReader.GetMethodSpecification((MethodSpecificationHandle)methodDeclCheckHandle).Method; + methodDeclHandleKind = methodDeclCheckHandle.Kind; + } + + MetadataType owningType = null; + switch (methodDeclHandleKind) + { + case HandleKind.MethodDefinition: + owningType = ((MethodDesc)_module.GetObject(methodDeclCheckHandle)).OwningType as MetadataType; + break; + + case HandleKind.MemberReference: + EntityHandle owningTypeHandle = metadataReader.GetMemberReference((MemberReferenceHandle)methodDeclCheckHandle).Parent; + owningType = _module.GetObject(owningTypeHandle) as MetadataType; + break; + + default: + Debug.Fail("unexpected methodDeclHandleKind"); + break; + } + + if (!owningType.IsInterface) + { + MethodImplRecord newRecord = new MethodImplRecord( + (MethodDesc)_module.GetObject(methodImpl.MethodDeclaration), + (MethodDesc)_module.GetObject(methodImpl.MethodBody)); + records.Add(newRecord); + } + } + + return records.ToArray(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Serialization.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Serialization.cs new file mode 100644 index 00000000000..3ba6042c5de --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Serialization.cs @@ -0,0 +1,19 @@ +// 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.Reflection; + +namespace Internal.TypeSystem.Ecma +{ + partial class EcmaType + { + public override bool IsSerializable + { + get + { + return (_typeDefinition.Attributes & TypeAttributes.Serializable) != 0; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Sorting.cs new file mode 100644 index 00000000000..246f36aa3f0 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Sorting.cs @@ -0,0 +1,24 @@ +// 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.Reflection.Metadata.Ecma335; + +namespace Internal.TypeSystem.Ecma +{ + // Functionality related to determinstic ordering of types + partial class EcmaType + { + protected internal override int ClassCode => 1340416537; + + protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + var otherType = (EcmaType)other; + int result = _module.MetadataReader.GetToken(_handle) - otherType._module.MetadataReader.GetToken(otherType._handle); + if (result != 0) + return result; + + return _module.CompareTo(otherType._module); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.cs new file mode 100644 index 00000000000..24cf0c8a43f --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.cs @@ -0,0 +1,598 @@ +// 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.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Threading; +using Debug = System.Diagnostics.Debug; + +using Internal.NativeFormat; + +namespace Internal.TypeSystem.Ecma +{ + /// + /// Override of MetadataType that uses actual Ecma335 metadata. + /// + public sealed partial class EcmaType : MetadataType, EcmaModule.IEntityHandleObject + { + private EcmaModule _module; + private TypeDefinitionHandle _handle; + + private TypeDefinition _typeDefinition; + + // Cached values + private string _typeName; + private string _typeNamespace; + private TypeDesc[] _genericParameters; + private MetadataType _baseType; + private int _hashcode; + + internal EcmaType(EcmaModule module, TypeDefinitionHandle handle) + { + _module = module; + _handle = handle; + + _typeDefinition = module.MetadataReader.GetTypeDefinition(handle); + + _baseType = this; // Not yet initialized flag + +#if DEBUG + // Initialize name eagerly in debug builds for convenience + InitializeName(); + InitializeNamespace(); +#endif + } + + public override int GetHashCode() + { + if (_hashcode != 0) + return _hashcode; + return InitializeHashCode(); + } + + private int InitializeHashCode() + { + TypeDesc containingType = ContainingType; + if (containingType == null) + { + string ns = Namespace; + var hashCodeBuilder = new TypeHashingAlgorithms.HashCodeBuilder(ns); + if (ns.Length > 0) + hashCodeBuilder.Append("."); + hashCodeBuilder.Append(Name); + _hashcode = hashCodeBuilder.ToHashCode(); + } + else + { + _hashcode = TypeHashingAlgorithms.ComputeNestedTypeHashCode( + containingType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(Name)); + } + + return _hashcode; + } + + EntityHandle EcmaModule.IEntityHandleObject.Handle + { + get + { + return _handle; + } + } + + public override TypeSystemContext Context + { + get + { + return _module.Context; + } + } + + private void ComputeGenericParameters() + { + var genericParameterHandles = _typeDefinition.GetGenericParameters(); + int count = genericParameterHandles.Count; + if (count > 0) + { + TypeDesc[] genericParameters = new TypeDesc[count]; + int i = 0; + foreach (var genericParameterHandle in genericParameterHandles) + { + genericParameters[i++] = new EcmaGenericParameter(_module, genericParameterHandle); + } + Interlocked.CompareExchange(ref _genericParameters, genericParameters, null); + } + else + { + _genericParameters = TypeDesc.EmptyTypes; + } + } + + public override Instantiation Instantiation + { + get + { + if (_genericParameters == null) + ComputeGenericParameters(); + return new Instantiation(_genericParameters); + } + } + + public override ModuleDesc Module + { + get + { + return _module; + } + } + + public EcmaModule EcmaModule + { + get + { + return _module; + } + } + + public MetadataReader MetadataReader + { + get + { + return _module.MetadataReader; + } + } + + public TypeDefinitionHandle Handle + { + get + { + return _handle; + } + } + + private MetadataType InitializeBaseType() + { + var baseTypeHandle = _typeDefinition.BaseType; + if (baseTypeHandle.IsNil) + { + _baseType = null; + return null; + } + + var type = _module.GetType(baseTypeHandle) as MetadataType; + if (type == null) + { + // PREFER: "new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadBadFormat, this)" but the metadata is too broken + ThrowHelper.ThrowTypeLoadException(Namespace, Name, Module); + } + _baseType = type; + return type; + } + + public override DefType BaseType + { + get + { + if (_baseType == this) + return InitializeBaseType(); + return _baseType; + } + } + + public override MetadataType MetadataBaseType + { + get + { + if (_baseType == this) + return InitializeBaseType(); + return _baseType; + } + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + if ((mask & TypeFlags.CategoryMask) != 0) + { + TypeDesc baseType = this.BaseType; + + if (baseType != null && baseType.IsWellKnownType(WellKnownType.ValueType)) + { + flags |= TypeFlags.ValueType; + } + else + if (baseType != null && baseType.IsWellKnownType(WellKnownType.Enum)) + { + flags |= TypeFlags.Enum; + } + else + { + if ((_typeDefinition.Attributes & TypeAttributes.Interface) != 0) + flags |= TypeFlags.Interface; + else + flags |= TypeFlags.Class; + } + + // All other cases are handled during TypeSystemContext intitialization + } + + if ((mask & TypeFlags.HasGenericVarianceComputed) != 0) + { + flags |= TypeFlags.HasGenericVarianceComputed; + + foreach (GenericParameterDesc genericParam in Instantiation) + { + if (genericParam.Variance != GenericVariance.None) + { + flags |= TypeFlags.HasGenericVariance; + break; + } + } + } + + if ((mask & TypeFlags.HasFinalizerComputed) != 0) + { + flags |= TypeFlags.HasFinalizerComputed; + + if (GetFinalizer() != null) + flags |= TypeFlags.HasFinalizer; + } + + if ((mask & TypeFlags.AttributeCacheComputed) != 0) + { + MetadataReader reader = MetadataReader; + MetadataStringComparer stringComparer = reader.StringComparer; + bool isValueType = IsValueType; + + flags |= TypeFlags.AttributeCacheComputed; + + foreach (CustomAttributeHandle attributeHandle in _typeDefinition.GetCustomAttributes()) + { + if (MetadataReader.GetAttributeNamespaceAndName(attributeHandle, out StringHandle namespaceHandle, out StringHandle nameHandle)) + { + if (isValueType && + stringComparer.Equals(nameHandle, "IsByRefLikeAttribute") && + stringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices")) + flags |= TypeFlags.IsByRefLike; + + if (stringComparer.Equals(nameHandle, "IntrinsicAttribute") && + stringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices")) + flags |= TypeFlags.IsIntrinsic; + } + } + } + + return flags; + } + + private string InitializeName() + { + var metadataReader = this.MetadataReader; + _typeName = metadataReader.GetString(_typeDefinition.Name); + return _typeName; + } + + public override string Name + { + get + { + if (_typeName == null) + return InitializeName(); + return _typeName; + } + } + + private string InitializeNamespace() + { + var metadataReader = this.MetadataReader; + _typeNamespace = metadataReader.GetString(_typeDefinition.Namespace); + return _typeNamespace; + } + + public override string Namespace + { + get + { + if (_typeNamespace == null) + return InitializeNamespace(); + return _typeNamespace; + } + } + + public override IEnumerable GetMethods() + { + foreach (var handle in _typeDefinition.GetMethods()) + { + yield return (MethodDesc)_module.GetObject(handle); + } + } + + public override MethodDesc GetMethod(string name, MethodSignature signature) + { + var metadataReader = this.MetadataReader; + var stringComparer = metadataReader.StringComparer; + + foreach (var handle in _typeDefinition.GetMethods()) + { + if (stringComparer.Equals(metadataReader.GetMethodDefinition(handle).Name, name)) + { + MethodDesc method = (MethodDesc)_module.GetObject(handle); + if (signature == null || signature.Equals(method.Signature)) + return method; + } + } + + return null; + } + + public override MethodDesc GetStaticConstructor() + { + var metadataReader = this.MetadataReader; + var stringComparer = metadataReader.StringComparer; + + foreach (var handle in _typeDefinition.GetMethods()) + { + var methodDefinition = metadataReader.GetMethodDefinition(handle); + if (methodDefinition.Attributes.IsRuntimeSpecialName() && + stringComparer.Equals(methodDefinition.Name, ".cctor")) + { + MethodDesc method = (MethodDesc)_module.GetObject(handle); + return method; + } + } + + return null; + } + + public override MethodDesc GetDefaultConstructor() + { + if (IsAbstract) + return null; + + MetadataReader metadataReader = this.MetadataReader; + MetadataStringComparer stringComparer = metadataReader.StringComparer; + + foreach (var handle in _typeDefinition.GetMethods()) + { + var methodDefinition = metadataReader.GetMethodDefinition(handle); + MethodAttributes attributes = methodDefinition.Attributes; + if (attributes.IsRuntimeSpecialName() && attributes.IsPublic() + && stringComparer.Equals(methodDefinition.Name, ".ctor")) + { + MethodDesc method = (MethodDesc)_module.GetObject(handle); + if (method.Signature.Length != 0) + continue; + + return method; + } + } + + return null; + } + + public override MethodDesc GetFinalizer() + { + // System.Object defines Finalize but doesn't use it, so we can determine that a type has a Finalizer + // by checking for a virtual method override that lands anywhere other than Object in the inheritance + // chain. + if (!HasBaseType) + return null; + + TypeDesc objectType = Context.GetWellKnownType(WellKnownType.Object); + MethodDesc decl = objectType.GetMethod("Finalize", null); + + if (decl != null) + { + MethodDesc impl = this.FindVirtualFunctionTargetMethodOnObjectType(decl); + if (impl == null) + { + // TODO: invalid input: the type doesn't derive from our System.Object + throw new TypeLoadException(this.GetFullName()); + } + + if (impl.OwningType != objectType) + { + return impl; + } + + return null; + } + + // Class library doesn't have finalizers + return null; + } + + public override IEnumerable GetFields() + { + foreach (var handle in _typeDefinition.GetFields()) + { + var field = (EcmaField)_module.GetObject(handle); + yield return field; + } + } + + public override FieldDesc GetField(string name) + { + var metadataReader = this.MetadataReader; + var stringComparer = metadataReader.StringComparer; + + foreach (var handle in _typeDefinition.GetFields()) + { + if (stringComparer.Equals(metadataReader.GetFieldDefinition(handle).Name, name)) + { + var field = (EcmaField)_module.GetObject(handle); + return field; + } + } + + return null; + } + + public override IEnumerable GetNestedTypes() + { + foreach (var handle in _typeDefinition.GetNestedTypes()) + { + yield return (MetadataType)_module.GetObject(handle); + } + } + + public override MetadataType GetNestedType(string name) + { + var metadataReader = this.MetadataReader; + var stringComparer = metadataReader.StringComparer; + + foreach (var handle in _typeDefinition.GetNestedTypes()) + { + bool nameMatched; + TypeDefinition type = metadataReader.GetTypeDefinition(handle); + if (type.Namespace.IsNil) + { + nameMatched = stringComparer.Equals(type.Name, name); + } + else + { + string typeName = metadataReader.GetString(type.Name); + typeName = metadataReader.GetString(type.Namespace) + "." + typeName; + nameMatched = typeName == name; + } + + if (nameMatched) + return (MetadataType)_module.GetObject(handle); + } + + return null; + } + + public TypeAttributes Attributes + { + get + { + return _typeDefinition.Attributes; + } + } + + public override DefType ContainingType + { + get + { + if (!_typeDefinition.Attributes.IsNested()) + return null; + + var handle = _typeDefinition.GetDeclaringType(); + return (DefType)_module.GetType(handle); + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return !MetadataReader.GetCustomAttributeHandle(_typeDefinition.GetCustomAttributes(), + attributeNamespace, attributeName).IsNil; + } + + public override ClassLayoutMetadata GetClassLayout() + { + TypeLayout layout = _typeDefinition.GetLayout(); + + ClassLayoutMetadata result; + result.PackingSize = layout.PackingSize; + result.Size = layout.Size; + + // Skip reading field offsets if this is not explicit layout + if (IsExplicitLayout) + { + var fieldDefinitionHandles = _typeDefinition.GetFields(); + var numInstanceFields = 0; + + foreach (var handle in fieldDefinitionHandles) + { + var fieldDefinition = MetadataReader.GetFieldDefinition(handle); + if ((fieldDefinition.Attributes & FieldAttributes.Static) != 0) + continue; + + numInstanceFields++; + } + + result.Offsets = new FieldAndOffset[numInstanceFields]; + + int index = 0; + foreach (var handle in fieldDefinitionHandles) + { + var fieldDefinition = MetadataReader.GetFieldDefinition(handle); + if ((fieldDefinition.Attributes & FieldAttributes.Static) != 0) + continue; + + // Note: GetOffset() returns -1 when offset was not set in the metadata + int specifiedOffset = fieldDefinition.GetOffset(); + result.Offsets[index] = + new FieldAndOffset((FieldDesc)_module.GetObject(handle), specifiedOffset == -1 ? FieldAndOffset.InvalidOffset : new LayoutInt(specifiedOffset)); + + index++; + } + } + else + result.Offsets = null; + + return result; + } + + public override bool IsExplicitLayout + { + get + { + return (_typeDefinition.Attributes & TypeAttributes.ExplicitLayout) != 0; + } + } + + public override bool IsSequentialLayout + { + get + { + return (_typeDefinition.Attributes & TypeAttributes.SequentialLayout) != 0; + } + } + + public override bool IsBeforeFieldInit + { + get + { + return (_typeDefinition.Attributes & TypeAttributes.BeforeFieldInit) != 0; + } + } + + public override bool IsModuleType + { + get + { + return _handle.Equals(MetadataTokens.TypeDefinitionHandle(0x00000001 /* COR_GLOBAL_PARENT_TOKEN */)); + } + } + + public override bool IsSealed + { + get + { + return (_typeDefinition.Attributes & TypeAttributes.Sealed) != 0; + } + } + + public override bool IsAbstract + { + get + { + return (_typeDefinition.Attributes & TypeAttributes.Abstract) != 0; + } + } + + public override PInvokeStringFormat PInvokeStringFormat + { + get + { + return (PInvokeStringFormat)(_typeDefinition.Attributes & TypeAttributes.StringFormatMask); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/IMetadataStringDecoderProvider.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/IMetadataStringDecoderProvider.cs new file mode 100644 index 00000000000..5c9fc98e928 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/IMetadataStringDecoderProvider.cs @@ -0,0 +1,18 @@ +// 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.Reflection.Metadata; + +namespace Internal.TypeSystem.Ecma +{ + /// + /// Interface implemented by TypeSystemContext to provide MetadataStringDecoder + /// instance for MetadataReaders created by the type system. + /// + public interface IMetadataStringDecoderProvider + { + MetadataStringDecoder GetMetadataStringDecoder(); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/MetadataExtensions.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/MetadataExtensions.cs new file mode 100644 index 00000000000..bbe4eed38d8 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/MetadataExtensions.cs @@ -0,0 +1,286 @@ +// 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.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Runtime.InteropServices; + +namespace Internal.TypeSystem.Ecma +{ + public static class MetadataExtensions + { + public static CustomAttributeValue? GetDecodedCustomAttribute(this EcmaType This, + string attributeNamespace, string attributeName) + { + var metadataReader = This.MetadataReader; + + var attributeHandle = metadataReader.GetCustomAttributeHandle(metadataReader.GetTypeDefinition(This.Handle).GetCustomAttributes(), + attributeNamespace, attributeName); + + if (attributeHandle.IsNil) + return null; + + return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.EcmaModule)); + } + + public static CustomAttributeValue? GetDecodedCustomAttribute(this EcmaMethod This, + string attributeNamespace, string attributeName) + { + var metadataReader = This.MetadataReader; + + var attributeHandle = metadataReader.GetCustomAttributeHandle(metadataReader.GetMethodDefinition(This.Handle).GetCustomAttributes(), + attributeNamespace, attributeName); + + if (attributeHandle.IsNil) + return null; + + return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.Module)); + } + + public static IEnumerable> GetDecodedCustomAttributes(this EcmaMethod This, + string attributeNamespace, string attributeName) + { + var metadataReader = This.MetadataReader; + var attributeHandles = metadataReader.GetMethodDefinition(This.Handle).GetCustomAttributes(); + foreach (var attributeHandle in attributeHandles) + { + if (IsEqualCustomAttributeName(attributeHandle, metadataReader, attributeNamespace, attributeName)) + { + yield return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.Module)); + } + } + } + + public static CustomAttributeValue? GetDecodedCustomAttribute(this EcmaField This, + string attributeNamespace, string attributeName) + { + var metadataReader = This.MetadataReader; + + var attributeHandle = metadataReader.GetCustomAttributeHandle(metadataReader.GetFieldDefinition(This.Handle).GetCustomAttributes(), + attributeNamespace, attributeName); + + if (attributeHandle.IsNil) + return null; + + return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.Module)); + } + + public static IEnumerable> GetDecodedCustomAttributes(this EcmaField This, + string attributeNamespace, string attributeName) + { + var metadataReader = This.MetadataReader; + var attributeHandles = metadataReader.GetFieldDefinition(This.Handle).GetCustomAttributes(); + foreach (var attributeHandle in attributeHandles) + { + if (IsEqualCustomAttributeName(attributeHandle, metadataReader, attributeNamespace, attributeName)) + { + yield return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.Module)); + } + } + } + + public static IEnumerable> GetDecodedCustomAttributes(this EcmaAssembly This, + string attributeNamespace, string attributeName) + { + var metadataReader = This.MetadataReader; + var attributeHandles = metadataReader.GetAssemblyDefinition().GetCustomAttributes(); + foreach (var attributeHandle in attributeHandles) + { + if (IsEqualCustomAttributeName(attributeHandle, metadataReader, attributeNamespace, attributeName)) + { + yield return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This)); + } + } + } + + public static CustomAttributeHandle GetCustomAttributeHandle(this MetadataReader metadataReader, CustomAttributeHandleCollection customAttributes, + string attributeNamespace, string attributeName) + { + foreach (var attributeHandle in customAttributes) + { + if (IsEqualCustomAttributeName(attributeHandle, metadataReader, attributeNamespace, attributeName)) + { + return attributeHandle; + } + } + + return default(CustomAttributeHandle); + } + + private static bool IsEqualCustomAttributeName(CustomAttributeHandle attributeHandle, MetadataReader metadataReader, + string attributeNamespace, string attributeName) + { + StringHandle namespaceHandle, nameHandle; + if (!metadataReader.GetAttributeNamespaceAndName(attributeHandle, out namespaceHandle, out nameHandle)) + return false; + + return metadataReader.StringComparer.Equals(namespaceHandle, attributeNamespace) + && metadataReader.StringComparer.Equals(nameHandle, attributeName); + } + + public static bool GetAttributeNamespaceAndName(this MetadataReader metadataReader, CustomAttributeHandle attributeHandle, + out StringHandle namespaceHandle, out StringHandle nameHandle) + { + EntityHandle attributeType, attributeCtor; + if (!GetAttributeTypeAndConstructor(metadataReader, attributeHandle, out attributeType, out attributeCtor)) + { + namespaceHandle = default(StringHandle); + nameHandle = default(StringHandle); + return false; + } + + return GetAttributeTypeNamespaceAndName(metadataReader, attributeType, out namespaceHandle, out nameHandle); + } + + public static bool GetAttributeTypeAndConstructor(this MetadataReader metadataReader, CustomAttributeHandle attributeHandle, + out EntityHandle attributeType, out EntityHandle attributeCtor) + { + attributeCtor = metadataReader.GetCustomAttribute(attributeHandle).Constructor; + + if (attributeCtor.Kind == HandleKind.MemberReference) + { + attributeType = metadataReader.GetMemberReference((MemberReferenceHandle)attributeCtor).Parent; + return true; + } + else if (attributeCtor.Kind == HandleKind.MethodDefinition) + { + attributeType = metadataReader.GetMethodDefinition((MethodDefinitionHandle)attributeCtor).GetDeclaringType(); + return true; + } + else + { + // invalid metadata + attributeType = default(EntityHandle); + return false; + } + } + + public static bool GetAttributeTypeNamespaceAndName(this MetadataReader metadataReader, EntityHandle attributeType, + out StringHandle namespaceHandle, out StringHandle nameHandle) + { + namespaceHandle = default(StringHandle); + nameHandle = default(StringHandle); + + if (attributeType.Kind == HandleKind.TypeReference) + { + TypeReference typeRefRow = metadataReader.GetTypeReference((TypeReferenceHandle)attributeType); + HandleKind handleType = typeRefRow.ResolutionScope.Kind; + + // Nested type? + if (handleType == HandleKind.TypeReference || handleType == HandleKind.TypeDefinition) + return false; + + nameHandle = typeRefRow.Name; + namespaceHandle = typeRefRow.Namespace; + return true; + } + else if (attributeType.Kind == HandleKind.TypeDefinition) + { + var def = metadataReader.GetTypeDefinition((TypeDefinitionHandle)attributeType); + + // Nested type? + if (IsNested(def.Attributes)) + return false; + + nameHandle = def.Name; + namespaceHandle = def.Namespace; + return true; + } + else + { + // unsupported metadata + return false; + } + } + + public static PInvokeFlags GetDelegatePInvokeFlags(this EcmaType type) + { + PInvokeFlags flags = new PInvokeFlags(); + + if (!type.IsDelegate) + { + return flags; + } + + var customAttributeValue = type.GetDecodedCustomAttribute( + "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute"); + + if (customAttributeValue == null) + { + return flags; + } + + if (!customAttributeValue.HasValue) + { + return flags; + } + + if (customAttributeValue.Value.FixedArguments.Length == 1) + { + CallingConvention callingConvention = (CallingConvention)customAttributeValue.Value.FixedArguments[0].Value; + + switch (callingConvention) + { + case CallingConvention.StdCall: + flags.UnmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConventionStdCall; + break; + case CallingConvention.Cdecl: + flags.UnmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConventionCdecl; + break; + case CallingConvention.ThisCall: + flags.UnmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConventionThisCall; + break; + case CallingConvention.Winapi: + flags.UnmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConventionStdCall; + break; + } + } + + foreach (var namedArgument in customAttributeValue.Value.NamedArguments) + { + if (namedArgument.Name == "CharSet") + { + flags.CharSet = (CharSet)namedArgument.Value; + } + else if (namedArgument.Name == "BestFitMapping") + { + flags.BestFitMapping = (bool)namedArgument.Value; + } + else if (namedArgument.Name == "SetLastError") + { + flags.SetLastError = (bool)namedArgument.Value; + } + else if (namedArgument.Name == "ThrowOnUnmappableChar") + { + flags.ThrowOnUnmappableChar = (bool)namedArgument.Value; + } + } + return flags; + } + + // This mask is the fastest way to check if a type is nested from its flags, + // but it should not be added to the BCL enum as its semantics can be misleading. + // Consider, for example, that (NestedFamANDAssem & NestedMask) == NestedFamORAssem. + // Only comparison of the masked value to 0 is meaningful, which is different from + // the other masks in the enum. + private const TypeAttributes NestedMask = (TypeAttributes)0x00000006; + + public static bool IsNested(this TypeAttributes flags) + { + return (flags & NestedMask) != 0; + } + + public static bool IsRuntimeSpecialName(this MethodAttributes flags) + { + return (flags & (MethodAttributes.SpecialName | MethodAttributes.RTSpecialName)) + == (MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); + } + + public static bool IsPublic(this MethodAttributes flags) + { + return (flags & MethodAttributes.MemberAccessMask) == MethodAttributes.Public; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/PrimitiveTypeProvider.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/PrimitiveTypeProvider.cs new file mode 100644 index 00000000000..ff9bea5afb7 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/PrimitiveTypeProvider.cs @@ -0,0 +1,79 @@ +// 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.Reflection.Metadata; + +namespace Internal.TypeSystem.Ecma +{ + public static class PrimitiveTypeProvider + { + public static TypeDesc GetPrimitiveType(TypeSystemContext context, PrimitiveTypeCode typeCode) + { + WellKnownType wkt; + + switch (typeCode) + { + case PrimitiveTypeCode.Boolean: + wkt = WellKnownType.Boolean; + break; + case PrimitiveTypeCode.Byte: + wkt = WellKnownType.Byte; + break; + case PrimitiveTypeCode.Char: + wkt = WellKnownType.Char; + break; + case PrimitiveTypeCode.Double: + wkt = WellKnownType.Double; + break; + case PrimitiveTypeCode.Int16: + wkt = WellKnownType.Int16; + break; + case PrimitiveTypeCode.Int32: + wkt = WellKnownType.Int32; + break; + case PrimitiveTypeCode.Int64: + wkt = WellKnownType.Int64; + break; + case PrimitiveTypeCode.IntPtr: + wkt = WellKnownType.IntPtr; + break; + case PrimitiveTypeCode.Object: + wkt = WellKnownType.Object; + break; + case PrimitiveTypeCode.SByte: + wkt = WellKnownType.SByte; + break; + case PrimitiveTypeCode.Single: + wkt = WellKnownType.Single; + break; + case PrimitiveTypeCode.String: + wkt = WellKnownType.String; + break; + case PrimitiveTypeCode.UInt16: + wkt = WellKnownType.UInt16; + break; + case PrimitiveTypeCode.UInt32: + wkt = WellKnownType.UInt32; + break; + case PrimitiveTypeCode.UInt64: + wkt = WellKnownType.UInt64; + break; + case PrimitiveTypeCode.UIntPtr: + wkt = WellKnownType.UIntPtr; + break; + case PrimitiveTypeCode.Void: + wkt = WellKnownType.Void; + break; + case PrimitiveTypeCode.TypedReference: + wkt = WellKnownType.TypedReference; + break; + default: + throw new BadImageFormatException(); + } + + return context.GetWellKnownType(wkt); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/PdbSymbolReader.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/PdbSymbolReader.cs new file mode 100644 index 00000000000..c35c1490a1e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/PdbSymbolReader.cs @@ -0,0 +1,21 @@ +// 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.Collections.Generic; + +using Internal.IL; + +namespace Internal.TypeSystem.Ecma +{ + /// + /// Abstraction for reading Pdb files + /// + public abstract class PdbSymbolReader : IDisposable + { + public abstract IEnumerable GetSequencePointsForMethod(int methodToken); + public abstract IEnumerable GetLocalVariableNamesForMethod(int methodToken); + public abstract void Dispose(); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/PortablePdbSymbolReader.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/PortablePdbSymbolReader.cs new file mode 100644 index 00000000000..4faecf8a7c3 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/PortablePdbSymbolReader.cs @@ -0,0 +1,154 @@ +// 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.Collections.Generic; +using System.IO; +using System.IO.MemoryMappedFiles; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using Internal.IL; + +namespace Internal.TypeSystem.Ecma +{ + /// + /// Provides PdbSymbolReader for portable PDB via System.Reflection.Metadata + /// + public sealed class PortablePdbSymbolReader : PdbSymbolReader + { + private static unsafe MetadataReader TryOpenMetadataFile(string filePath, MetadataStringDecoder stringDecoder, out MemoryMappedViewAccessor mappedViewAccessor) + { + FileStream fileStream = null; + MemoryMappedFile mappedFile = null; + MemoryMappedViewAccessor accessor = null; + try + { + // Create stream because CreateFromFile(string, ...) uses FileShare.None which is too strict + fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false); + mappedFile = MemoryMappedFile.CreateFromFile( + fileStream, null, fileStream.Length, MemoryMappedFileAccess.Read, HandleInheritability.None, true); + + accessor = mappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); + + var safeBuffer = accessor.SafeMemoryMappedViewHandle; + + // Check whether this is a real metadata file to avoid thrown and caught exceptions + // for non-portable .pdbs + if (safeBuffer.Read(0) != 'B' || // COR20MetadataSignature + safeBuffer.Read(1) != 'S' || + safeBuffer.Read(2) != 'J' || + safeBuffer.Read(3) != 'B') + { + mappedViewAccessor = null; + return null; + } + + var metadataReader = new MetadataReader((byte*)safeBuffer.DangerousGetHandle(), (int)safeBuffer.ByteLength, MetadataReaderOptions.Default, stringDecoder); + + // MemoryMappedFile does not need to be kept around. MemoryMappedViewAccessor is enough. + + mappedViewAccessor = accessor; + accessor = null; + + return metadataReader; + } + finally + { + if (accessor != null) + accessor.Dispose(); + if (mappedFile != null) + mappedFile.Dispose(); + if (fileStream != null) + fileStream.Dispose(); + } + } + + public static PdbSymbolReader TryOpen(string pdbFilename, MetadataStringDecoder stringDecoder) + { + MemoryMappedViewAccessor mappedViewAccessor; + MetadataReader reader = TryOpenMetadataFile(pdbFilename, stringDecoder, out mappedViewAccessor); + if (reader == null) + return null; + + return new PortablePdbSymbolReader(reader, mappedViewAccessor); + } + + private MetadataReader _reader; + private MemoryMappedViewAccessor _mappedViewAccessor; + + private PortablePdbSymbolReader(MetadataReader reader, MemoryMappedViewAccessor mappedViewAccessor) + { + _reader = reader; + _mappedViewAccessor = mappedViewAccessor; + } + + public override void Dispose() + { + _mappedViewAccessor.Dispose(); + } + + public override IEnumerable GetSequencePointsForMethod(int methodToken) + { + var debugInformationHandle = ((MethodDefinitionHandle)MetadataTokens.EntityHandle(methodToken)).ToDebugInformationHandle(); + + var debugInformation = _reader.GetMethodDebugInformation(debugInformationHandle); + + var sequencePoints = debugInformation.GetSequencePoints(); + + foreach (var sequencePoint in sequencePoints) + { + if (sequencePoint.StartLine == 0xFEEFEE) + continue; + + var url = _reader.GetString(_reader.GetDocument(sequencePoint.Document).Name); + + yield return new ILSequencePoint(sequencePoint.Offset, url, sequencePoint.StartLine); + } + } + + // + // Gather the local details in a scope and then recurse to child scopes + // + private void ProbeScopeForLocals(List variables, LocalScopeHandle localScopeHandle) + { + var localScope = _reader.GetLocalScope(localScopeHandle); + + foreach (var localVariableHandle in localScope.GetLocalVariables()) + { + var localVariable = _reader.GetLocalVariable(localVariableHandle); + + var name = _reader.GetString(localVariable.Name); + bool compilerGenerated = (localVariable.Attributes & LocalVariableAttributes.DebuggerHidden) != 0; + + variables.Add(new ILLocalVariable(localVariable.Index, name, compilerGenerated)); + } + + var children = localScope.GetChildren(); + while (children.MoveNext()) + { + ProbeScopeForLocals(variables, children.Current); + } + } + + // + // Recursively scan the scopes for a method stored in a PDB and gather the local slots + // and names for all of them. This assumes a CSC-like compiler that doesn't re-use + // local slots in the same method across scopes. + // + public override IEnumerable GetLocalVariableNamesForMethod(int methodToken) + { + var debugInformationHandle = MetadataTokens.MethodDefinitionHandle(methodToken).ToDebugInformationHandle(); + + var localScopes = _reader.GetLocalScopes(debugInformationHandle); + + var variables = new List(); + foreach (var localScopeHandle in localScopes) + { + ProbeScopeForLocals(variables, localScopeHandle); + } + return variables; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/UnmanagedPdbSymbolReader.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/UnmanagedPdbSymbolReader.cs new file mode 100644 index 00000000000..5dc82b12ad6 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/SymbolReader/UnmanagedPdbSymbolReader.cs @@ -0,0 +1,283 @@ +// 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.Collections.Generic; +using System.Runtime.InteropServices; + +using Microsoft.DiaSymReader; + +using Internal.IL; + +namespace Internal.TypeSystem.Ecma +{ + /// + /// Provides PdbSymbolReader via unmanaged SymBinder from full .NET Framework + /// + public sealed class UnmanagedPdbSymbolReader : PdbSymbolReader + { + [DllImport("mscoree.dll")] + private static extern int CLRCreateInstance([In] ref Guid clsid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out ICLRMetaHost ppInterface); + + [Guid("d332db9e-b9b3-4125-8207-a14884f53216")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComVisible(true)] + interface ICLRMetaHost + { + [PreserveSig] + int GetRuntime([In, MarshalAs(UnmanagedType.LPWStr)] String pwzVersion, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out ICLRRuntimeInfo ppRuntime); + + // Don't need any other methods. + } + + [Guid("bd39d1d2-ba2f-486a-89b0-b4b0cb466891")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComVisible(true)] + interface ICLRRuntimeInfo + { + void GetVersionString_Placeholder(); + void GetRuntimeDirectory_Placeholder(); + void IsLoaded_Placeholder(); + void LoadErrorString_Placeholder(); + void LoadLibrary_Placeholder(); + void GetProcAddress_Placeholder(); + + [PreserveSig] + int GetInterface([In] ref Guid rclsid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out Object ppUnk); + + void IsLoadable_Placeholder(); + void SetDefaultStartupFlags_Placeholder(); + void GetDefaultStartupFlags_Placeholder(); + + [PreserveSig] + int BindAsLegacyV2Runtime(); + + // Don't need any other methods. + } + + [Guid("809c652e-7396-11d2-9771-00a0c9b4d50c")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComVisible(true)] + private interface IMetaDataDispenser + { + void DefineScope_Placeholder(); + + [PreserveSig] + int OpenScope([In, MarshalAs(UnmanagedType.LPWStr)] String szScope, [In] Int32 dwOpenFlags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out Object punk); + + // Don't need any other methods. + } + + [DllImport("ole32.dll")] + private static extern int CoCreateInstance(ref Guid rclsid, IntPtr pUnkOuter, + Int32 dwClsContext, + ref Guid riid, + [MarshalAs(UnmanagedType.Interface)] out object ppv); + + private void ThrowExceptionForHR(int hr) + { + Marshal.ThrowExceptionForHR(hr, new IntPtr(-1)); + } + + static UnmanagedPdbSymbolReader() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + try + { + Guid IID_IUnknown = new Guid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); + + ICLRMetaHost objMetaHost; + Guid CLSID_CLRMetaHost = new Guid(0x9280188d, 0x0e8e, 0x4867, 0xb3, 0x0c, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde); + Guid IID_CLRMetaHost = new Guid(0xd332db9e, 0xb9b3, 0x4125, 0x82, 0x07, 0xa1, 0x48, 0x84, 0xf5, 0x32, 0x16); + if (CLRCreateInstance(ref CLSID_CLRMetaHost, ref IID_CLRMetaHost, out objMetaHost) < 0) + return; + + ICLRRuntimeInfo objRuntime; + Guid IID_CLRRuntimeInfo = new Guid(0xbd39d1d2, 0xba2f, 0x486a, 0x89, 0xb0, 0xb4, 0xb0, 0xcb, 0x46, 0x68, 0x91); + if (objMetaHost.GetRuntime("v4.0.30319", ref IID_CLRRuntimeInfo, out objRuntime) < 0) + return; + + // To get everything from the v4 runtime + objRuntime.BindAsLegacyV2Runtime(); + + // Create a COM Metadata dispenser + object objDispenser; + Guid CLSID_CorMetaDataDispenser = new Guid(0xe5cb7a31, 0x7512, 0x11d2, 0x89, 0xce, 0x00, 0x80, 0xc7, 0x92, 0xe5, 0xd8); + if (objRuntime.GetInterface(ref CLSID_CorMetaDataDispenser, ref IID_IUnknown, out objDispenser) < 0) + return; + s_metadataDispenser = (IMetaDataDispenser)objDispenser; + + // Create a SymBinder + object objBinder; + Guid CLSID_CorSymBinder = new Guid(0x0a29ff9e, 0x7f9c, 0x4437, 0x8b, 0x11, 0xf4, 0x24, 0x49, 0x1e, 0x39, 0x31); + if (CoCreateInstance(ref CLSID_CorSymBinder, + IntPtr.Zero, // pUnkOuter + 1, // CLSCTX_INPROC_SERVER + ref IID_IUnknown, + out objBinder) < 0) + return; + s_symBinder = (ISymUnmanagedBinder)objBinder; + } + catch + { + } + } + } + + private static IMetaDataDispenser s_metadataDispenser; + private static ISymUnmanagedBinder s_symBinder; + + public static PdbSymbolReader TryOpenSymbolReaderForMetadataFile(string metadataFileName, string searchPath) + { + try + { + if (s_metadataDispenser == null || s_symBinder == null) + return null; + + Guid IID_IMetaDataImport = new Guid(0x7dac8207, 0xd3ae, 0x4c75, 0x9b, 0x67, 0x92, 0x80, 0x1a, 0x49, 0x7d, 0x44); + + // Open an metadata importer on the given filename. We'll end up passing this importer straight + // through to the Binder. + object objImporter; + if (s_metadataDispenser.OpenScope(metadataFileName, 0x00000010 /* read only */, ref IID_IMetaDataImport, out objImporter) < 0) + return null; + + ISymUnmanagedReader reader; + if (s_symBinder.GetReaderForFile(objImporter, metadataFileName, searchPath, out reader) < 0) + return null; + + return new UnmanagedPdbSymbolReader(reader); + } + catch + { + return null; + } + } + + private ISymUnmanagedReader _symUnmanagedReader; + + private UnmanagedPdbSymbolReader(ISymUnmanagedReader symUnmanagedReader) + { + _symUnmanagedReader = symUnmanagedReader; + } + + public override void Dispose() + { + Marshal.ReleaseComObject(_symUnmanagedReader); + } + + private Dictionary _urlCache; + + private string GetUrl(ISymUnmanagedDocument doc) + { + lock (this) + { + if (_urlCache == null) + _urlCache = new Dictionary(); + + string url; + if (_urlCache.TryGetValue(doc, out url)) + return url; + + int urlLength; + ThrowExceptionForHR(doc.GetUrl(0, out urlLength, null)); + + // urlLength includes terminating '\0' + char[] urlBuffer = new char[urlLength]; + ThrowExceptionForHR(doc.GetUrl(urlLength, out urlLength, urlBuffer)); + + url = new string(urlBuffer, 0, urlLength - 1); + _urlCache.Add(doc, url); + return url; + } + } + + public override IEnumerable GetSequencePointsForMethod(int methodToken) + { + ISymUnmanagedMethod symbolMethod; + if (_symUnmanagedReader.GetMethod(methodToken, out symbolMethod) < 0) + yield break; + + int count; + ThrowExceptionForHR(symbolMethod.GetSequencePointCount(out count)); + + ISymUnmanagedDocument[] docs = new ISymUnmanagedDocument[count]; + int[] lineNumbers = new int[count]; + int[] ilOffsets = new int[count]; + + ThrowExceptionForHR(symbolMethod.GetSequencePoints(count, out count, ilOffsets, docs, lineNumbers, null, null, null)); + + for (int i = 0; i < count; i++) + { + if (lineNumbers[i] == 0xFEEFEE) + continue; + + yield return new ILSequencePoint(ilOffsets[i], GetUrl(docs[i]), lineNumbers[i]); + } + } + + // + // Gather the local details in a scope and then recurse to child scopes + // + private void ProbeScopeForLocals(List variables, ISymUnmanagedScope scope) + { + int localCount; + ThrowExceptionForHR(scope.GetLocalCount(out localCount)); + + ISymUnmanagedVariable[] locals = new ISymUnmanagedVariable[localCount]; + ThrowExceptionForHR(scope.GetLocals(localCount, out localCount, locals)); + + for (int i = 0; i < localCount; i++) + { + var local = locals[i]; + + int slot; + ThrowExceptionForHR(local.GetAddressField1(out slot)); + + int nameLength; + ThrowExceptionForHR(local.GetName(0, out nameLength, null)); + + // nameLength includes terminating '\0' + char[] nameBuffer = new char[nameLength]; + ThrowExceptionForHR(local.GetName(nameLength, out nameLength, nameBuffer)); + + int attributes; + ThrowExceptionForHR(local.GetAttributes(out attributes)); + + variables.Add(new ILLocalVariable(slot, new String(nameBuffer, 0, nameLength - 1), (attributes & 0x1) != 0)); + } + + int childrenCount; + ThrowExceptionForHR(scope.GetChildren(0, out childrenCount, null)); + + ISymUnmanagedScope[] children = new ISymUnmanagedScope[childrenCount]; + ThrowExceptionForHR(scope.GetChildren(childrenCount, out childrenCount, children)); + + for (int i = 0; i < childrenCount; i++) + { + ProbeScopeForLocals(variables, children[i]); + } + } + + // + // Recursively scan the scopes for a method stored in a PDB and gather the local slots + // and names for all of them. This assumes a CSC-like compiler that doesn't re-use + // local slots in the same method across scopes. + // + public override IEnumerable GetLocalVariableNamesForMethod(int methodToken) + { + ISymUnmanagedMethod symbolMethod; + if (_symUnmanagedReader.GetMethod(methodToken, out symbolMethod) < 0) + return null; + + ISymUnmanagedScope rootScope; + ThrowExceptionForHR(symbolMethod.GetRootScope(out rootScope)); + + var variables = new List(); + ProbeScopeForLocals(variables, rootScope); + return variables; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/EcmaMethodIL.Symbols.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/EcmaMethodIL.Symbols.cs new file mode 100644 index 00000000000..35b7c22e496 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/EcmaMethodIL.Symbols.cs @@ -0,0 +1,75 @@ +// 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.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using Internal.TypeSystem.Ecma; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL +{ + // Pluggable file that adds PDB handling functionality to EcmaMethodIL + partial class EcmaMethodIL + { + public override MethodDebugInformation GetDebugInfo() + { + if (_method.Module.PdbReader != null) + { + return new EcmaMethodDebugInformation(_method); + } + + return MethodDebugInformation.None; + } + } + + /// + /// Represents debugging information about a method backed by ECMA-335 metadata. + /// + public sealed class EcmaMethodDebugInformation : MethodDebugInformation + { + private EcmaMethod _method; + + public EcmaMethodDebugInformation(EcmaMethod method) + { + Debug.Assert(method.Module.PdbReader != null); + _method = method; + } + + public override IEnumerable GetSequencePoints() + { + return _method.Module.PdbReader.GetSequencePointsForMethod(MetadataTokens.GetToken(_method.Handle)); + } + + public override IEnumerable GetLocalVariables() + { + return _method.Module.PdbReader.GetLocalVariableNamesForMethod(MetadataTokens.GetToken(_method.Handle)); + } + + public override IEnumerable GetParameterNames() + { + ParameterHandleCollection parameters = _method.MetadataReader.GetMethodDefinition(_method.Handle).GetParameters(); + + if (!_method.Signature.IsStatic) + { + // TODO: this name might conflict with a parameter name or a local name. We need something unique. + yield return "___this"; + } + + // TODO: The Params table is allowed to have holes in it. This expect all parameters to be present. + foreach (var parameterHandle in parameters) + { + Parameter p = _method.MetadataReader.GetParameter(parameterHandle); + + // Parameter with sequence number 0 refers to the return parameter + if (p.SequenceNumber == 0) + continue; + + yield return _method.MetadataReader.GetString(p.Name); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/EcmaMethodIL.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/EcmaMethodIL.cs new file mode 100644 index 00000000000..f15b86762fd --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/EcmaMethodIL.cs @@ -0,0 +1,146 @@ +// 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.Collections.Immutable; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace Internal.IL +{ + public sealed partial class EcmaMethodIL : MethodIL + { + private readonly EcmaModule _module; + private readonly EcmaMethod _method; + private readonly MethodBodyBlock _methodBody; + + // Cached values + private byte[] _ilBytes; + private LocalVariableDefinition[] _locals; + private ILExceptionRegion[] _ilExceptionRegions; + + // TODO: Remove: Workaround for missing ClearInitLocals transforms in CoreRT CoreLib + private readonly bool _clearInitLocals; + + public static EcmaMethodIL Create(EcmaMethod method, bool clearInitLocals = false) + { + var rva = method.MetadataReader.GetMethodDefinition(method.Handle).RelativeVirtualAddress; + if (rva == 0) + return null; + return new EcmaMethodIL(method, rva, clearInitLocals); + } + + private EcmaMethodIL(EcmaMethod method, int rva, bool clearInitLocals) + { + _method = method; + _module = method.Module; + _methodBody = _module.PEReader.GetMethodBody(rva); + + _clearInitLocals = clearInitLocals; + } + + public EcmaModule Module + { + get + { + return _module; + } + } + + public override MethodDesc OwningMethod + { + get + { + return _method; + } + } + + public override byte[] GetILBytes() + { + if (_ilBytes != null) + return _ilBytes; + + byte[] ilBytes = _methodBody.GetILBytes(); + return (_ilBytes = ilBytes); + } + + public override bool IsInitLocals + { + get + { + return !_clearInitLocals && _methodBody.LocalVariablesInitialized; + } + } + + public override int MaxStack + { + get + { + return _methodBody.MaxStack; + } + } + + public override LocalVariableDefinition[] GetLocals() + { + if (_locals != null) + return _locals; + + var metadataReader = _module.MetadataReader; + var localSignature = _methodBody.LocalSignature; + if (localSignature.IsNil) + return Array.Empty(); + BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetStandaloneSignature(localSignature).Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(_module, signatureReader); + LocalVariableDefinition[] locals = parser.ParseLocalsSignature(); + return (_locals = locals); + } + + public override ILExceptionRegion[] GetExceptionRegions() + { + if (_ilExceptionRegions != null) + return _ilExceptionRegions; + + ImmutableArray exceptionRegions = _methodBody.ExceptionRegions; + ILExceptionRegion[] ilExceptionRegions; + + int length = exceptionRegions.Length; + if (length == 0) + { + ilExceptionRegions = Array.Empty(); + } + else + { + ilExceptionRegions = new ILExceptionRegion[length]; + for (int i = 0; i < length; i++) + { + var exceptionRegion = exceptionRegions[i]; + + ilExceptionRegions[i] = new ILExceptionRegion( + (ILExceptionRegionKind)exceptionRegion.Kind, // assumes that ILExceptionRegionKind and ExceptionRegionKind enums are in sync + exceptionRegion.TryOffset, + exceptionRegion.TryLength, + exceptionRegion.HandlerOffset, + exceptionRegion.HandlerLength, + MetadataTokens.GetToken(exceptionRegion.CatchType), + exceptionRegion.FilterOffset); + } + } + + return (_ilExceptionRegions = ilExceptionRegions); + } + + public override object GetObject(int token) + { + // UserStrings cannot be wrapped in EntityHandle + if ((token & 0xFF000000) == 0x70000000) + return _module.GetUserString(MetadataTokens.UserStringHandle(token)); + + return _module.GetObject(MetadataTokens.EntityHandle(token)); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/HelperExtensions.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/HelperExtensions.cs new file mode 100644 index 00000000000..682dab4f04b --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/HelperExtensions.cs @@ -0,0 +1,112 @@ +// 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.TypeSystem; +using Internal.IL.Stubs; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL +{ + internal static class HelperExtensions + { + public static MetadataType GetHelperType(this TypeSystemContext context, string name) + { + MetadataType helperType = context.SystemModule.GetKnownType("Internal.Runtime.CompilerHelpers", name); + return helperType; + } + + public static MethodDesc GetHelperEntryPoint(this TypeSystemContext context, string typeName, string methodName) + { + MetadataType helperType = context.GetHelperType(typeName); + MethodDesc helperMethod = helperType.GetKnownMethod(methodName, null); + return helperMethod; + } + + /// + /// Emits a call to a throw helper. Use this to emit calls to static parameterless methods that don't return. + /// The advantage of using this extension method is that you don't have to deal with what code to emit after + /// the call (e.g. do you need to make sure the stack is balanced?). + /// + public static void EmitCallThrowHelper(this ILCodeStream codeStream, ILEmitter emitter, MethodDesc method) + { + Debug.Assert(method.Signature.Length == 0 && method.Signature.IsStatic); + + // Emit a call followed by a branch to the call. + + // We are emitting this instead of emitting a tight loop that jumps to itself + // so that the JIT doesn't generate extra GC checks within the loop. + + ILCodeLabel label = emitter.NewCodeLabel(); + codeStream.EmitLabel(label); + codeStream.Emit(ILOpcode.call, emitter.NewToken(method)); + codeStream.Emit(ILOpcode.br, label); + } + + /// + /// Retrieves a method on that is well known to the compiler. + /// Throws an exception if the method doesn't exist. + /// + public static MethodDesc GetKnownMethod(this TypeDesc type, string name, MethodSignature signature) + { + MethodDesc method = type.GetMethod(name, signature); + if (method == null) + { + throw new InvalidOperationException(String.Format("Expected method '{0}' not found on type '{1}'", name, type)); + } + + return method; + } + + /// + /// Retrieves a field on that is well known to the compiler. + /// Throws an exception if the field doesn't exist. + /// + public static FieldDesc GetKnownField(this TypeDesc type, string name) + { + FieldDesc field = type.GetField(name); + if (field == null) + { + throw new InvalidOperationException(String.Format("Expected field '{0}' not found on type '{1}'", name, type)); + } + + return field; + } + + /// + /// Retrieves a nested type on that is well known to the compiler. + /// Throws an exception if the nested type doesn't exist. + /// + 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; + } + + /// + /// Retrieves a namespace type in that is well known to the compiler. + /// Throws an exception if the type doesn't exist. + /// + public static MetadataType GetKnownType(this ModuleDesc module, string @namespace, string name) + { + MetadataType type = module.GetType(@namespace, name, false); + if (type == null) + { + throw new InvalidOperationException( + String.Format("Expected type '{0}' not found in module '{1}'", + @namespace.Length > 0 ? String.Concat(@namespace, ".", name) : name, + module)); + } + + return type; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/ILDisassembler.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/ILDisassembler.cs new file mode 100644 index 00000000000..c7fb70f6e8e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/ILDisassembler.cs @@ -0,0 +1,633 @@ +// 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.Text; + +using Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL +{ + // Known shortcomings: + // - Escaping identifier names is missing (special characters and ILASM identifier names) + // - Array bounds in signatures missing + // - Custom modifiers and PINNED constraint not decoded in signatures + // - Calling conventions in signatures not decoded + // - Vararg signatures + // - Floating point numbers are not represented in roundtrippable format + + /// + /// Helper struct to disassemble IL instructions into a textual representation. + /// + public struct ILDisassembler + { + private byte[] _ilBytes; + private MethodIL _methodIL; + private ILTypeNameFormatter _typeNameFormatter; + private int _currentOffset; + + public ILDisassembler(MethodIL methodIL) + { + _methodIL = methodIL; + _ilBytes = methodIL.GetILBytes(); + _currentOffset = 0; + _typeNameFormatter = null; + } + + #region Type/member/signature name formatting + private ILTypeNameFormatter TypeNameFormatter + { + get + { + if (_typeNameFormatter == null) + { + // Find the owning module so that the type name formatter can remove + // redundant assembly name qualifiers in type names. + TypeDesc owningTypeDefinition = _methodIL.OwningMethod.OwningType; + ModuleDesc owningModule = owningTypeDefinition is MetadataType ? + ((MetadataType)owningTypeDefinition).Module : null; + + _typeNameFormatter = new ILTypeNameFormatter(owningModule); + } + return _typeNameFormatter; + } + } + + public void AppendType(StringBuilder sb, TypeDesc type, bool forceValueClassPrefix = true) + { + // Types referenced from the IL show as instantiated over generic parameter. + // E.g. "initobj !0" becomes "initobj !T" + TypeDesc typeInContext = type.InstantiateSignature( + _methodIL.OwningMethod.OwningType.Instantiation, _methodIL.OwningMethod.Instantiation); + if (typeInContext.HasInstantiation || forceValueClassPrefix) + this.TypeNameFormatter.AppendNameWithValueClassPrefix(sb, typeInContext); + else + this.TypeNameFormatter.AppendName(sb, typeInContext); + } + + private void AppendOwningType(StringBuilder sb, TypeDesc type) + { + // Special case primitive types: we don't want to use short names here + if (type.IsPrimitive || type.IsString || type.IsObject) + _typeNameFormatter.AppendNameForNamespaceTypeWithoutAliases(sb, (MetadataType)type); + else + AppendType(sb, type, false); + } + + private void AppendMethodSignature(StringBuilder sb, MethodDesc method) + { + // If this is an instantiated generic method, the formatted signature should + // be uninstantiated (e.g. "void Foo::Bar(!!0 param)", not "void Foo::Bar(int param)") + MethodSignature signature = method.GetMethodDefinition().Signature; + + AppendSignaturePrefix(sb, signature); + sb.Append(' '); + AppendOwningType(sb, method.OwningType); + sb.Append("::"); + sb.Append(method.Name); + + if (method.HasInstantiation) + { + sb.Append('<'); + + for (int i = 0; i < method.Instantiation.Length; i++) + { + if (i != 0) + sb.Append(", "); + _typeNameFormatter.AppendNameWithValueClassPrefix(sb, method.Instantiation[i]); + } + + sb.Append('>'); + } + + sb.Append('('); + AppendSignatureArgumentList(sb, signature); + sb.Append(')'); + } + + private void AppendMethodSignature(StringBuilder sb, MethodSignature signature) + { + AppendSignaturePrefix(sb, signature); + sb.Append('('); + AppendSignatureArgumentList(sb, signature); + sb.Append(')'); + } + + private void AppendSignaturePrefix(StringBuilder sb, MethodSignature signature) + { + if (!signature.IsStatic) + sb.Append("instance "); + + this.TypeNameFormatter.AppendNameWithValueClassPrefix(sb, signature.ReturnType); + } + + private void AppendSignatureArgumentList(StringBuilder sb, MethodSignature signature) + { + for (int i = 0; i < signature.Length; i++) + { + if (i != 0) + sb.Append(", "); + + this.TypeNameFormatter.AppendNameWithValueClassPrefix(sb, signature[i]); + } + } + + private void AppendFieldSignature(StringBuilder sb, FieldDesc field) + { + this.TypeNameFormatter.AppendNameWithValueClassPrefix(sb, field.FieldType); + sb.Append(' '); + AppendOwningType(sb, field.OwningType); + sb.Append("::"); + sb.Append(field.Name); + } + + private void AppendStringLiteral(StringBuilder sb, string s) + { + sb.Append('"'); + for (int i = 0; i < s.Length; i++) + { + if (s[i] == '\\') + sb.Append("\\\\"); + else if (s[i] == '\t') + sb.Append("\\t"); + else if (s[i] == '"') + sb.Append("\\\""); + else if (s[i] == '\n') + sb.Append("\\n"); + else + sb.Append(s[i]); + } + sb.Append('"'); + } + + private void AppendToken(StringBuilder sb, int token) + { + object obj = _methodIL.GetObject(token); + if (obj is MethodDesc) + AppendMethodSignature(sb, (MethodDesc)obj); + else if (obj is FieldDesc) + AppendFieldSignature(sb, (FieldDesc)obj); + else if (obj is MethodSignature) + AppendMethodSignature(sb, (MethodSignature)obj); + else if (obj is TypeDesc) + AppendType(sb, (TypeDesc)obj, false); + else + { + Debug.Assert(obj is string, "NYI: " + obj.GetType()); + AppendStringLiteral(sb, (string)obj); + } + } + #endregion + + #region Instruction decoding + private byte ReadILByte() + { + return _ilBytes[_currentOffset++]; + } + + private UInt16 ReadILUInt16() + { + UInt16 val = (UInt16)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8)); + _currentOffset += 2; + return val; + } + + private UInt32 ReadILUInt32() + { + UInt32 val = (UInt32)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8) + (_ilBytes[_currentOffset + 2] << 16) + (_ilBytes[_currentOffset + 3] << 24)); + _currentOffset += 4; + return val; + } + + private int ReadILToken() + { + return (int)ReadILUInt32(); + } + + private ulong ReadILUInt64() + { + ulong value = ReadILUInt32(); + value |= (((ulong)ReadILUInt32()) << 32); + return value; + } + + private unsafe float ReadILFloat() + { + uint value = ReadILUInt32(); + return *(float*)(&value); + } + + private unsafe double ReadILDouble() + { + ulong value = ReadILUInt64(); + return *(double*)(&value); + } + + public static void AppendOffset(StringBuilder sb, int offset) + { + sb.Append("IL_"); + sb.AppendFormat("{0:X4}", offset); + } + + private static void PadForInstructionArgument(StringBuilder sb) + { + if (sb.Length < 22) + sb.Append(' ', 22 - sb.Length); + else + sb.Append(' '); + } + + public bool HasNextInstruction + { + get + { + return _currentOffset < _ilBytes.Length; + } + } + + public int Offset + { + get + { + return _currentOffset; + } + } + + public int CodeSize + { + get + { + return _ilBytes.Length; + } + } + + public string GetNextInstruction() + { + StringBuilder decodedInstruction = new StringBuilder(); + AppendOffset(decodedInstruction, _currentOffset); + decodedInstruction.Append(": "); + + again: + + ILOpcode opCode = (ILOpcode)ReadILByte(); + if (opCode == ILOpcode.prefix1) + { + opCode = (ILOpcode)(0x100 + ReadILByte()); + } + + // Quick and dirty way to get the opcode name is to convert the enum value to string. + // We need some adjustments though. + string opCodeString = opCode.ToString().Replace("_", "."); + if (opCodeString.EndsWith(".")) + opCodeString = opCodeString.Substring(0, opCodeString.Length - 1); + + decodedInstruction.Append(opCodeString); + + switch (opCode) + { + case ILOpcode.ldarg_s: + case ILOpcode.ldarga_s: + case ILOpcode.starg_s: + case ILOpcode.ldloc_s: + case ILOpcode.ldloca_s: + case ILOpcode.stloc_s: + case ILOpcode.ldc_i4_s: + PadForInstructionArgument(decodedInstruction); + decodedInstruction.Append(ReadILByte().ToStringInvariant()); + return decodedInstruction.ToString(); + + case ILOpcode.unaligned: + decodedInstruction.Append(' '); + decodedInstruction.Append(ReadILByte().ToStringInvariant()); + decodedInstruction.Append(' '); + goto again; + + case ILOpcode.ldarg: + case ILOpcode.ldarga: + case ILOpcode.starg: + case ILOpcode.ldloc: + case ILOpcode.ldloca: + case ILOpcode.stloc: + PadForInstructionArgument(decodedInstruction); + decodedInstruction.Append(ReadILUInt16().ToStringInvariant()); + return decodedInstruction.ToString(); + + case ILOpcode.ldc_i4: + PadForInstructionArgument(decodedInstruction); + decodedInstruction.Append(ReadILUInt32().ToStringInvariant()); + return decodedInstruction.ToString(); + + case ILOpcode.ldc_r4: + PadForInstructionArgument(decodedInstruction); + decodedInstruction.Append(ReadILFloat().ToStringInvariant()); + return decodedInstruction.ToString(); + + case ILOpcode.ldc_i8: + PadForInstructionArgument(decodedInstruction); + decodedInstruction.Append(ReadILUInt64().ToStringInvariant()); + return decodedInstruction.ToString(); + + case ILOpcode.ldc_r8: + PadForInstructionArgument(decodedInstruction); + decodedInstruction.Append(ReadILDouble().ToStringInvariant()); + return decodedInstruction.ToString(); + + case ILOpcode.jmp: + case ILOpcode.call: + case ILOpcode.calli: + case ILOpcode.callvirt: + case ILOpcode.cpobj: + case ILOpcode.ldobj: + case ILOpcode.ldstr: + case ILOpcode.newobj: + case ILOpcode.castclass: + case ILOpcode.isinst: + case ILOpcode.unbox: + case ILOpcode.ldfld: + case ILOpcode.ldflda: + case ILOpcode.stfld: + case ILOpcode.ldsfld: + case ILOpcode.ldsflda: + case ILOpcode.stsfld: + case ILOpcode.stobj: + case ILOpcode.box: + case ILOpcode.newarr: + case ILOpcode.ldelema: + case ILOpcode.ldelem: + case ILOpcode.stelem: + case ILOpcode.unbox_any: + case ILOpcode.refanyval: + case ILOpcode.mkrefany: + case ILOpcode.ldtoken: + case ILOpcode.ldftn: + case ILOpcode.ldvirtftn: + case ILOpcode.initobj: + case ILOpcode.constrained: + case ILOpcode.sizeof_: + PadForInstructionArgument(decodedInstruction); + AppendToken(decodedInstruction, ReadILToken()); + return decodedInstruction.ToString(); + + case ILOpcode.br_s: + case ILOpcode.leave_s: + case ILOpcode.brfalse_s: + case ILOpcode.brtrue_s: + case ILOpcode.beq_s: + case ILOpcode.bge_s: + case ILOpcode.bgt_s: + case ILOpcode.ble_s: + case ILOpcode.blt_s: + case ILOpcode.bne_un_s: + case ILOpcode.bge_un_s: + case ILOpcode.bgt_un_s: + case ILOpcode.ble_un_s: + case ILOpcode.blt_un_s: + PadForInstructionArgument(decodedInstruction); + AppendOffset(decodedInstruction, (sbyte)ReadILByte() + _currentOffset); + return decodedInstruction.ToString(); + + case ILOpcode.br: + case ILOpcode.leave: + case ILOpcode.brfalse: + case ILOpcode.brtrue: + case ILOpcode.beq: + case ILOpcode.bge: + case ILOpcode.bgt: + case ILOpcode.ble: + case ILOpcode.blt: + case ILOpcode.bne_un: + case ILOpcode.bge_un: + case ILOpcode.bgt_un: + case ILOpcode.ble_un: + case ILOpcode.blt_un: + PadForInstructionArgument(decodedInstruction); + AppendOffset(decodedInstruction, (int)ReadILUInt32() + _currentOffset); + return decodedInstruction.ToString(); + + case ILOpcode.switch_: + { + decodedInstruction.Clear(); + decodedInstruction.Append("switch ("); + uint count = ReadILUInt32(); + int jmpBase = _currentOffset + (int)(4 * count); + for (uint i = 0; i < count; i++) + { + if (i != 0) + decodedInstruction.Append(", "); + int delta = (int)ReadILUInt32(); + AppendOffset(decodedInstruction, jmpBase + delta); + } + decodedInstruction.Append(")"); + return decodedInstruction.ToString(); + } + + default: + return decodedInstruction.ToString(); + } + } + #endregion + + #region Helpers + public class ILTypeNameFormatter : TypeNameFormatter + { + private ModuleDesc _thisModule; + + public ILTypeNameFormatter(ModuleDesc thisModule) + { + _thisModule = thisModule; + } + + public void AppendNameWithValueClassPrefix(StringBuilder sb, TypeDesc type) + { + if (!type.IsSignatureVariable + && type.IsDefType + && !type.IsPrimitive + && !type.IsObject + && !type.IsString) + { + string prefix = type.IsValueType ? "valuetype " : "class "; + sb.Append(prefix); + AppendName(sb, type); + } + else + { + AppendName(sb, type); + } + } + + public override void AppendName(StringBuilder sb, PointerType type) + { + AppendNameWithValueClassPrefix(sb, type.ParameterType); + sb.Append('*'); + } + + public override void AppendName(StringBuilder sb, FunctionPointerType type) + { + MethodSignature signature = type.Signature; + + sb.Append("method "); + + if (!signature.IsStatic) + sb.Append("instance "); + + // TODO: rest of calling conventions + + AppendName(sb, signature.ReturnType); + + sb.Append(" *("); + for (int i = 0; i < signature.Length; i++) + { + if (i > 0) + sb.Append(", "); + AppendName(sb, signature[i]); + } + sb.Append(')'); + } + + public override void AppendName(StringBuilder sb, SignatureMethodVariable type) + { + sb.Append("!!"); + sb.Append(type.Index.ToStringInvariant()); + } + + public override void AppendName(StringBuilder sb, SignatureTypeVariable type) + { + sb.Append("!"); + sb.Append(type.Index.ToStringInvariant()); + } + + public override void AppendName(StringBuilder sb, GenericParameterDesc type) + { + string prefix = type.Kind == GenericParameterKind.Type ? "!" : "!!"; + sb.Append(prefix); + sb.Append(type.Name); + } + + protected override void AppendNameForInstantiatedType(StringBuilder sb, DefType type) + { + AppendName(sb, type.GetTypeDefinition()); + sb.Append('<'); + + for (int i = 0; i < type.Instantiation.Length; i++) + { + if (i > 0) + sb.Append(", "); + AppendNameWithValueClassPrefix(sb, type.Instantiation[i]); + } + + sb.Append('>'); + } + + public override void AppendName(StringBuilder sb, ByRefType type) + { + AppendNameWithValueClassPrefix(sb, type.ParameterType); + sb.Append('&'); + } + + public override void AppendName(StringBuilder sb, ArrayType type) + { + AppendNameWithValueClassPrefix(sb, type.ElementType); + sb.Append('['); + sb.Append(',', type.Rank - 1); + sb.Append(']'); + } + + protected override void AppendNameForNamespaceType(StringBuilder sb, DefType type) + { + switch (type.Category) + { + case TypeFlags.Void: + sb.Append("void"); + return; + case TypeFlags.Boolean: + sb.Append("bool"); + return; + case TypeFlags.Char: + sb.Append("char"); + return; + case TypeFlags.SByte: + sb.Append("int8"); + return; + case TypeFlags.Byte: + sb.Append("uint8"); + return; + case TypeFlags.Int16: + sb.Append("int16"); + return; + case TypeFlags.UInt16: + sb.Append("uint16"); + return; + case TypeFlags.Int32: + sb.Append("int32"); + return; + case TypeFlags.UInt32: + sb.Append("uint32"); + return; + case TypeFlags.Int64: + sb.Append("int64"); + return; + case TypeFlags.UInt64: + sb.Append("uint64"); + return; + case TypeFlags.IntPtr: + sb.Append("native int"); + return; + case TypeFlags.UIntPtr: + sb.Append("native uint"); + return; + case TypeFlags.Single: + sb.Append("float32"); + return; + case TypeFlags.Double: + sb.Append("float64"); + return; + } + + if (type.IsString) + { + sb.Append("string"); + return; + } + + if (type.IsObject) + { + sb.Append("object"); + return; + } + + AppendNameForNamespaceTypeWithoutAliases(sb, type); + } + public void AppendNameForNamespaceTypeWithoutAliases(StringBuilder sb, DefType type) + { + ModuleDesc owningModule = (type as MetadataType)?.Module; + if (owningModule != null && owningModule != _thisModule) + { + Debug.Assert(owningModule is IAssemblyDesc); + string owningModuleName = ((IAssemblyDesc)owningModule).GetName().Name; + sb.Append('['); + sb.Append(owningModuleName); + sb.Append(']'); + } + + string ns = type.Namespace; + if (ns.Length > 0) + { + sb.Append(ns); + sb.Append('.'); + } + sb.Append(type.Name); + } + + protected override void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType) + { + AppendName(sb, containingType); + sb.Append('/'); + sb.Append(nestedType.Name); + } + } + #endregion + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/ILOpcode.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/ILOpcode.cs new file mode 100644 index 00000000000..e031553f537 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/ILOpcode.cs @@ -0,0 +1,235 @@ +// 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; + +namespace Internal.IL +{ + /// + /// An enumeration of all of the operation codes that are used in the CLI Common Intermediate Language. + /// + public enum ILOpcode + { + nop = 0x00, + break_ = 0x01, + ldarg_0 = 0x02, + ldarg_1 = 0x03, + ldarg_2 = 0x04, + ldarg_3 = 0x05, + ldloc_0 = 0x06, + ldloc_1 = 0x07, + ldloc_2 = 0x08, + ldloc_3 = 0x09, + stloc_0 = 0x0a, + stloc_1 = 0x0b, + stloc_2 = 0x0c, + stloc_3 = 0x0d, + ldarg_s = 0x0e, + ldarga_s = 0x0f, + starg_s = 0x10, + ldloc_s = 0x11, + ldloca_s = 0x12, + stloc_s = 0x13, + ldnull = 0x14, + ldc_i4_m1 = 0x15, + ldc_i4_0 = 0x16, + ldc_i4_1 = 0x17, + ldc_i4_2 = 0x18, + ldc_i4_3 = 0x19, + ldc_i4_4 = 0x1a, + ldc_i4_5 = 0x1b, + ldc_i4_6 = 0x1c, + ldc_i4_7 = 0x1d, + ldc_i4_8 = 0x1e, + ldc_i4_s = 0x1f, + ldc_i4 = 0x20, + ldc_i8 = 0x21, + ldc_r4 = 0x22, + ldc_r8 = 0x23, + dup = 0x25, + pop = 0x26, + jmp = 0x27, + call = 0x28, + calli = 0x29, + ret = 0x2a, + br_s = 0x2b, + brfalse_s = 0x2c, + brtrue_s = 0x2d, + beq_s = 0x2e, + bge_s = 0x2f, + bgt_s = 0x30, + ble_s = 0x31, + blt_s = 0x32, + bne_un_s = 0x33, + bge_un_s = 0x34, + bgt_un_s = 0x35, + ble_un_s = 0x36, + blt_un_s = 0x37, + br = 0x38, + brfalse = 0x39, + brtrue = 0x3a, + beq = 0x3b, + bge = 0x3c, + bgt = 0x3d, + ble = 0x3e, + blt = 0x3f, + bne_un = 0x40, + bge_un = 0x41, + bgt_un = 0x42, + ble_un = 0x43, + blt_un = 0x44, + switch_ = 0x45, + ldind_i1 = 0x46, + ldind_u1 = 0x47, + ldind_i2 = 0x48, + ldind_u2 = 0x49, + ldind_i4 = 0x4a, + ldind_u4 = 0x4b, + ldind_i8 = 0x4c, + ldind_i = 0x4d, + ldind_r4 = 0x4e, + ldind_r8 = 0x4f, + ldind_ref = 0x50, + stind_ref = 0x51, + stind_i1 = 0x52, + stind_i2 = 0x53, + stind_i4 = 0x54, + stind_i8 = 0x55, + stind_r4 = 0x56, + stind_r8 = 0x57, + add = 0x58, + sub = 0x59, + mul = 0x5a, + div = 0x5b, + div_un = 0x5c, + rem = 0x5d, + rem_un = 0x5e, + and = 0x5f, + or = 0x60, + xor = 0x61, + shl = 0x62, + shr = 0x63, + shr_un = 0x64, + neg = 0x65, + not = 0x66, + conv_i1 = 0x67, + conv_i2 = 0x68, + conv_i4 = 0x69, + conv_i8 = 0x6a, + conv_r4 = 0x6b, + conv_r8 = 0x6c, + conv_u4 = 0x6d, + conv_u8 = 0x6e, + callvirt = 0x6f, + cpobj = 0x70, + ldobj = 0x71, + ldstr = 0x72, + newobj = 0x73, + castclass = 0x74, + isinst = 0x75, + conv_r_un = 0x76, + unbox = 0x79, + throw_ = 0x7a, + ldfld = 0x7b, + ldflda = 0x7c, + stfld = 0x7d, + ldsfld = 0x7e, + ldsflda = 0x7f, + stsfld = 0x80, + stobj = 0x81, + conv_ovf_i1_un = 0x82, + conv_ovf_i2_un = 0x83, + conv_ovf_i4_un = 0x84, + conv_ovf_i8_un = 0x85, + conv_ovf_u1_un = 0x86, + conv_ovf_u2_un = 0x87, + conv_ovf_u4_un = 0x88, + conv_ovf_u8_un = 0x89, + conv_ovf_i_un = 0x8a, + conv_ovf_u_un = 0x8b, + box = 0x8c, + newarr = 0x8d, + ldlen = 0x8e, + ldelema = 0x8f, + ldelem_i1 = 0x90, + ldelem_u1 = 0x91, + ldelem_i2 = 0x92, + ldelem_u2 = 0x93, + ldelem_i4 = 0x94, + ldelem_u4 = 0x95, + ldelem_i8 = 0x96, + ldelem_i = 0x97, + ldelem_r4 = 0x98, + ldelem_r8 = 0x99, + ldelem_ref = 0x9a, + stelem_i = 0x9b, + stelem_i1 = 0x9c, + stelem_i2 = 0x9d, + stelem_i4 = 0x9e, + stelem_i8 = 0x9f, + stelem_r4 = 0xa0, + stelem_r8 = 0xa1, + stelem_ref = 0xa2, + ldelem = 0xa3, + stelem = 0xa4, + unbox_any = 0xa5, + conv_ovf_i1 = 0xb3, + conv_ovf_u1 = 0xb4, + conv_ovf_i2 = 0xb5, + conv_ovf_u2 = 0xb6, + conv_ovf_i4 = 0xb7, + conv_ovf_u4 = 0xb8, + conv_ovf_i8 = 0xb9, + conv_ovf_u8 = 0xba, + refanyval = 0xc2, + ckfinite = 0xc3, + mkrefany = 0xc6, + ldtoken = 0xd0, + conv_u2 = 0xd1, + conv_u1 = 0xd2, + conv_i = 0xd3, + conv_ovf_i = 0xd4, + conv_ovf_u = 0xd5, + add_ovf = 0xd6, + add_ovf_un = 0xd7, + mul_ovf = 0xd8, + mul_ovf_un = 0xd9, + sub_ovf = 0xda, + sub_ovf_un = 0xdb, + endfinally = 0xdc, + leave = 0xdd, + leave_s = 0xde, + stind_i = 0xdf, + conv_u = 0xe0, + prefix1 = 0xfe, + arglist = 0x100, + ceq = 0x101, + cgt = 0x102, + cgt_un = 0x103, + clt = 0x104, + clt_un = 0x105, + ldftn = 0x106, + ldvirtftn = 0x107, + ldarg = 0x109, + ldarga = 0x10a, + starg = 0x10b, + ldloc = 0x10c, + ldloca = 0x10d, + stloc = 0x10e, + localloc = 0x10f, + endfilter = 0x111, + unaligned = 0x112, + volatile_ = 0x113, + tail = 0x114, + initobj = 0x115, + constrained = 0x116, + cpblk = 0x117, + initblk = 0x118, + no = 0x119, + rethrow = 0x11a, + sizeof_ = 0x11c, + refanytype = 0x11d, + readonly_ = 0x11e, + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/ILOpcodeHelper.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/ILOpcodeHelper.cs new file mode 100644 index 00000000000..b051e205f08 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/ILOpcodeHelper.cs @@ -0,0 +1,328 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.IL +{ + public static class ILOpcodeHelper + { + private const byte VariableSize = 0xFF; + private const byte Invalid = 0xFE; + + /// + /// Gets the size, in bytes, of the opcode and its arguments. + /// Note: if '' is , + /// the caller must handle it differently as that opcode is variable sized. + /// + public static int GetSize(this ILOpcode opcode) + { + Debug.Assert((uint)opcode < (uint)s_opcodeSizes.Length); + byte result = s_opcodeSizes[(int)opcode]; + Debug.Assert(result != VariableSize); + Debug.Assert(result != Invalid); + return result; + } + + /// + /// Returns true if '' is a valid opcode. + /// + public static bool IsValid(this ILOpcode opcode) + { + return (uint)opcode < (uint)s_opcodeSizes.Length + && s_opcodeSizes[(int)opcode] != Invalid; + } + + private static readonly byte[] s_opcodeSizes = new byte[] + { + 1, // nop = 0x00, + 1, // break_ = 0x01, + 1, // ldarg_0 = 0x02, + 1, // ldarg_1 = 0x03, + 1, // ldarg_2 = 0x04, + 1, // ldarg_3 = 0x05, + 1, // ldloc_0 = 0x06, + 1, // ldloc_1 = 0x07, + 1, // ldloc_2 = 0x08, + 1, // ldloc_3 = 0x09, + 1, // stloc_0 = 0x0a, + 1, // stloc_1 = 0x0b, + 1, // stloc_2 = 0x0c, + 1, // stloc_3 = 0x0d, + 2, // ldarg_s = 0x0e, + 2, // ldarga_s = 0x0f, + 2, // starg_s = 0x10, + 2, // ldloc_s = 0x11, + 2, // ldloca_s = 0x12, + 2, // stloc_s = 0x13, + 1, // ldnull = 0x14, + 1, // ldc_i4_m1 = 0x15, + 1, // ldc_i4_0 = 0x16, + 1, // ldc_i4_1 = 0x17, + 1, // ldc_i4_2 = 0x18, + 1, // ldc_i4_3 = 0x19, + 1, // ldc_i4_4 = 0x1a, + 1, // ldc_i4_5 = 0x1b, + 1, // ldc_i4_6 = 0x1c, + 1, // ldc_i4_7 = 0x1d, + 1, // ldc_i4_8 = 0x1e, + 2, // ldc_i4_s = 0x1f, + 5, // ldc_i4 = 0x20, + 9, // ldc_i8 = 0x21, + 5, // ldc_r4 = 0x22, + 9, // ldc_r8 = 0x23, + Invalid, // = 0x24, + 1, // dup = 0x25, + 1, // pop = 0x26, + 5, // jmp = 0x27, + 5, // call = 0x28, + 5, // calli = 0x29, + 1, // ret = 0x2a, + 2, // br_s = 0x2b, + 2, // brfalse_s = 0x2c, + 2, // brtrue_s = 0x2d, + 2, // beq_s = 0x2e, + 2, // bge_s = 0x2f, + 2, // bgt_s = 0x30, + 2, // ble_s = 0x31, + 2, // blt_s = 0x32, + 2, // bne_un_s = 0x33, + 2, // bge_un_s = 0x34, + 2, // bgt_un_s = 0x35, + 2, // ble_un_s = 0x36, + 2, // blt_un_s = 0x37, + 5, // br = 0x38, + 5, // brfalse = 0x39, + 5, // brtrue = 0x3a, + 5, // beq = 0x3b, + 5, // bge = 0x3c, + 5, // bgt = 0x3d, + 5, // ble = 0x3e, + 5, // blt = 0x3f, + 5, // bne_un = 0x40, + 5, // bge_un = 0x41, + 5, // bgt_un = 0x42, + 5, // ble_un = 0x43, + 5, // blt_un = 0x44, + VariableSize, // switch_ = 0x45, + 1, // ldind_i1 = 0x46, + 1, // ldind_u1 = 0x47, + 1, // ldind_i2 = 0x48, + 1, // ldind_u2 = 0x49, + 1, // ldind_i4 = 0x4a, + 1, // ldind_u4 = 0x4b, + 1, // ldind_i8 = 0x4c, + 1, // ldind_i = 0x4d, + 1, // ldind_r4 = 0x4e, + 1, // ldind_r8 = 0x4f, + 1, // ldind_ref = 0x50, + 1, // stind_ref = 0x51, + 1, // stind_i1 = 0x52, + 1, // stind_i2 = 0x53, + 1, // stind_i4 = 0x54, + 1, // stind_i8 = 0x55, + 1, // stind_r4 = 0x56, + 1, // stind_r8 = 0x57, + 1, // add = 0x58, + 1, // sub = 0x59, + 1, // mul = 0x5a, + 1, // div = 0x5b, + 1, // div_un = 0x5c, + 1, // rem = 0x5d, + 1, // rem_un = 0x5e, + 1, // and = 0x5f, + 1, // or = 0x60, + 1, // xor = 0x61, + 1, // shl = 0x62, + 1, // shr = 0x63, + 1, // shr_un = 0x64, + 1, // neg = 0x65, + 1, // not = 0x66, + 1, // conv_i1 = 0x67, + 1, // conv_i2 = 0x68, + 1, // conv_i4 = 0x69, + 1, // conv_i8 = 0x6a, + 1, // conv_r4 = 0x6b, + 1, // conv_r8 = 0x6c, + 1, // conv_u4 = 0x6d, + 1, // conv_u8 = 0x6e, + 5, // callvirt = 0x6f, + 5, // cpobj = 0x70, + 5, // ldobj = 0x71, + 5, // ldstr = 0x72, + 5, // newobj = 0x73, + 5, // castclass = 0x74, + 5, // isinst = 0x75, + 1, // conv_r_un = 0x76, + Invalid, // = 0x77, + Invalid, // = 0x78, + 5, // unbox = 0x79, + 1, // throw_ = 0x7a, + 5, // ldfld = 0x7b, + 5, // ldflda = 0x7c, + 5, // stfld = 0x7d, + 5, // ldsfld = 0x7e, + 5, // ldsflda = 0x7f, + 5, // stsfld = 0x80, + 5, // stobj = 0x81, + 1, // conv_ovf_i1_un = 0x82, + 1, // conv_ovf_i2_un = 0x83, + 1, // conv_ovf_i4_un = 0x84, + 1, // conv_ovf_i8_un = 0x85, + 1, // conv_ovf_u1_un = 0x86, + 1, // conv_ovf_u2_un = 0x87, + 1, // conv_ovf_u4_un = 0x88, + 1, // conv_ovf_u8_un = 0x89, + 1, // conv_ovf_i_un = 0x8a, + 1, // conv_ovf_u_un = 0x8b, + 5, // box = 0x8c, + 5, // newarr = 0x8d, + 1, // ldlen = 0x8e, + 5, // ldelema = 0x8f, + 1, // ldelem_i1 = 0x90, + 1, // ldelem_u1 = 0x91, + 1, // ldelem_i2 = 0x92, + 1, // ldelem_u2 = 0x93, + 1, // ldelem_i4 = 0x94, + 1, // ldelem_u4 = 0x95, + 1, // ldelem_i8 = 0x96, + 1, // ldelem_i = 0x97, + 1, // ldelem_r4 = 0x98, + 1, // ldelem_r8 = 0x99, + 1, // ldelem_ref = 0x9a, + 1, // stelem_i = 0x9b, + 1, // stelem_i1 = 0x9c, + 1, // stelem_i2 = 0x9d, + 1, // stelem_i4 = 0x9e, + 1, // stelem_i8 = 0x9f, + 1, // stelem_r4 = 0xa0, + 1, // stelem_r8 = 0xa1, + 1, // stelem_ref = 0xa2, + 5, // ldelem = 0xa3, + 5, // stelem = 0xa4, + 5, // unbox_any = 0xa5, + Invalid, // = 0xa6, + Invalid, // = 0xa7, + Invalid, // = 0xa8, + Invalid, // = 0xa9, + Invalid, // = 0xaa, + Invalid, // = 0xab, + Invalid, // = 0xac, + Invalid, // = 0xad, + Invalid, // = 0xae, + Invalid, // = 0xaf, + Invalid, // = 0xb0, + Invalid, // = 0xb1, + Invalid, // = 0xb2, + 1, // conv_ovf_i1 = 0xb3, + 1, // conv_ovf_u1 = 0xb4, + 1, // conv_ovf_i2 = 0xb5, + 1, // conv_ovf_u2 = 0xb6, + 1, // conv_ovf_i4 = 0xb7, + 1, // conv_ovf_u4 = 0xb8, + 1, // conv_ovf_i8 = 0xb9, + 1, // conv_ovf_u8 = 0xba, + Invalid, // = 0xbb, + Invalid, // = 0xbc, + Invalid, // = 0xbd, + Invalid, // = 0xbe, + Invalid, // = 0xbf, + Invalid, // = 0xc0, + Invalid, // = 0xc1, + 5, // refanyval = 0xc2, + 1, // ckfinite = 0xc3, + Invalid, // = 0xc4, + Invalid, // = 0xc5, + 5, // mkrefany = 0xc6, + Invalid, // = 0xc7, + Invalid, // = 0xc8, + Invalid, // = 0xc9, + Invalid, // = 0xca, + Invalid, // = 0xcb, + Invalid, // = 0xcc, + Invalid, // = 0xcd, + Invalid, // = 0xce, + Invalid, // = 0xcf, + 5, // ldtoken = 0xd0, + 1, // conv_u2 = 0xd1, + 1, // conv_u1 = 0xd2, + 1, // conv_i = 0xd3, + 1, // conv_ovf_i = 0xd4, + 1, // conv_ovf_u = 0xd5, + 1, // add_ovf = 0xd6, + 1, // add_ovf_un = 0xd7, + 1, // mul_ovf = 0xd8, + 1, // mul_ovf_un = 0xd9, + 1, // sub_ovf = 0xda, + 1, // sub_ovf_un = 0xdb, + 1, // endfinally = 0xdc, + 5, // leave = 0xdd, + 2, // leave_s = 0xde, + 1, // stind_i = 0xdf, + 1, // conv_u = 0xe0, + Invalid, // = 0xe1, + Invalid, // = 0xe2, + Invalid, // = 0xe3, + Invalid, // = 0xe4, + Invalid, // = 0xe5, + Invalid, // = 0xe6, + Invalid, // = 0xe7, + Invalid, // = 0xe8, + Invalid, // = 0xe9, + Invalid, // = 0xea, + Invalid, // = 0xeb, + Invalid, // = 0xec, + Invalid, // = 0xed, + Invalid, // = 0xee, + Invalid, // = 0xef, + Invalid, // = 0xf0, + Invalid, // = 0xf1, + Invalid, // = 0xf2, + Invalid, // = 0xf3, + Invalid, // = 0xf4, + Invalid, // = 0xf5, + Invalid, // = 0xf6, + Invalid, // = 0xf7, + Invalid, // = 0xf8, + Invalid, // = 0xf9, + Invalid, // = 0xfa, + Invalid, // = 0xfb, + Invalid, // = 0xfc, + Invalid, // = 0xfd, + 1, // prefix1 = 0xfe, + Invalid, // = 0xff, + 2, // arglist = 0x100, + 2, // ceq = 0x101, + 2, // cgt = 0x102, + 2, // cgt_un = 0x103, + 2, // clt = 0x104, + 2, // clt_un = 0x105, + 6, // ldftn = 0x106, + 6, // ldvirtftn = 0x107, + Invalid, // = 0x108, + 4, // ldarg = 0x109, + 4, // ldarga = 0x10a, + 4, // starg = 0x10b, + 4, // ldloc = 0x10c, + 4, // ldloca = 0x10d, + 4, // stloc = 0x10e, + 2, // localloc = 0x10f, + Invalid, // = 0x110, + 2, // endfilter = 0x111, + 3, // unaligned = 0x112, + 2, // volatile_ = 0x113, + 2, // tail = 0x114, + 6, // initobj = 0x115, + 6, // constrained = 0x116, + 2, // cpblk = 0x117, + 2, // initblk = 0x118, + 3, // no = 0x119, + 2, // rethrow = 0x11a, + Invalid, // = 0x11b, + 6, // sizeof_ = 0x11c, + 2, // refanytype = 0x11d, + 2, // readonly_ = 0x11e, + }; + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/ILProvider.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/ILProvider.cs new file mode 100644 index 00000000000..f17bb497982 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/ILProvider.cs @@ -0,0 +1,17 @@ +// 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 Internal.TypeSystem; + +namespace Internal.IL +{ + /// + /// Provides IL for method bodies either by reading + /// the IL bytes from the source ECMA-335 assemblies, or through other means. + /// + public abstract class ILProvider + { + public abstract MethodIL GetMethodIL(MethodDesc method); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/ILStackHelper.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/ILStackHelper.cs new file mode 100644 index 00000000000..d30532e1373 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/ILStackHelper.cs @@ -0,0 +1,474 @@ +// 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.TypeSystem; + +namespace Internal.IL +{ + public static class ILStackHelper + { + /// + /// Validates that the CIL evaluation stack is properly balanced. + /// + [Conditional("DEBUG")] + public static void CheckStackBalance(this MethodIL methodIL) + { + methodIL.ComputeMaxStack(); + } + + /// + /// Computes the maximum number of items that can be pushed onto the CIL evaluation stack. + /// + public static int ComputeMaxStack(this MethodIL methodIL) + { + const int StackHeightNotSet = Int32.MinValue; + + byte[] ilbytes = methodIL.GetILBytes(); + int currentOffset = 0; + int stackHeight = 0; + int maxStack = 0; + + // TODO: Use Span for this and stackalloc the array if reasonably sized + int[] stackHeights = new int[ilbytes.Length]; + for (int i = 0; i < stackHeights.Length; i++) + stackHeights[i] = StackHeightNotSet; + + // Catch and filter clauses have a known non-zero stack height. + foreach (ILExceptionRegion region in methodIL.GetExceptionRegions()) + { + if (region.Kind == ILExceptionRegionKind.Catch) + { + stackHeights[region.HandlerOffset] = 1; + } + else if (region.Kind == ILExceptionRegionKind.Filter) + { + stackHeights[region.FilterOffset] = 1; + stackHeights[region.HandlerOffset] = 1; + } + } + + while (currentOffset < ilbytes.Length) + { + ILOpcode opcode = (ILOpcode)ilbytes[currentOffset]; + if (opcode == ILOpcode.prefix1) + opcode = 0x100 + (ILOpcode)ilbytes[currentOffset + 1]; + + // The stack height could be unknown if the previous instruction + // was an unconditional control transfer. + // In that case we check if we have a known stack height due to + // this instruction being a target of a previous branch or an EH block. + if (stackHeight == StackHeightNotSet) + stackHeight = stackHeights[currentOffset]; + + // If we still don't know the stack height, ECMA-335 III.1.7.5 + // "Backward branch constraint" demands the evaluation stack be empty. + if (stackHeight == StackHeightNotSet) + stackHeight = 0; + + // Remeber the stack height at this offset. + Debug.Assert(stackHeights[currentOffset] == StackHeightNotSet + || stackHeights[currentOffset] == stackHeight); + stackHeights[currentOffset] = stackHeight; + + bool isVariableSize = false; + switch (opcode) + { + case ILOpcode.arglist: + case ILOpcode.dup: + case ILOpcode.ldc_i4: + case ILOpcode.ldc_i4_0: + case ILOpcode.ldc_i4_1: + case ILOpcode.ldc_i4_2: + case ILOpcode.ldc_i4_3: + case ILOpcode.ldc_i4_4: + case ILOpcode.ldc_i4_5: + case ILOpcode.ldc_i4_6: + case ILOpcode.ldc_i4_7: + case ILOpcode.ldc_i4_8: + case ILOpcode.ldc_i4_m1: + case ILOpcode.ldc_i4_s: + case ILOpcode.ldc_i8: + case ILOpcode.ldc_r4: + case ILOpcode.ldc_r8: + case ILOpcode.ldftn: + case ILOpcode.ldnull: + case ILOpcode.ldsfld: + case ILOpcode.ldsflda: + case ILOpcode.ldstr: + case ILOpcode.ldtoken: + case ILOpcode.ldarg: + case ILOpcode.ldarg_0: + case ILOpcode.ldarg_1: + case ILOpcode.ldarg_2: + case ILOpcode.ldarg_3: + case ILOpcode.ldarg_s: + case ILOpcode.ldarga: + case ILOpcode.ldarga_s: + case ILOpcode.ldloc: + case ILOpcode.ldloc_0: + case ILOpcode.ldloc_1: + case ILOpcode.ldloc_2: + case ILOpcode.ldloc_3: + case ILOpcode.ldloc_s: + case ILOpcode.ldloca: + case ILOpcode.ldloca_s: + case ILOpcode.sizeof_: + stackHeight += 1; + break; + + case ILOpcode.add: + case ILOpcode.add_ovf: + case ILOpcode.add_ovf_un: + case ILOpcode.and: + case ILOpcode.ceq: + case ILOpcode.cgt: + case ILOpcode.cgt_un: + case ILOpcode.clt: + case ILOpcode.clt_un: + case ILOpcode.div: + case ILOpcode.div_un: + case ILOpcode.initobj: + case ILOpcode.ldelem: + case ILOpcode.ldelem_i: + case ILOpcode.ldelem_i1: + case ILOpcode.ldelem_i2: + case ILOpcode.ldelem_i4: + case ILOpcode.ldelem_i8: + case ILOpcode.ldelem_r4: + case ILOpcode.ldelem_r8: + case ILOpcode.ldelem_ref: + case ILOpcode.ldelem_u1: + case ILOpcode.ldelem_u2: + case ILOpcode.ldelem_u4: + case ILOpcode.ldelema: + case ILOpcode.mkrefany: + case ILOpcode.mul: + case ILOpcode.mul_ovf: + case ILOpcode.mul_ovf_un: + case ILOpcode.or: + case ILOpcode.pop: + case ILOpcode.rem: + case ILOpcode.rem_un: + case ILOpcode.shl: + case ILOpcode.shr: + case ILOpcode.shr_un: + case ILOpcode.stsfld: + case ILOpcode.sub: + case ILOpcode.sub_ovf: + case ILOpcode.sub_ovf_un: + case ILOpcode.xor: + case ILOpcode.starg: + case ILOpcode.starg_s: + case ILOpcode.stloc: + case ILOpcode.stloc_0: + case ILOpcode.stloc_1: + case ILOpcode.stloc_2: + case ILOpcode.stloc_3: + case ILOpcode.stloc_s: + Debug.Assert(stackHeight > 0); + stackHeight -= 1; + break; + + case ILOpcode.throw_: + Debug.Assert(stackHeight > 0); + stackHeight = StackHeightNotSet; + break; + + case ILOpcode.br: + case ILOpcode.leave: + case ILOpcode.brfalse: + case ILOpcode.brtrue: + case ILOpcode.beq: + case ILOpcode.bge: + case ILOpcode.bge_un: + case ILOpcode.bgt: + case ILOpcode.bgt_un: + case ILOpcode.ble: + case ILOpcode.ble_un: + case ILOpcode.blt: + case ILOpcode.blt_un: + case ILOpcode.bne_un: + { + int target = currentOffset + ReadInt32(ilbytes, currentOffset + 1) + 5; + + int adjustment; + bool isConditional; + if (opcode == ILOpcode.br || opcode == ILOpcode.leave) + { + isConditional = false; + adjustment = 0; + } + else if (opcode == ILOpcode.brfalse || opcode == ILOpcode.brtrue) + { + isConditional = true; + adjustment = 1; + } + else + { + isConditional = true; + adjustment = 2; + } + + Debug.Assert(stackHeight >= adjustment); + stackHeight -= adjustment; + + Debug.Assert(stackHeights[target] == StackHeightNotSet + || stackHeights[target] == stackHeight); + + // Forward branch carries information about stack height at a future + // offset. We need to remember it. + if (target > currentOffset) + stackHeights[target] = stackHeight; + + if (!isConditional) + stackHeight = StackHeightNotSet; + } + break; + + case ILOpcode.br_s: + case ILOpcode.leave_s: + case ILOpcode.brfalse_s: + case ILOpcode.brtrue_s: + case ILOpcode.beq_s: + case ILOpcode.bge_s: + case ILOpcode.bge_un_s: + case ILOpcode.bgt_s: + case ILOpcode.bgt_un_s: + case ILOpcode.ble_s: + case ILOpcode.ble_un_s: + case ILOpcode.blt_s: + case ILOpcode.blt_un_s: + case ILOpcode.bne_un_s: + { + int target = currentOffset + (sbyte)ilbytes[currentOffset + 1] + 2; + + int adjustment; + bool isConditional; + if (opcode == ILOpcode.br_s || opcode == ILOpcode.leave_s) + { + isConditional = false; + adjustment = 0; + } + else if (opcode == ILOpcode.brfalse_s || opcode == ILOpcode.brtrue_s) + { + isConditional = true; + adjustment = 1; + } + else + { + isConditional = true; + adjustment = 2; + } + + Debug.Assert(stackHeight >= adjustment); + stackHeight -= adjustment; + + Debug.Assert(stackHeights[target] == StackHeightNotSet + || stackHeights[target] == stackHeight); + + // Forward branch carries information about stack height at a future + // offset. We need to remember it. + if (target > currentOffset) + stackHeights[target] = stackHeight; + + if (!isConditional) + stackHeight = StackHeightNotSet; + } + break; + + case ILOpcode.call: + case ILOpcode.calli: + case ILOpcode.callvirt: + case ILOpcode.newobj: + { + int token = ReadILToken(ilbytes, currentOffset + 1); + object obj = methodIL.GetObject(token); + MethodSignature sig = obj is MethodSignature ? + (MethodSignature)obj : + ((MethodDesc)obj).Signature; + int adjustment = sig.Length; + if (opcode == ILOpcode.newobj) + { + adjustment--; + } + else + { + if (opcode == ILOpcode.calli) + adjustment++; + if (!sig.IsStatic) + adjustment++; + if (!sig.ReturnType.IsVoid) + adjustment--; + } + + Debug.Assert(stackHeight >= adjustment); + stackHeight -= adjustment; + } + break; + + case ILOpcode.ret: + { + bool hasReturnValue = !methodIL.OwningMethod.Signature.ReturnType.IsVoid; + if (hasReturnValue) + stackHeight -= 1; + + Debug.Assert(stackHeight == 0); + + stackHeight = StackHeightNotSet; + } + break; + + case ILOpcode.cpobj: + case ILOpcode.stfld: + case ILOpcode.stind_i: + case ILOpcode.stind_i1: + case ILOpcode.stind_i2: + case ILOpcode.stind_i4: + case ILOpcode.stind_i8: + case ILOpcode.stind_r4: + case ILOpcode.stind_r8: + case ILOpcode.stind_ref: + case ILOpcode.stobj: + Debug.Assert(stackHeight > 1); + stackHeight -= 2; + break; + + case ILOpcode.cpblk: + case ILOpcode.initblk: + case ILOpcode.stelem: + case ILOpcode.stelem_i: + case ILOpcode.stelem_i1: + case ILOpcode.stelem_i2: + case ILOpcode.stelem_i4: + case ILOpcode.stelem_i8: + case ILOpcode.stelem_r4: + case ILOpcode.stelem_r8: + case ILOpcode.stelem_ref: + Debug.Assert(stackHeight > 2); + stackHeight -= 3; + break; + + case ILOpcode.break_: + case ILOpcode.constrained: + case ILOpcode.no: + case ILOpcode.nop: + case ILOpcode.readonly_: + case ILOpcode.tail: + case ILOpcode.unaligned: + case ILOpcode.volatile_: + break; + + case ILOpcode.endfilter: + Debug.Assert(stackHeight > 0); + stackHeight = StackHeightNotSet; + break; + + case ILOpcode.jmp: + case ILOpcode.rethrow: + case ILOpcode.endfinally: + stackHeight = StackHeightNotSet; + break; + + case ILOpcode.box: + case ILOpcode.castclass: + case ILOpcode.ckfinite: + case ILOpcode.conv_i: + case ILOpcode.conv_i1: + case ILOpcode.conv_i2: + case ILOpcode.conv_i4: + case ILOpcode.conv_i8: + case ILOpcode.conv_ovf_i: + case ILOpcode.conv_ovf_i_un: + case ILOpcode.conv_ovf_i1: + case ILOpcode.conv_ovf_i1_un: + case ILOpcode.conv_ovf_i2: + case ILOpcode.conv_ovf_i2_un: + case ILOpcode.conv_ovf_i4: + case ILOpcode.conv_ovf_i4_un: + case ILOpcode.conv_ovf_i8: + case ILOpcode.conv_ovf_i8_un: + case ILOpcode.conv_ovf_u: + case ILOpcode.conv_ovf_u_un: + case ILOpcode.conv_ovf_u1: + case ILOpcode.conv_ovf_u1_un: + case ILOpcode.conv_ovf_u2: + case ILOpcode.conv_ovf_u2_un: + case ILOpcode.conv_ovf_u4: + case ILOpcode.conv_ovf_u4_un: + case ILOpcode.conv_ovf_u8: + case ILOpcode.conv_ovf_u8_un: + case ILOpcode.conv_r_un: + case ILOpcode.conv_r4: + case ILOpcode.conv_r8: + case ILOpcode.conv_u: + case ILOpcode.conv_u1: + case ILOpcode.conv_u2: + case ILOpcode.conv_u4: + case ILOpcode.conv_u8: + case ILOpcode.isinst: + case ILOpcode.ldfld: + case ILOpcode.ldflda: + case ILOpcode.ldind_i: + case ILOpcode.ldind_i1: + case ILOpcode.ldind_i2: + case ILOpcode.ldind_i4: + case ILOpcode.ldind_i8: + case ILOpcode.ldind_r4: + case ILOpcode.ldind_r8: + case ILOpcode.ldind_ref: + case ILOpcode.ldind_u1: + case ILOpcode.ldind_u2: + case ILOpcode.ldind_u4: + case ILOpcode.ldlen: + case ILOpcode.ldobj: + case ILOpcode.ldvirtftn: + case ILOpcode.localloc: + case ILOpcode.neg: + case ILOpcode.newarr: + case ILOpcode.not: + case ILOpcode.refanytype: + case ILOpcode.refanyval: + case ILOpcode.unbox: + case ILOpcode.unbox_any: + Debug.Assert(stackHeight > 0); + break; + + case ILOpcode.switch_: + Debug.Assert(stackHeight > 0); + isVariableSize = true; + stackHeight -= 1; + currentOffset += 1 + (ReadInt32(ilbytes, currentOffset + 1) * 4) + 4; + break; + + default: + Debug.Fail("Unknown instruction"); + break; + } + + if (!isVariableSize) + currentOffset += opcode.GetSize(); + + maxStack = Math.Max(maxStack, stackHeight); + } + + return maxStack; + } + + private static int ReadInt32(byte[] ilBytes, int offset) + { + return ilBytes[offset] + + (ilBytes[offset + 1] << 8) + + (ilBytes[offset + 2] << 16) + + (ilBytes[offset + 3] << 24); + } + + private static int ReadILToken(byte[] ilBytes, int offset) + { + return ReadInt32(ilBytes, offset); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/InstantiatedMethodIL.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/InstantiatedMethodIL.cs new file mode 100644 index 00000000000..f444f5da770 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/InstantiatedMethodIL.cs @@ -0,0 +1,130 @@ +// 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.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL +{ + public sealed partial class InstantiatedMethodIL : MethodIL + { + private MethodDesc _method; + private MethodIL _methodIL; + private Instantiation _typeInstantiation; + private Instantiation _methodInstantiation; + + public InstantiatedMethodIL(MethodDesc owningMethod, MethodIL methodIL) + { + Debug.Assert(methodIL.GetMethodILDefinition() == methodIL); + Debug.Assert(owningMethod.HasInstantiation || owningMethod.OwningType.HasInstantiation); + Debug.Assert(owningMethod.GetTypicalMethodDefinition() == methodIL.OwningMethod); + + _methodIL = methodIL; + _method = owningMethod; + + _typeInstantiation = owningMethod.OwningType.Instantiation; + _methodInstantiation = owningMethod.Instantiation; + } + + public override MethodDesc OwningMethod + { + get + { + return _method; + } + } + + public override byte[] GetILBytes() + { + return _methodIL.GetILBytes(); + } + + public override int MaxStack + { + get + { + return _methodIL.MaxStack; + } + } + + public override ILExceptionRegion[] GetExceptionRegions() + { + return _methodIL.GetExceptionRegions(); + } + + public override bool IsInitLocals + { + get + { + return _methodIL.IsInitLocals; + } + } + + public override LocalVariableDefinition[] GetLocals() + { + LocalVariableDefinition[] locals = _methodIL.GetLocals(); + LocalVariableDefinition[] clone = null; + + for (int i = 0; i < locals.Length; i++) + { + TypeDesc uninst = locals[i].Type; + TypeDesc inst = uninst.InstantiateSignature(_typeInstantiation, _methodInstantiation); + if (uninst != inst) + { + if (clone == null) + { + clone = new LocalVariableDefinition[locals.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = locals[j]; + } + } + clone[i] = new LocalVariableDefinition(inst, locals[i].IsPinned); + } + } + + return (clone == null) ? locals : clone; + } + + public override Object GetObject(int token) + { + Object o = _methodIL.GetObject(token); + + if (o is MethodDesc) + { + o = ((MethodDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); + } + else if (o is TypeDesc) + { + o = ((TypeDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); + } + else if (o is FieldDesc) + { + o = ((FieldDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); + } + else if (o is MethodSignature) + { + MethodSignature template = (MethodSignature)o; + MethodSignatureBuilder builder = new MethodSignatureBuilder(template); + + builder.ReturnType = template.ReturnType.InstantiateSignature(_typeInstantiation, _methodInstantiation); + for (int i = 0; i < template.Length; i++) + builder[i] = template[i].InstantiateSignature(_typeInstantiation, _methodInstantiation); + + o = builder.ToSignature(); + } + + + return o; + } + + public override MethodIL GetMethodILDefinition() + { + return _methodIL; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/MethodIL.Symbols.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/MethodIL.Symbols.cs new file mode 100644 index 00000000000..9271af838e5 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/MethodIL.Symbols.cs @@ -0,0 +1,87 @@ +// 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.Collections.Generic; + +using Internal.TypeSystem; + +namespace Internal.IL +{ + partial class MethodIL + { + public virtual MethodDebugInformation GetDebugInfo() + { + return MethodDebugInformation.None; + } + } + + partial class InstantiatedMethodIL + { + public override MethodDebugInformation GetDebugInfo() + { + return _methodIL.GetDebugInfo(); + } + } + + /// + /// Represents debug information attached to a . + /// + public class MethodDebugInformation + { + public static MethodDebugInformation None = new MethodDebugInformation(); + + public virtual IEnumerable GetSequencePoints() + { + return null; + } + + public virtual IEnumerable GetLocalVariables() + { + return null; + } + + public virtual IEnumerable GetParameterNames() + { + return null; + } + } + + /// + /// Represents a sequence point within an IL method body. + /// Sequence point describes a point in the method body at which all side effects of + /// previous evaluations have been performed. + /// + public struct ILSequencePoint + { + public readonly int Offset; + public readonly string Document; + public readonly int LineNumber; + // TODO: The remaining info + + public ILSequencePoint(int offset, string document, int lineNumber) + { + Offset = offset; + Document = document; + LineNumber = lineNumber; + } + } + + /// + /// Represents information about a local variable within a method body. + /// + public struct ILLocalVariable + { + public readonly int Slot; + public readonly string Name; + public readonly bool CompilerGenerated; + + public ILLocalVariable(int slot, string name, bool compilerGenerated) + { + Slot = slot; + Name = name; + CompilerGenerated = compilerGenerated; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/MethodIL.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/MethodIL.cs new file mode 100644 index 00000000000..70e925d718b --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/MethodIL.cs @@ -0,0 +1,110 @@ +// 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.TypeSystem; + +namespace Internal.IL +{ + // + // This duplicates types from System.Reflection.Metadata to avoid layering issues, and + // because of the System.Reflection.Metadata constructors are not public anyway. + // + + public enum ILExceptionRegionKind + { + Catch = 0, + Filter = 1, + Finally = 2, + Fault = 4, + } + + public struct ILExceptionRegion + { + public readonly ILExceptionRegionKind Kind; + public readonly int TryOffset; + public readonly int TryLength; + public readonly int HandlerOffset; + public readonly int HandlerLength; + public readonly int ClassToken; + public readonly int FilterOffset; + + public ILExceptionRegion( + ILExceptionRegionKind kind, + int tryOffset, + int tryLength, + int handlerOffset, + int handlerLength, + int classToken, + int filterOffset) + { + Kind = kind; + TryOffset = tryOffset; + TryLength = tryLength; + HandlerOffset = handlerOffset; + HandlerLength = handlerLength; + ClassToken = classToken; + FilterOffset = filterOffset; + } + } + + /// + /// Represents a method body. + /// + [System.Diagnostics.DebuggerTypeProxy(typeof(MethodILDebugView))] + public abstract partial class MethodIL + { + /// + /// Gets the method whose body this represents. + /// + public abstract MethodDesc OwningMethod { get; } + + /// + /// Gets the maximum possible stack depth this method declares. + /// + public abstract int MaxStack { get; } + + /// + /// Gets a value indicating whether the locals should be initialized to zero + /// before first access. + /// + public abstract bool IsInitLocals { get; } + + /// + /// Retrieves IL opcode bytes of this method body. + /// + public abstract byte[] GetILBytes(); + + /// + /// Gets the list of locals this method body defines. + /// + public abstract LocalVariableDefinition[] GetLocals(); + + /// + /// Resolves a token from within the method body into a type system object + /// (typically a , , , + /// or ). + /// + public abstract Object GetObject(int token); + + /// + /// Gets a list of exception regions this method body defines. + /// + public abstract ILExceptionRegion[] GetExceptionRegions(); + + /// + /// Gets the open (uninstantiated) version of the . + /// + public virtual MethodIL GetMethodILDefinition() + { + return this; + } + + public override string ToString() + { + return OwningMethod.ToString(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/MethodILDebugView.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/MethodILDebugView.cs new file mode 100644 index 00000000000..e0d5675e602 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/MethodILDebugView.cs @@ -0,0 +1,143 @@ +// 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.Text; + +using Internal.TypeSystem; + +namespace Internal.IL +{ + internal sealed class MethodILDebugView + { + private readonly MethodIL _methodIL; + + public MethodILDebugView(MethodIL methodIL) + { + _methodIL = methodIL; + } + + public string Disassembly + { + get + { + ILDisassembler disasm = new ILDisassembler(_methodIL); + + StringBuilder sb = new StringBuilder(); + + MethodDesc owningMethod = _methodIL.OwningMethod; + + sb.Append("// "); + sb.AppendLine(owningMethod.ToString()); + sb.Append(".method "); + // TODO: accessibility, specialname, calling conventions etc. + if (!owningMethod.Signature.IsStatic) + sb.Append("instance "); + disasm.AppendType(sb, owningMethod.Signature.ReturnType); + sb.Append(" "); + sb.Append(owningMethod.Name); + if (owningMethod.HasInstantiation) + { + sb.Append("<"); + for (int i = 0; i < owningMethod.Instantiation.Length; i++) + { + if (i != 0) + sb.Append(", "); + disasm.AppendType(sb, owningMethod.Instantiation[i]); + } + sb.Append(">"); + } + sb.Append("("); + for (int i = 0; i < owningMethod.Signature.Length; i++) + { + if (i != 0) + sb.Append(", "); + disasm.AppendType(sb, owningMethod.Signature[i]); + } + sb.AppendLine(") cil managed"); + + sb.AppendLine("{"); + + sb.Append(" // Code size: "); + sb.Append(disasm.CodeSize); + sb.AppendLine(); + sb.Append(" .maxstack "); + sb.Append(_methodIL.MaxStack); + sb.AppendLine(); + + LocalVariableDefinition[] locals = _methodIL.GetLocals(); + if (locals != null && locals.Length > 0) + { + sb.Append(" .locals "); + if (_methodIL.IsInitLocals) + sb.Append("init "); + + sb.Append("("); + + for (int i = 0; i < locals.Length; i++) + { + if (i != 0) + { + sb.AppendLine(","); + sb.Append(' ', 6); + } + disasm.AppendType(sb, locals[i].Type); + sb.Append(" "); + if (locals[i].IsPinned) + sb.Append("pinned "); + sb.Append("V_"); + sb.Append(i); + } + sb.AppendLine(")"); + } + sb.AppendLine(); + + const string pad = " "; + + // TODO: pretty exception regions + foreach (ILExceptionRegion region in _methodIL.GetExceptionRegions()) + { + sb.Append(pad); + sb.Append(".try "); + ILDisassembler.AppendOffset(sb, region.TryOffset); + sb.Append(" to "); + ILDisassembler.AppendOffset(sb, region.TryOffset + region.TryLength); + + switch (region.Kind) + { + case ILExceptionRegionKind.Catch: + sb.Append(" catch "); + disasm.AppendType(sb, (TypeDesc)_methodIL.GetObject(region.ClassToken)); + break; + case ILExceptionRegionKind.Fault: + sb.Append(" fault"); + break; + case ILExceptionRegionKind.Filter: + sb.Append(" filter "); + ILDisassembler.AppendOffset(sb, region.FilterOffset); + break; + case ILExceptionRegionKind.Finally: + sb.Append(" finally"); + break; + } + + sb.Append(" handler "); + ILDisassembler.AppendOffset(sb, region.HandlerOffset); + sb.Append(" to "); + ILDisassembler.AppendOffset(sb, region.HandlerOffset + region.HandlerLength); + sb.AppendLine(); + } + + while (disasm.HasNextInstruction) + { + sb.Append(pad); + sb.AppendLine(disasm.GetNextInstruction()); + } + + sb.AppendLine("}"); + + return sb.ToString(); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs new file mode 100644 index 00000000000..9919805e286 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs @@ -0,0 +1,219 @@ +// 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.Collections.Generic; + +using Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL.Stubs +{ + /// + /// Intrinsic support arround EqualityComparer<T> and Comparer<T>. + /// + public static class ComparerIntrinsics + { + /// + /// Generates a specialized method body for Comparer`1.Create or returns null if no specialized body can be generated. + /// + public static MethodIL EmitComparerCreate(MethodDesc target) + { + return EmitComparerAndEqualityComparerCreateCommon(target, "Comparer", "IComparable`1"); + } + + /// + /// Generates a specialized method body for EqualityComparer`1.Create or returns null if no specialized body can be generated. + /// + public static MethodIL EmitEqualityComparerCreate(MethodDesc target) + { + return EmitComparerAndEqualityComparerCreateCommon(target, "EqualityComparer", "IEquatable`1"); + } + + /// + /// Gets the concrete type EqualityComparer`1.Create returns or null if it's not known at compile time. + /// + public static TypeDesc GetEqualityComparerForType(TypeDesc comparand) + { + return GetComparerForType(comparand, "EqualityComparer", "IEquatable`1"); + } + + private static MethodIL EmitComparerAndEqualityComparerCreateCommon(MethodDesc methodBeingGenerated, string flavor, string interfaceName) + { + // We expect the method to be fully instantiated + Debug.Assert(!methodBeingGenerated.IsTypicalMethodDefinition); + + TypeDesc owningType = methodBeingGenerated.OwningType; + TypeDesc comparedType = owningType.Instantiation[0]; + + // If the type is canonical, we use the default implementation provided by the class library. + // This will rely on the type loader to load the proper type at runtime. + if (comparedType.IsCanonicalSubtype(CanonicalFormKind.Any)) + return null; + + TypeDesc comparerType = GetComparerForType(comparedType, flavor, interfaceName); + Debug.Assert(comparerType != null); + + ILEmitter emitter = new ILEmitter(); + var codeStream = emitter.NewCodeStream(); + + codeStream.Emit(ILOpcode.newobj, emitter.NewToken(comparerType.GetParameterlessConstructor())); + codeStream.Emit(ILOpcode.dup); + codeStream.Emit(ILOpcode.stsfld, emitter.NewToken(owningType.GetKnownField("_default"))); + codeStream.Emit(ILOpcode.ret); + + return emitter.Link(methodBeingGenerated); + } + + /// + /// Gets the comparer type that is suitable to compare instances of + /// or null if such comparer cannot be determined at compile time. + /// + private static TypeDesc GetComparerForType(TypeDesc type, string flavor, string interfaceName) + { + TypeSystemContext context = type.Context; + + if (context.IsCanonicalDefinitionType(type, CanonicalFormKind.Any) || + (type.IsRuntimeDeterminedSubtype && !type.HasInstantiation)) + { + // The comparer will be determined at runtime. We can't tell the exact type at compile time. + return null; + } + else if (type.IsNullable) + { + TypeDesc nullableType = type.Instantiation[0]; + + if (context.IsCanonicalDefinitionType(nullableType, CanonicalFormKind.Universal)) + { + // We can't tell at compile time either. + return null; + } + else if (ImplementsInterfaceOfSelf(nullableType, interfaceName)) + { + return context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1") + .MakeInstantiatedType(nullableType); + } + } + else if (flavor == "EqualityComparer" && type.IsEnum) + { + // Enums have a specialized comparer that avoids boxing + return context.SystemModule.GetKnownType("System.Collections.Generic", $"Enum{flavor}`1") + .MakeInstantiatedType(type); + } + else if (ImplementsInterfaceOfSelf(type, interfaceName)) + { + return context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1") + .MakeInstantiatedType(type); + } + + return context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1") + .MakeInstantiatedType(type); + } + + public static TypeDesc[] GetPotentialComparersForType(TypeDesc type) + { + return GetPotentialComparersForTypeCommon(type, "Comparer", "IComparable`1"); + } + + public static TypeDesc[] GetPotentialEqualityComparersForType(TypeDesc type) + { + return GetPotentialComparersForTypeCommon(type, "EqualityComparer", "IEquatable`1"); + } + + /// + /// Gets the set of template types needed to support loading comparers for the give canonical type at runtime. + /// + private static TypeDesc[] GetPotentialComparersForTypeCommon(TypeDesc type, string flavor, string interfaceName) + { + Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any)); + + TypeDesc exactComparer = GetComparerForType(type, flavor, interfaceName); + + if (exactComparer != null) + { + // If we have a comparer that is exactly known at runtime, we're done. + // This will typically be if type is a generic struct, generic enum, or a nullable. + return new TypeDesc[] { exactComparer }; + } + + TypeSystemContext context = type.Context; + + if (context.IsCanonicalDefinitionType(type, CanonicalFormKind.Universal)) + { + // This can be any of the comparers we have. + + ArrayBuilder universalComparers = new ArrayBuilder(); + + universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1") + .MakeInstantiatedType(type)); + + if (flavor == "EqualityComparer") + universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Enum{flavor}`1") + .MakeInstantiatedType(type)); + + universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1") + .MakeInstantiatedType(type)); + + universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1") + .MakeInstantiatedType(type)); + + return universalComparers.ToArray(); + } + + // This mirrors exactly what GetUnknownEquatableComparer and GetUnknownComparer (in the class library) + // will need at runtime. This is the general purpose code path that can be used to compare + // anything. + + if (type.IsNullable) + { + TypeDesc nullableType = type.Instantiation[0]; + + // This should only be reachabe for universal canon code. + // For specific canon, this should have been an exact match above. + Debug.Assert(context.IsCanonicalDefinitionType(nullableType, CanonicalFormKind.Universal)); + + return new TypeDesc[] + { + context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1") + .MakeInstantiatedType(nullableType), + context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1") + .MakeInstantiatedType(type), + }; + } + + return new TypeDesc[] + { + context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1") + .MakeInstantiatedType(type), + context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1") + .MakeInstantiatedType(type), + }; + } + + public static bool ImplementsIEquatable(TypeDesc type) + => ImplementsInterfaceOfSelf(type, "IEquatable`1"); + + private static bool ImplementsInterfaceOfSelf(TypeDesc type, string interfaceName) + { + MetadataType interfaceType = null; + + foreach (TypeDesc implementedInterface in type.RuntimeInterfaces) + { + Instantiation interfaceInstantiation = implementedInterface.Instantiation; + if (interfaceInstantiation.Length == 1 && + interfaceInstantiation[0] == type) + { + if (interfaceType == null) + interfaceType = type.Context.SystemModule.GetKnownType("System", interfaceName); + + if (implementedInterface.GetTypeDefinition() == interfaceType) + return true; + } + } + + return false; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs new file mode 100644 index 00000000000..363ab351c89 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs @@ -0,0 +1,829 @@ +// 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.Collections.Generic; + +using Internal.IL; +using Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL.Stubs +{ + public class ILCodeStream + { + private const int StartOffsetNotSet = -1; + + private struct LabelAndOffset + { + public readonly ILCodeLabel Label; + public readonly int Offset; + public LabelAndOffset(ILCodeLabel label, int offset) + { + Label = label; + Offset = offset; + } + } + + internal byte[] _instructions; + internal int _length; + internal int _startOffsetForLinking; + internal ArrayBuilder _sequencePoints; + + private ArrayBuilder _offsetsNeedingPatching; + + private ILEmitter _emitter; + + internal ILCodeStream(ILEmitter emitter) + { + _instructions = Array.Empty(); + _startOffsetForLinking = StartOffsetNotSet; + _emitter = emitter; + } + + internal int RelativeToAbsoluteOffset(int relativeOffset) + { + Debug.Assert(_startOffsetForLinking != StartOffsetNotSet); + return _startOffsetForLinking + relativeOffset; + } + + private void EmitByte(byte b) + { + if (_instructions.Length == _length) + Array.Resize(ref _instructions, 2 * _instructions.Length + 10); + _instructions[_length++] = b; + } + + private void EmitUInt16(ushort value) + { + EmitByte((byte)value); + EmitByte((byte)(value >> 8)); + } + + private void EmitUInt32(int value) + { + EmitByte((byte)value); + EmitByte((byte)(value >> 8)); + EmitByte((byte)(value >> 16)); + EmitByte((byte)(value >> 24)); + } + + public void Emit(ILOpcode opcode) + { + if ((int)opcode > 0x100) + EmitByte((byte)ILOpcode.prefix1); + EmitByte((byte)opcode); + } + + public void Emit(ILOpcode opcode, ILToken token) + { + Emit(opcode); + EmitUInt32((int)token); + } + + public void EmitLdc(int value) + { + if (-1 <= value && value <= 8) + { + Emit((ILOpcode)(ILOpcode.ldc_i4_0 + value)); + } + else if (value == (sbyte)value) + { + Emit(ILOpcode.ldc_i4_s); + EmitByte((byte)value); + } + else + { + Emit(ILOpcode.ldc_i4); + EmitUInt32(value); + } + } + + public void EmitLdArg(int index) + { + if (index < 4) + { + Emit((ILOpcode)(ILOpcode.ldarg_0 + index)); + } + else + { + Emit(ILOpcode.ldarg); + EmitUInt16((ushort)index); + } + } + + public void EmitLdArga(int index) + { + if (index < 0x100) + { + Emit(ILOpcode.ldarga_s); + EmitByte((byte)index); + } + else + { + Emit(ILOpcode.ldarga); + EmitUInt16((ushort)index); + } + } + + public void EmitLdLoc(ILLocalVariable variable) + { + int index = (int)variable; + + if (index < 4) + { + Emit((ILOpcode)(ILOpcode.ldloc_0 + index)); + } + else if (index < 0x100) + { + Emit(ILOpcode.ldloc_s); + EmitByte((byte)index); + } + else + { + Emit(ILOpcode.ldloc); + EmitUInt16((ushort)index); + } + } + + public void EmitLdLoca(ILLocalVariable variable) + { + int index = (int)variable; + + if (index < 0x100) + { + Emit(ILOpcode.ldloca_s); + EmitByte((byte)index); + } + else + { + Emit(ILOpcode.ldloca); + EmitUInt16((ushort)index); + } + } + + public void EmitStLoc(ILLocalVariable variable) + { + int index = (int)variable; + + if (index < 4) + { + Emit((ILOpcode)(ILOpcode.stloc_0 + index)); + } + else if (index < 0x100) + { + Emit(ILOpcode.stloc_s); + EmitByte((byte)index); + } + else + { + Emit(ILOpcode.stloc); + EmitUInt16((ushort)index); + } + } + + public void Emit(ILOpcode opcode, ILCodeLabel label) + { + Debug.Assert(opcode == ILOpcode.br || opcode == ILOpcode.brfalse || + opcode == ILOpcode.brtrue || opcode == ILOpcode.beq || + opcode == ILOpcode.bge || opcode == ILOpcode.bgt || + opcode == ILOpcode.ble || opcode == ILOpcode.blt || + opcode == ILOpcode.bne_un || opcode == ILOpcode.bge_un || + opcode == ILOpcode.bgt_un || opcode == ILOpcode.ble_un || + opcode == ILOpcode.blt_un || opcode == ILOpcode.leave); + + Emit(opcode); + _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length)); + EmitUInt32(4); + } + + public void EmitSwitch(ILCodeLabel[] labels) + { + Emit(ILOpcode.switch_); + EmitUInt32(labels.Length); + + int remainingBytes = labels.Length * 4; + foreach (var label in labels) + { + _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length)); + EmitUInt32(remainingBytes); + remainingBytes -= 4; + } + } + + public void EmitUnaligned() + { + Emit(ILOpcode.unaligned); + EmitByte(1); + } + + public void EmitLdInd(TypeDesc type) + { + switch (type.UnderlyingType.Category) + { + case TypeFlags.SByte: + Emit(ILOpcode.ldind_i1); + break; + case TypeFlags.Byte: + case TypeFlags.Boolean: + Emit(ILOpcode.ldind_u1); + break; + case TypeFlags.Int16: + Emit(ILOpcode.ldind_i2); + break; + case TypeFlags.Char: + case TypeFlags.UInt16: + Emit(ILOpcode.ldind_u2); + break; + case TypeFlags.UInt32: + Emit(ILOpcode.ldind_u4); + break; + case TypeFlags.Int32: + Emit(ILOpcode.ldind_i4); + break; + case TypeFlags.UInt64: + case TypeFlags.Int64: + Emit(ILOpcode.ldind_i8); + break; + case TypeFlags.Single: + Emit(ILOpcode.ldind_r4); + break; + case TypeFlags.Double: + Emit(ILOpcode.ldind_r8); + break; + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + case TypeFlags.Pointer: + case TypeFlags.FunctionPointer: + Emit(ILOpcode.ldind_i); + break; + case TypeFlags.Array: + case TypeFlags.SzArray: + case TypeFlags.Class: + case TypeFlags.Interface: + Emit(ILOpcode.ldind_ref); + break; + case TypeFlags.ValueType: + case TypeFlags.Nullable: + case TypeFlags.SignatureMethodVariable: + case TypeFlags.SignatureTypeVariable: + Emit(ILOpcode.ldobj, _emitter.NewToken(type)); + break; + default: + Debug.Fail("Unexpected TypeDesc category"); + break; + } + } + public void EmitStInd(TypeDesc type) + { + switch (type.UnderlyingType.Category) + { + case TypeFlags.Byte: + case TypeFlags.SByte: + case TypeFlags.Boolean: + Emit(ILOpcode.stind_i1); + break; + case TypeFlags.Char: + case TypeFlags.UInt16: + case TypeFlags.Int16: + Emit(ILOpcode.stind_i2); + break; + case TypeFlags.UInt32: + case TypeFlags.Int32: + Emit(ILOpcode.stind_i4); + break; + case TypeFlags.UInt64: + case TypeFlags.Int64: + Emit(ILOpcode.stind_i8); + break; + case TypeFlags.Single: + Emit(ILOpcode.stind_r4); + break; + case TypeFlags.Double: + Emit(ILOpcode.stind_r8); + break; + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + case TypeFlags.Pointer: + case TypeFlags.FunctionPointer: + Emit(ILOpcode.stind_i); + break; + case TypeFlags.Array: + case TypeFlags.SzArray: + case TypeFlags.Class: + case TypeFlags.Interface: + Emit(ILOpcode.stind_ref); + break; + case TypeFlags.ValueType: + case TypeFlags.Nullable: + Emit(ILOpcode.stobj, _emitter.NewToken(type)); + break; + default: + Debug.Fail("Unexpected TypeDesc category"); + break; + } + } + + public void EmitStElem(TypeDesc type) + { + switch (type.UnderlyingType.Category) + { + case TypeFlags.Byte: + case TypeFlags.SByte: + case TypeFlags.Boolean: + Emit(ILOpcode.stelem_i1); + break; + case TypeFlags.Char: + case TypeFlags.UInt16: + case TypeFlags.Int16: + Emit(ILOpcode.stelem_i2); + break; + case TypeFlags.UInt32: + case TypeFlags.Int32: + Emit(ILOpcode.stelem_i4); + break; + case TypeFlags.UInt64: + case TypeFlags.Int64: + Emit(ILOpcode.stelem_i8); + break; + case TypeFlags.Single: + Emit(ILOpcode.stelem_r4); + break; + case TypeFlags.Double: + Emit(ILOpcode.stelem_r8); + break; + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + case TypeFlags.Pointer: + case TypeFlags.FunctionPointer: + Emit(ILOpcode.stelem_i); + break; + case TypeFlags.Array: + case TypeFlags.SzArray: + case TypeFlags.Class: + case TypeFlags.Interface: + Emit(ILOpcode.stelem_ref); + break; + case TypeFlags.ValueType: + case TypeFlags.Nullable: + Emit(ILOpcode.stelem, _emitter.NewToken(type)); + break; + default: + Debug.Fail("Unexpected TypeDesc category"); + break; + } + } + + public void EmitLdElem(TypeDesc type) + { + switch (type.UnderlyingType.Category) + { + case TypeFlags.Byte: + case TypeFlags.SByte: + case TypeFlags.Boolean: + Emit(ILOpcode.ldelem_i1); + break; + case TypeFlags.Char: + case TypeFlags.UInt16: + case TypeFlags.Int16: + Emit(ILOpcode.ldelem_i2); + break; + case TypeFlags.UInt32: + case TypeFlags.Int32: + Emit(ILOpcode.ldelem_i4); + break; + case TypeFlags.UInt64: + case TypeFlags.Int64: + Emit(ILOpcode.ldelem_i8); + break; + case TypeFlags.Single: + Emit(ILOpcode.ldelem_r4); + break; + case TypeFlags.Double: + Emit(ILOpcode.ldelem_r8); + break; + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + case TypeFlags.Pointer: + case TypeFlags.FunctionPointer: + Emit(ILOpcode.ldelem_i); + break; + case TypeFlags.Array: + case TypeFlags.SzArray: + case TypeFlags.Class: + case TypeFlags.Interface: + Emit(ILOpcode.ldelem_ref); + break; + case TypeFlags.ValueType: + case TypeFlags.Nullable: + Emit(ILOpcode.ldelem, _emitter.NewToken(type)); + break; + default: + Debug.Fail("Unexpected TypeDesc category"); + break; + } + } + + public void EmitLabel(ILCodeLabel label) + { + label.Place(this, _length); + } + + public void BeginTry(ILExceptionRegionBuilder builder) + { + Debug.Assert(builder._beginTryStream == null); + builder._beginTryStream = this; + builder._beginTryOffset = _length; + } + + public void EndTry(ILExceptionRegionBuilder builder) + { + Debug.Assert(builder._endTryStream == null); + builder._endTryStream = this; + builder._endTryOffset = _length; + } + + public void BeginHandler(ILExceptionRegionBuilder builder) + { + Debug.Assert(builder._beginHandlerStream == null); + builder._beginHandlerStream = this; + builder._beginHandlerOffset = _length; + } + + public void EndHandler(ILExceptionRegionBuilder builder) + { + Debug.Assert(builder._endHandlerStream == null); + builder._endHandlerStream = this; + builder._endHandlerOffset = _length; + } + + internal void PatchLabels() + { + for (int i = 0; i < _offsetsNeedingPatching.Count; i++) + { + LabelAndOffset patch = _offsetsNeedingPatching[i]; + + Debug.Assert(patch.Label.IsPlaced); + Debug.Assert(_startOffsetForLinking != StartOffsetNotSet); + + int offset = patch.Offset; + + int delta = _instructions[offset + 3] << 24 | + _instructions[offset + 2] << 16 | + _instructions[offset + 1] << 8 | + _instructions[offset]; + + int value = patch.Label.AbsoluteOffset - _startOffsetForLinking - patch.Offset - delta; + + _instructions[offset] = (byte)value; + _instructions[offset + 1] = (byte)(value >> 8); + _instructions[offset + 2] = (byte)(value >> 16); + _instructions[offset + 3] = (byte)(value >> 24); + } + } + + public void DefineSequencePoint(string document, int lineNumber) + { + // Last sequence point defined for this offset wins. + if (_sequencePoints.Count > 0 && _sequencePoints[_sequencePoints.Count - 1].Offset == _length) + { + _sequencePoints[_sequencePoints.Count - 1] = new ILSequencePoint(_length, document, lineNumber); + } + else + { + _sequencePoints.Add(new ILSequencePoint(_length, document, lineNumber)); + } + } + } + + public class ILExceptionRegionBuilder + { + internal ILCodeStream _beginTryStream; + internal int _beginTryOffset; + + internal ILCodeStream _endTryStream; + internal int _endTryOffset; + + internal ILCodeStream _beginHandlerStream; + internal int _beginHandlerOffset; + + internal ILCodeStream _endHandlerStream; + internal int _endHandlerOffset; + + internal ILExceptionRegionBuilder() + { + } + + internal int TryOffset => _beginTryStream.RelativeToAbsoluteOffset(_beginTryOffset); + internal int TryLength => _endTryStream.RelativeToAbsoluteOffset(_endTryOffset) - TryOffset; + internal int HandlerOffset => _beginHandlerStream.RelativeToAbsoluteOffset(_beginHandlerOffset); + internal int HandlerLength => _endHandlerStream.RelativeToAbsoluteOffset(_endHandlerOffset) - HandlerOffset; + + internal bool IsDefined => + _beginTryStream != null && _endTryStream != null + && _beginHandlerStream != null && _endHandlerStream != null; + } + + /// + /// Represent a token. Use one of the overloads of + /// to create a new token. + /// + public enum ILToken { } + + /// + /// Represents a local variable. Use to create a new local variable. + /// + public enum ILLocalVariable { } + + public class ILStubMethodIL : MethodIL + { + private readonly byte[] _ilBytes; + private readonly LocalVariableDefinition[] _locals; + private readonly Object[] _tokens; + private readonly MethodDesc _method; + private readonly ILExceptionRegion[] _exceptionRegions; + private readonly MethodDebugInformation _debugInformation; + + private const int MaxStackNotSet = -1; + private int _maxStack; + + public ILStubMethodIL(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, ILExceptionRegion[] exceptionRegions = null, MethodDebugInformation debugInfo = null) + { + _ilBytes = ilBytes; + _locals = locals; + _tokens = tokens; + _method = owningMethod; + _maxStack = MaxStackNotSet; + + if (exceptionRegions == null) + exceptionRegions = Array.Empty(); + _exceptionRegions = exceptionRegions; + + if (debugInfo == null) + debugInfo = MethodDebugInformation.None; + _debugInformation = debugInfo; + } + + public ILStubMethodIL(ILStubMethodIL methodIL) + { + _ilBytes = methodIL._ilBytes; + _locals = methodIL._locals; + _tokens = methodIL._tokens; + _method = methodIL._method; + _debugInformation = methodIL._debugInformation; + _exceptionRegions = methodIL._exceptionRegions; + _maxStack = methodIL._maxStack; + } + + public override MethodDesc OwningMethod + { + get + { + return _method; + } + } + + public override byte[] GetILBytes() + { + return _ilBytes; + } + + public override MethodDebugInformation GetDebugInfo() + { + return _debugInformation; + } + + public override int MaxStack + { + get + { + if (_maxStack == MaxStackNotSet) + _maxStack = this.ComputeMaxStack(); + return _maxStack; + } + } + + public override ILExceptionRegion[] GetExceptionRegions() + { + return _exceptionRegions; + } + public override bool IsInitLocals + { + get + { + return true; + } + } + + public override LocalVariableDefinition[] GetLocals() + { + return _locals; + } + public override Object GetObject(int token) + { + return _tokens[(token & 0xFFFFFF) - 1]; + } + } + + public class ILCodeLabel + { + private ILCodeStream _codeStream; + private int _offsetWithinCodeStream; + + internal bool IsPlaced + { + get + { + return _codeStream != null; + } + } + + internal int AbsoluteOffset + { + get + { + Debug.Assert(IsPlaced); + return _codeStream.RelativeToAbsoluteOffset(_offsetWithinCodeStream); + } + } + + internal ILCodeLabel() + { + } + + internal void Place(ILCodeStream codeStream, int offsetWithinCodeStream) + { + Debug.Assert(!IsPlaced); + _codeStream = codeStream; + _offsetWithinCodeStream = offsetWithinCodeStream; + } + } + + public class ILEmitter + { + private ArrayBuilder _codeStreams; + private ArrayBuilder _locals; + private ArrayBuilder _tokens; + private ArrayBuilder _finallyRegions; + + public ILEmitter() + { + } + + public ILCodeStream NewCodeStream() + { + ILCodeStream stream = new ILCodeStream(this); + _codeStreams.Add(stream); + return stream; + } + + private ILToken NewToken(Object value, int tokenType) + { + Debug.Assert(value != null); + _tokens.Add(value); + return (ILToken)(_tokens.Count | tokenType); + } + + public ILToken NewToken(TypeDesc value) + { + return NewToken(value, 0x01000000); + } + + public ILToken NewToken(MethodDesc value) + { + return NewToken(value, 0x0a000000); + } + + public ILToken NewToken(FieldDesc value) + { + return NewToken(value, 0x0a000000); + } + + public ILToken NewToken(string value) + { + return NewToken(value, 0x70000000); + } + + public ILToken NewToken(MethodSignature value) + { + return NewToken(value, 0x11000000); + } + + public ILLocalVariable NewLocal(TypeDesc localType, bool isPinned = false) + { + int index = _locals.Count; + _locals.Add(new LocalVariableDefinition(localType, isPinned)); + return (ILLocalVariable)index; + } + + public ILCodeLabel NewCodeLabel() + { + var newLabel = new ILCodeLabel(); + return newLabel; + } + + public ILExceptionRegionBuilder NewFinallyRegion() + { + var region = new ILExceptionRegionBuilder(); + _finallyRegions.Add(region); + return region; + } + + public MethodIL Link(MethodDesc owningMethod) + { + int totalLength = 0; + int numSequencePoints = 0; + + for (int i = 0; i < _codeStreams.Count; i++) + { + ILCodeStream ilCodeStream = _codeStreams[i]; + ilCodeStream._startOffsetForLinking = totalLength; + totalLength += ilCodeStream._length; + numSequencePoints += ilCodeStream._sequencePoints.Count; + } + + byte[] ilInstructions = new byte[totalLength]; + int copiedLength = 0; + for (int i = 0; i < _codeStreams.Count; i++) + { + ILCodeStream ilCodeStream = _codeStreams[i]; + ilCodeStream.PatchLabels(); + Array.Copy(ilCodeStream._instructions, 0, ilInstructions, copiedLength, ilCodeStream._length); + copiedLength += ilCodeStream._length; + } + + MethodDebugInformation debugInfo = null; + if (numSequencePoints > 0) + { + ILSequencePoint[] sequencePoints = new ILSequencePoint[numSequencePoints]; + int copiedSequencePointLength = 0; + for (int codeStreamIndex = 0; codeStreamIndex < _codeStreams.Count; codeStreamIndex++) + { + ILCodeStream ilCodeStream = _codeStreams[codeStreamIndex]; + + for (int sequencePointIndex = 0; sequencePointIndex < ilCodeStream._sequencePoints.Count; sequencePointIndex++) + { + ILSequencePoint sequencePoint = ilCodeStream._sequencePoints[sequencePointIndex]; + sequencePoints[copiedSequencePointLength] = new ILSequencePoint( + ilCodeStream._startOffsetForLinking + sequencePoint.Offset, + sequencePoint.Document, + sequencePoint.LineNumber); + copiedSequencePointLength++; + } + } + + debugInfo = new EmittedMethodDebugInformation(sequencePoints); + } + + ILExceptionRegion[] exceptionRegions = null; + + int numberOfExceptionRegions = _finallyRegions.Count; + if (numberOfExceptionRegions > 0) + { + exceptionRegions = new ILExceptionRegion[numberOfExceptionRegions]; + + for (int i = 0; i < _finallyRegions.Count; i++) + { + ILExceptionRegionBuilder region = _finallyRegions[i]; + + Debug.Assert(region.IsDefined); + + exceptionRegions[i] = new ILExceptionRegion(ILExceptionRegionKind.Finally, + region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength, + classToken: 0, filterOffset: 0); + } + } + + var result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), exceptionRegions, debugInfo); + result.CheckStackBalance(); + return result; + } + + private class EmittedMethodDebugInformation : MethodDebugInformation + { + private readonly ILSequencePoint[] _sequencePoints; + + public EmittedMethodDebugInformation(ILSequencePoint[] sequencePoints) + { + _sequencePoints = sequencePoints; + } + + public override IEnumerable GetSequencePoints() + { + return _sequencePoints; + } + } + } + + public abstract partial class ILStubMethod : MethodDesc + { + public abstract MethodIL EmitIL(); + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return false; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/InterlockedIntrinsics.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/InterlockedIntrinsics.cs new file mode 100644 index 00000000000..bf75857a937 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/InterlockedIntrinsics.cs @@ -0,0 +1,45 @@ +// 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.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL.Stubs +{ + /// + /// Provides method bodies for System.Threading.Interlocked intrinsics. + /// + public static class InterlockedIntrinsics + { + public static MethodIL EmitIL(MethodDesc method) + { + Debug.Assert(((MetadataType)method.OwningType).Name == "Interlocked"); + + if (method.HasInstantiation && method.Name == "CompareExchange") + { + TypeDesc objectType = method.Context.GetWellKnownType(WellKnownType.Object); + MethodDesc compareExchangeObject = method.OwningType.GetKnownMethod("CompareExchange", + new MethodSignature( + MethodSignatureFlags.Static, + genericParameterCount: 0, + returnType: objectType, + parameters: new TypeDesc[] { objectType.MakeByRefType(), objectType, objectType })); + + ILEmitter emit = new ILEmitter(); + ILCodeStream codeStream = emit.NewCodeStream(); + codeStream.EmitLdArg(0); + codeStream.EmitLdArg(1); + codeStream.EmitLdArg(2); + codeStream.Emit(ILOpcode.call, emit.NewToken(compareExchangeObject)); + codeStream.Emit(ILOpcode.ret); + return emit.Link(method); + } + + return null; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeILCodeStreams.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeILCodeStreams.cs new file mode 100644 index 00000000000..c8a7d94d49d --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeILCodeStreams.cs @@ -0,0 +1,45 @@ +// 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.IL.Stubs +{ + internal sealed class PInvokeILCodeStreams + { + public ILEmitter Emitter { get; } + public ILCodeStream FunctionPointerLoadStream { get; } + public ILCodeStream MarshallingCodeStream { get; } + public ILCodeStream CallsiteSetupCodeStream { get; } + public ILCodeStream ReturnValueMarshallingCodeStream { get; } + public ILCodeStream UnmarshallingCodestream { get; } + public ILCodeStream CleanupCodeStream { get; } + public PInvokeILCodeStreams() + { + Emitter = new ILEmitter(); + + // We have these code streams: + // - FunctionPointerLoadStream is used to load the function pointer to call + // - MarshallingCodeStream is used to convert each argument into a native type and + // store that into the local + // - CallsiteSetupCodeStream is used to used to load each previously generated local + // and call the actual target native method. + // - ReturnValueMarshallingCodeStream is used to convert the native return value + // to managed one. + // - UnmarshallingCodestream is used to propagate [out] native arguments values to + // managed ones. + // - CleanupCodestream is used to perform a guaranteed cleanup + FunctionPointerLoadStream = Emitter.NewCodeStream(); + MarshallingCodeStream = Emitter.NewCodeStream(); + CallsiteSetupCodeStream = Emitter.NewCodeStream(); + ReturnValueMarshallingCodeStream = Emitter.NewCodeStream(); + UnmarshallingCodestream = Emitter.NewCodeStream(); + CleanupCodeStream = Emitter.NewCodeStream(); + } + + public PInvokeILCodeStreams(ILEmitter emitter, ILCodeStream codeStream) + { + Emitter = emitter; + MarshallingCodeStream = codeStream; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Diagnostic.cs new file mode 100644 index 00000000000..2cb4d1ea33c --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Diagnostic.cs @@ -0,0 +1,19 @@ +// 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 Internal.TypeSystem; + +namespace Internal.IL.Stubs +{ + partial class PInvokeTargetNativeMethod + { + public override string DiagnosticName + { + get + { + return _declMethod.DiagnosticName; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Mangling.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Mangling.cs new file mode 100644 index 00000000000..79ea39a9001 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Mangling.cs @@ -0,0 +1,27 @@ +// 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 Internal.TypeSystem; + +namespace Internal.IL.Stubs +{ + partial class PInvokeTargetNativeMethod : IPrefixMangledMethod + { + MethodDesc IPrefixMangledMethod.BaseMethod + { + get + { + return _declMethod; + } + } + + string IPrefixMangledMethod.Prefix + { + get + { + return "rawpinvoke"; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Sorting.cs new file mode 100644 index 00000000000..ea754346f7a --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Sorting.cs @@ -0,0 +1,20 @@ +// 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 Internal.TypeSystem; + +namespace Internal.IL.Stubs +{ + // Functionality related to deterministic ordering of types + partial class PInvokeTargetNativeMethod + { + protected internal override int ClassCode => -1626939381; + + protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) + { + var otherMethod = (PInvokeTargetNativeMethod)other; + return comparer.Compare(_declMethod, otherMethod._declMethod); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.cs new file mode 100644 index 00000000000..519dee4e9ab --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.cs @@ -0,0 +1,92 @@ +// 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 Internal.TypeSystem; + +namespace Internal.IL.Stubs +{ + /// + /// Synthetic method that represents the actual PInvoke target method. + /// All parameters are simple types. There will be no code + /// generated for this method. Instead, a static reference to a symbol will be emitted. + /// + public sealed partial class PInvokeTargetNativeMethod : MethodDesc + { + private readonly MethodDesc _declMethod; + private readonly MethodSignature _signature; + + public MethodDesc Target + { + get + { + return _declMethod; + } + } + + public PInvokeTargetNativeMethod(MethodDesc declMethod, MethodSignature signature) + { + _declMethod = declMethod; + _signature = signature; + } + + public override TypeSystemContext Context + { + get + { + return _declMethod.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _declMethod.OwningType; + } + } + + public override MethodSignature Signature + { + get + { + return _signature; + } + } + + public override string Name + { + get + { + return _declMethod.Name; + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return false; + } + + public override bool IsPInvoke + { + get + { + return true; + } + } + + public override bool IsNoInlining + { + get + { + // This method does not have real IL body. NoInlining stops the JIT asking for it. + return true; + } + } + + public override PInvokeMetadata GetPInvokeMethodMetadata() + { + return _declMethod.GetPInvokeMethodMetadata(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/RuntimeHelpersIntrinsics.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/RuntimeHelpersIntrinsics.cs new file mode 100644 index 00000000000..d45a6c9ec08 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/RuntimeHelpersIntrinsics.cs @@ -0,0 +1,97 @@ +// 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.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL.Stubs +{ + /// + /// Provides method bodies for System.Runtime.CompilerServices.RuntimeHelpers intrinsics. + /// + public static class RuntimeHelpersIntrinsics + { + public static MethodIL EmitIL(MethodDesc method) + { + Debug.Assert(((MetadataType)method.OwningType).Name == "RuntimeHelpers"); + string methodName = method.Name; + + if (methodName == "GetRawSzArrayData") + { + ILEmitter emit = new ILEmitter(); + ILCodeStream codeStream = emit.NewCodeStream(); + codeStream.EmitLdArg(0); + codeStream.Emit(ILOpcode.ldflda, emit.NewToken(method.Context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "RawArrayData").GetField("Data"))); + codeStream.Emit(ILOpcode.ret); + return emit.Link(method); + } + + // All the methods handled below are per-instantiation generic methods + if (method.Instantiation.Length != 1 || method.IsTypicalMethodDefinition) + return null; + + TypeDesc elementType = method.Instantiation[0]; + + // Fallback to non-intrinsic implementation for universal generics + if (elementType.IsCanonicalSubtype(CanonicalFormKind.Universal)) + return null; + + bool result; + if (methodName == "IsReferenceOrContainsReferences") + { + result = elementType.IsGCPointer || (elementType is DefType defType && defType.ContainsGCPointers); + } + else if (methodName == "IsReference") + { + result = elementType.IsGCPointer; + } + else if (methodName == "IsBitwiseEquatable") + { + // Ideally we could detect automatically whether a type is trivially equatable + // (i.e., its operator == could be implemented via memcmp). But for now we'll + // do the simple thing and hardcode the list of types we know fulfill this contract. + // n.b. This doesn't imply that the type's CompareTo method can be memcmp-implemented, + // as a method like CompareTo may need to take a type's signedness into account. + switch (elementType.UnderlyingType.Category) + { + case TypeFlags.Boolean: + case TypeFlags.Byte: + case TypeFlags.SByte: + case TypeFlags.Char: + case TypeFlags.UInt16: + case TypeFlags.Int16: + case TypeFlags.UInt32: + case TypeFlags.Int32: + case TypeFlags.UInt64: + case TypeFlags.Int64: + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + result = true; + break; + default: + var mdType = elementType as MetadataType; + if (mdType != null && mdType.Name == "Rune" && mdType.Namespace == "System.Text") + result = true; + else if (mdType != null && mdType.Name == "Char8" && mdType.Namespace == "System") + result = true; + else + result = false; + break; + } + } + else + { + return null; + } + + ILOpcode opcode = result ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0; + + return new ILStubMethodIL(method, new byte[] { (byte)opcode, (byte)ILOpcode.ret }, Array.Empty(), Array.Empty()); + } + } +} + diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs new file mode 100644 index 00000000000..c0e0ea1feab --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs @@ -0,0 +1,141 @@ +// 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.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL.Stubs +{ + /// + /// Provides method bodies for generic System.Runtime.CompilerServices.Unsafe intrinsics. + /// + public static class UnsafeIntrinsics + { + public static MethodIL EmitIL(MethodDesc method) + { + Debug.Assert(((MetadataType)method.OwningType).Name == "Unsafe"); + + switch (method.Name) + { + case "AsPointer": + return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.conv_u, (byte)ILOpcode.ret }, Array.Empty(), null); + case "SizeOf": + return EmitSizeOf(method); + case "As": + case "AsRef": + return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ret }, Array.Empty(), null); + case "Add": + return EmitAdd(method); + case "AddByteOffset": + return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.add, (byte)ILOpcode.ret }, Array.Empty(), null); + case "InitBlockUnaligned": + return new ILStubMethodIL(method, new byte[] { + (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.ldarg_2, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.unaligned), 0x01, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.initblk), + (byte)ILOpcode.ret }, Array.Empty(), null); + case "Read": + return EmitReadWrite(method, write: false); + case "Write": + return EmitReadWrite(method, write: true); + case "ReadUnaligned": + return EmitReadWrite(method, write: false, unaligned: true); + case "WriteUnaligned": + return EmitReadWrite(method, write: true, unaligned: true); + case "AreSame": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), + (byte)ILOpcode.ret }, Array.Empty(), null); + case "IsAddressGreaterThan": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.cgt_un), + (byte)ILOpcode.ret }, Array.Empty(), null); + case "IsAddressLessThan": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.clt_un), + (byte)ILOpcode.ret }, Array.Empty(), null); + case "ByteOffset": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_1, (byte)ILOpcode.ldarg_0, + (byte)ILOpcode.sub, + (byte)ILOpcode.ret }, Array.Empty(), null); + case "NullRef": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldc_i4_0, (byte)ILOpcode.conv_u, + (byte)ILOpcode.ret }, Array.Empty(), null); + case "IsNullRef": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_0, + (byte)ILOpcode.ldc_i4_0, (byte)ILOpcode.conv_u, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), + (byte)ILOpcode.ret }, Array.Empty(), null); + case "SkipInit": + return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ret }, Array.Empty(), null); + } + + return null; + } + + private static MethodIL EmitSizeOf(MethodDesc method) + { + Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 0); + + TypeSystemContext context = method.Context; + + ILEmitter emit = new ILEmitter(); + ILCodeStream codeStream = emit.NewCodeStream(); + codeStream.Emit(ILOpcode.sizeof_, emit.NewToken(context.GetSignatureVariable(0, method: true))); + codeStream.Emit(ILOpcode.ret); + return emit.Link(method); + } + + private static MethodIL EmitAdd(MethodDesc method) + { + Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 2); + + TypeSystemContext context = method.Context; + + ILEmitter emit = new ILEmitter(); + ILCodeStream codeStream = emit.NewCodeStream(); + codeStream.Emit(ILOpcode.ldarg_1); + codeStream.Emit(ILOpcode.sizeof_, emit.NewToken(context.GetSignatureVariable(0, method: true))); + codeStream.Emit(ILOpcode.conv_i); + codeStream.Emit(ILOpcode.mul); + codeStream.Emit(ILOpcode.ldarg_0); + codeStream.Emit(ILOpcode.add); + codeStream.Emit(ILOpcode.ret); + return emit.Link(method); + } + + private static MethodIL EmitReadWrite(MethodDesc method, bool write, bool unaligned = false) + { + Debug.Assert(method.Signature.IsStatic && method.Signature.Length == (write ? 2 : 1)); + + TypeSystemContext context = method.Context; + + ILEmitter emit = new ILEmitter(); + ILCodeStream codeStream = emit.NewCodeStream(); + + codeStream.EmitLdArg(0); + if (write) codeStream.EmitLdArg(1); + if (unaligned) codeStream.EmitUnaligned(); + codeStream.Emit(write ? ILOpcode.stobj : ILOpcode.ldobj, + emit.NewToken(context.GetSignatureVariable(0, method: true))); + codeStream.Emit(ILOpcode.ret); + return emit.Link(method); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs new file mode 100644 index 00000000000..4a9ca72eb9f --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.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.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.IL.Stubs +{ + /// + /// Provides method bodies for System.Threading.Volatile intrinsics. + /// + public static class VolatileIntrinsics + { + public static MethodIL EmitIL(MethodDesc method) + { + Debug.Assert(((MetadataType)method.OwningType).Name == "Volatile"); + + bool isRead = method.Name == "Read"; + if (!isRead && method.Name != "Write") + return null; + + // All interesting methods have a signature that starts with `ref location` + if (method.Signature.Length == 0 || !method.Signature[0].IsByRef) + return null; + + ILOpcode opcode; + switch (((ByRefType)method.Signature[0]).ParameterType.Category) + { + case TypeFlags.SignatureMethodVariable: + opcode = isRead ? ILOpcode.ldind_ref : ILOpcode.stind_ref; + break; + + case TypeFlags.Boolean: + case TypeFlags.SByte: + opcode = isRead ? ILOpcode.ldind_i1 : ILOpcode.stind_i1; + break; + case TypeFlags.Byte: + opcode = isRead ? ILOpcode.ldind_u1 : ILOpcode.stind_i1; + break; + case TypeFlags.Int16: + opcode = isRead ? ILOpcode.ldind_i2 : ILOpcode.stind_i2; + break; + case TypeFlags.UInt16: + opcode = isRead ? ILOpcode.ldind_u2 : ILOpcode.stind_i2; + break; + case TypeFlags.Int32: + opcode = isRead ? ILOpcode.ldind_i4 : ILOpcode.stind_i4; + break; + case TypeFlags.UInt32: + opcode = isRead ? ILOpcode.ldind_u4 : ILOpcode.stind_i4; + break; + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + opcode = isRead ? ILOpcode.ldind_i : ILOpcode.stind_i; + break; + case TypeFlags.Single: + opcode = isRead ? ILOpcode.ldind_r4 : ILOpcode.stind_r4; + break; + + // + // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data. + // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types. + // The implementation in mscorlib already does this, so we will only substitute a new + // IL body if we're running on a 64-bit platform. + // + case TypeFlags.Int64 when method.Context.Target.PointerSize == 8: + case TypeFlags.UInt64 when method.Context.Target.PointerSize == 8: + opcode = isRead ? ILOpcode.ldind_i8 : ILOpcode.stind_i8; + break; + case TypeFlags.Double when method.Context.Target.PointerSize == 8: + opcode = isRead ? ILOpcode.ldind_r8 : ILOpcode.stind_r8; + break; + default: + return null; + } + + byte[] ilBytes; + if (isRead) + { + ilBytes = new byte[] + { + (byte)ILOpcode.ldarg_0, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.volatile_), + (byte)opcode, + (byte)ILOpcode.ret + }; + } + else + { + ilBytes = new byte[] + { + (byte)ILOpcode.ldarg_0, + (byte)ILOpcode.ldarg_1, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.volatile_), + (byte)opcode, + (byte)ILOpcode.ret + }; + } + + return new ILStubMethodIL(method, ilBytes, Array.Empty(), null); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/FieldDesc.Interop.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/FieldDesc.Interop.cs new file mode 100644 index 00000000000..1e7a3e3ba76 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/FieldDesc.Interop.cs @@ -0,0 +1,25 @@ +// 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 +{ + partial class FieldDesc + { + /// + /// Returns description of how the field should be marshalled to native code. + /// + public virtual MarshalAsDescriptor GetMarshalAsDescriptor() + { + return null; + } + } + + partial class FieldForInstantiatedType + { + public override MarshalAsDescriptor GetMarshalAsDescriptor() + { + return _fieldDef.GetMarshalAsDescriptor(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs new file mode 100644 index 00000000000..fc857c30381 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs @@ -0,0 +1,758 @@ +// 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.IL; +using Debug = System.Diagnostics.Debug; +using Internal.IL.Stubs; + +namespace Internal.TypeSystem.Interop +{ + public static partial class MarshalHelpers + { + internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type, + MarshallerKind kind, + MarshallerKind elementMarshallerKind, +#if !READYTORUN + InteropStateManager interopStateManager, +#endif + MarshalAsDescriptor marshalAs, + bool isArrayElement = false) + { + TypeSystemContext context = type.Context; + NativeTypeKind nativeType = NativeTypeKind.Default; + if (marshalAs != null) + { + nativeType = isArrayElement ? marshalAs.ArraySubType : marshalAs.Type; + } + + switch (kind) + { + case MarshallerKind.BlittableValue: + { + switch (nativeType) + { + case NativeTypeKind.I1: + return context.GetWellKnownType(WellKnownType.SByte); + case NativeTypeKind.U1: + return context.GetWellKnownType(WellKnownType.Byte); + case NativeTypeKind.I2: + return context.GetWellKnownType(WellKnownType.Int16); + case NativeTypeKind.U2: + return context.GetWellKnownType(WellKnownType.UInt16); + case NativeTypeKind.I4: + return context.GetWellKnownType(WellKnownType.Int32); + case NativeTypeKind.U4: + return context.GetWellKnownType(WellKnownType.UInt32); + case NativeTypeKind.I8: + return context.GetWellKnownType(WellKnownType.Int64); + case NativeTypeKind.U8: + return context.GetWellKnownType(WellKnownType.UInt64); + case NativeTypeKind.R4: + return context.GetWellKnownType(WellKnownType.Single); + case NativeTypeKind.R8: + return context.GetWellKnownType(WellKnownType.Double); + default: + return type.UnderlyingType; + } + } + + case MarshallerKind.Bool: + return context.GetWellKnownType(WellKnownType.Int32); + + case MarshallerKind.CBool: + return context.GetWellKnownType(WellKnownType.Byte); + + case MarshallerKind.Enum: + case MarshallerKind.BlittableStruct: + case MarshallerKind.Decimal: + case MarshallerKind.VoidReturn: + return type; + +#if !READYTORUN + case MarshallerKind.Struct: + case MarshallerKind.LayoutClass: + return interopStateManager.GetStructMarshallingNativeType((MetadataType)type); +#endif + + case MarshallerKind.BlittableStructPtr: + return type.MakePointerType(); + + case MarshallerKind.HandleRef: + return context.GetWellKnownType(WellKnownType.IntPtr); + + case MarshallerKind.UnicodeChar: + if (nativeType == NativeTypeKind.U2) + return context.GetWellKnownType(WellKnownType.UInt16); + else + return context.GetWellKnownType(WellKnownType.Int16); + + case MarshallerKind.OleDateTime: + return context.GetWellKnownType(WellKnownType.Double); + + case MarshallerKind.SafeHandle: + case MarshallerKind.CriticalHandle: + return context.GetWellKnownType(WellKnownType.IntPtr); + + case MarshallerKind.UnicodeString: + case MarshallerKind.UnicodeStringBuilder: + return context.GetWellKnownType(WellKnownType.Char).MakePointerType(); + + case MarshallerKind.AnsiString: + case MarshallerKind.AnsiStringBuilder: + case MarshallerKind.UTF8String: + return context.GetWellKnownType(WellKnownType.Byte).MakePointerType(); + + case MarshallerKind.BlittableArray: + case MarshallerKind.Array: + case MarshallerKind.AnsiCharArray: + { + ArrayType arrayType = type as ArrayType; + Debug.Assert(arrayType != null, "Expecting array"); + + // + // We need to construct the unsafe array from the right unsafe array element type + // + TypeDesc elementNativeType = GetNativeTypeFromMarshallerKind( + arrayType.ElementType, + elementMarshallerKind, + MarshallerKind.Unknown, +#if !READYTORUN + interopStateManager, +#endif + marshalAs, + isArrayElement: true); + + return elementNativeType.MakePointerType(); + } + + case MarshallerKind.AnsiChar: + return context.GetWellKnownType(WellKnownType.Byte); + + case MarshallerKind.FunctionPointer: + return context.GetWellKnownType(WellKnownType.IntPtr); + +#if !READYTORUN + case MarshallerKind.ByValUnicodeString: + case MarshallerKind.ByValAnsiString: + { + var inlineArrayCandidate = GetInlineArrayCandidate(context.GetWellKnownType(WellKnownType.Char), elementMarshallerKind, interopStateManager, marshalAs); + return interopStateManager.GetInlineArrayType(inlineArrayCandidate); + } + + case MarshallerKind.ByValAnsiCharArray: + case MarshallerKind.ByValArray: + { + ArrayType arrayType = type as ArrayType; + Debug.Assert(arrayType != null, "Expecting array"); + + var inlineArrayCandidate = GetInlineArrayCandidate(arrayType.ElementType, elementMarshallerKind, interopStateManager, marshalAs); + + return interopStateManager.GetInlineArrayType(inlineArrayCandidate); + } +#endif + + case MarshallerKind.LayoutClassPtr: + case MarshallerKind.AsAnyA: + case MarshallerKind.AsAnyW: + return context.GetWellKnownType(WellKnownType.IntPtr); + + case MarshallerKind.Unknown: + default: + throw new NotSupportedException(); + } + } + + internal static MarshallerKind GetMarshallerKind( + TypeDesc type, + MarshalAsDescriptor marshalAs, + bool isReturn, + bool isAnsi, + MarshallerType marshallerType, + out MarshallerKind elementMarshallerKind) + { + elementMarshallerKind = MarshallerKind.Invalid; + + bool isByRef = false; + if (type.IsByRef) + { + isByRef = true; + + type = type.GetParameterType(); + + // Compat note: CLR allows ref returning blittable structs for IJW + if (isReturn) + return MarshallerKind.Invalid; + } + TypeSystemContext context = type.Context; + NativeTypeKind nativeType = NativeTypeKind.Default; + bool isField = marshallerType == MarshallerType.Field; + + if (marshalAs != null) + nativeType = marshalAs.Type; + + // + // Determine MarshalerKind + // + // This mostly resembles desktop CLR and .NET Native code as we need to match their behavior + // + if (type.IsPrimitive) + { + switch (type.Category) + { + case TypeFlags.Void: + return MarshallerKind.VoidReturn; + + case TypeFlags.Boolean: + switch (nativeType) + { + case NativeTypeKind.Default: + case NativeTypeKind.Boolean: + return MarshallerKind.Bool; + + case NativeTypeKind.U1: + case NativeTypeKind.I1: + return MarshallerKind.CBool; + + default: + return MarshallerKind.Invalid; + } + + case TypeFlags.Char: + switch (nativeType) + { + case NativeTypeKind.I1: + case NativeTypeKind.U1: + return MarshallerKind.AnsiChar; + + case NativeTypeKind.I2: + case NativeTypeKind.U2: + return MarshallerKind.UnicodeChar; + + case NativeTypeKind.Default: + if (isAnsi) + return MarshallerKind.AnsiChar; + else + return MarshallerKind.UnicodeChar; + default: + return MarshallerKind.Invalid; + } + + case TypeFlags.SByte: + case TypeFlags.Byte: + if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + + case TypeFlags.Int16: + case TypeFlags.UInt16: + if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + + case TypeFlags.Int32: + case TypeFlags.UInt32: + if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + + case TypeFlags.Int64: + case TypeFlags.UInt64: + if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + if (nativeType == NativeTypeKind.SysInt || nativeType == NativeTypeKind.SysUInt || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + + case TypeFlags.Single: + if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + + case TypeFlags.Double: + if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + + default: + return MarshallerKind.Invalid; + } + } + else if (type.IsValueType) + { + if (type.IsEnum) + return MarshallerKind.Enum; + + if (InteropTypes.IsSystemDateTime(context, type)) + { + if (nativeType == NativeTypeKind.Default || + nativeType == NativeTypeKind.Struct) + return MarshallerKind.OleDateTime; + else + return MarshallerKind.Invalid; + } + else if (InteropTypes.IsHandleRef(context, type)) + { + if (nativeType == NativeTypeKind.Default) + return MarshallerKind.HandleRef; + else + return MarshallerKind.Invalid; + } + else if (InteropTypes.IsSystemDecimal(context, type)) + { + if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default) + return MarshallerKind.Decimal; + else if (nativeType == NativeTypeKind.LPStruct && !isField && !isReturn) + return MarshallerKind.BlittableStructPtr; + else + return MarshallerKind.Invalid; + } + else if (InteropTypes.IsSystemGuid(context, type)) + { + if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableStruct; + else if (nativeType == NativeTypeKind.LPStruct && !isField && !isReturn) + return MarshallerKind.BlittableStructPtr; + else + return MarshallerKind.Invalid; + } + else if (InteropTypes.IsSystemArgIterator(context, type)) + { + // Don't want to fall through to the blittable/haslayout case + return MarshallerKind.Invalid; + } + + bool isBlittable = MarshalUtils.IsBlittableType(type); + + // Blittable generics are allowed to be marshalled with the following exceptions: + // * ByReference: This represents an interior pointer and is not actually blittable + // * Nullable: We don't want to be locked into the default behavior as we may want special handling later + // * Vector64: Represents the __m64 ABI primitive which requires currently unimplemented handling + // * Vector128: Represents the __m128 ABI primitive which requires currently unimplemented handling + // * Vector256: Represents the __m256 ABI primitive which requires currently unimplemented handling + // * Vector: Has a variable size (either __m128 or __m256) and isn't readily usable for inteorp scenarios + + if (type.HasInstantiation && (!isBlittable + || InteropTypes.IsSystemByReference(context, type) + || InteropTypes.IsSystemNullable(context, type) + || InteropTypes.IsSystemRuntimeIntrinsicsVector64T(context, type) + || InteropTypes.IsSystemRuntimeIntrinsicsVector128T(context, type) + || InteropTypes.IsSystemRuntimeIntrinsicsVector256T(context, type) + || InteropTypes.IsSystemNumericsVectorT(context, type))) + { + // Generic types cannot be marshaled. + return MarshallerKind.Invalid; + } + + if (isBlittable) + { + if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct) + return MarshallerKind.Invalid; + + return MarshallerKind.BlittableStruct; + } + else if (((MetadataType)type).HasLayout()) + { + if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct) + return MarshallerKind.Invalid; + + return MarshallerKind.Struct; + } + else + { + return MarshallerKind.Invalid; + } + } + else if (type.IsSzArray) + { +#if READYTORUN + // We don't want the additional test/maintenance cost of this in R2R. + if (isByRef) + return MarshallerKind.Invalid; +#else + _ = isByRef; +#endif + + if (nativeType == NativeTypeKind.Default) + nativeType = NativeTypeKind.Array; + + switch (nativeType) + { + case NativeTypeKind.Array: + { + if (isField || isReturn) + return MarshallerKind.Invalid; + + var arrayType = (ArrayType)type; + + elementMarshallerKind = GetArrayElementMarshallerKind( + arrayType, + marshalAs, + isAnsi); + + // If element is invalid type, the array itself is invalid + if (elementMarshallerKind == MarshallerKind.Invalid) + return MarshallerKind.Invalid; + + if (elementMarshallerKind == MarshallerKind.AnsiChar) + return MarshallerKind.AnsiCharArray; + else if (elementMarshallerKind == MarshallerKind.UnicodeChar // Arrays of unicode char should be marshalled as blittable arrays + || elementMarshallerKind == MarshallerKind.Enum + || elementMarshallerKind == MarshallerKind.BlittableValue) + return MarshallerKind.BlittableArray; + else + return MarshallerKind.Array; + } + + case NativeTypeKind.ByValArray: // fix sized array + { + var arrayType = (ArrayType)type; + elementMarshallerKind = GetArrayElementMarshallerKind( + arrayType, + marshalAs, + isAnsi); + + // If element is invalid type, the array itself is invalid + if (elementMarshallerKind == MarshallerKind.Invalid) + return MarshallerKind.Invalid; + + if (elementMarshallerKind == MarshallerKind.AnsiChar) + return MarshallerKind.ByValAnsiCharArray; + else + return MarshallerKind.ByValArray; + } + + default: + return MarshallerKind.Invalid; + } + } + else if (type.IsPointer) + { + TypeDesc parameterType = ((PointerType)type).ParameterType; + + if ((!parameterType.IsEnum + && !parameterType.IsPrimitive + && !MarshalUtils.IsBlittableType(parameterType)) + || parameterType.IsGCPointer) + { + // Pointers cannot reference marshaled structures. Use ByRef instead. + return MarshallerKind.Invalid; + } + + if (nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + } + else if (type.IsFunctionPointer) + { + if (nativeType == NativeTypeKind.Func || nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + } + else if (type.IsDelegate) + { + if (type.HasInstantiation) + { + // Generic types cannot be marshaled. + return MarshallerKind.Invalid; + } + + if (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Func) + return MarshallerKind.FunctionPointer; + else + return MarshallerKind.Invalid; + } + else if (type.IsString) + { + switch (nativeType) + { + case NativeTypeKind.LPWStr: + return MarshallerKind.UnicodeString; + + case NativeTypeKind.LPStr: + return MarshallerKind.AnsiString; + + case NativeTypeKind.LPUTF8Str: + return MarshallerKind.UTF8String; + + case NativeTypeKind.LPTStr: + return MarshallerKind.UnicodeString; + + case NativeTypeKind.ByValTStr: + if (isAnsi) + { + elementMarshallerKind = MarshallerKind.AnsiChar; + return MarshallerKind.ByValAnsiString; + } + else + { + elementMarshallerKind = MarshallerKind.UnicodeChar; + return MarshallerKind.ByValUnicodeString; + } + + case NativeTypeKind.Default: + if (isAnsi) + return MarshallerKind.AnsiString; + else + return MarshallerKind.UnicodeString; + + default: + return MarshallerKind.Invalid; + } + } + else if (type.IsObject) + { + if (nativeType == NativeTypeKind.AsAny) + return isAnsi ? MarshallerKind.AsAnyA : MarshallerKind.AsAnyW; + else + return MarshallerKind.Invalid; + } + else if (InteropTypes.IsStringBuilder(context, type)) + { + switch (nativeType) + { + case NativeTypeKind.Default: + if (isAnsi) + { + return MarshallerKind.AnsiStringBuilder; + } + else + { + return MarshallerKind.UnicodeStringBuilder; + } + + case NativeTypeKind.LPStr: + return MarshallerKind.AnsiStringBuilder; + + case NativeTypeKind.LPWStr: + return MarshallerKind.UnicodeStringBuilder; + default: + return MarshallerKind.Invalid; + } + } + else if (InteropTypes.IsSafeHandle(context, type)) + { + if (nativeType == NativeTypeKind.Default) + return MarshallerKind.SafeHandle; + else + return MarshallerKind.Invalid; + } + else if (InteropTypes.IsCriticalHandle(context, type)) + { + if (nativeType == NativeTypeKind.Default) + return MarshallerKind.CriticalHandle; + else + return MarshallerKind.Invalid; + } + else if (type is MetadataType mdType && mdType.HasLayout()) + { + if (type.HasInstantiation) + { + // Generic types cannot be marshaled. + return MarshallerKind.Invalid; + } + + if (!isField && nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.LPStruct) + return MarshallerKind.LayoutClassPtr; + else if (isField && (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Struct)) + return MarshallerKind.LayoutClass; + else + return MarshallerKind.Invalid; + } + else + return MarshallerKind.Invalid; + } + + private static MarshallerKind GetArrayElementMarshallerKind( + ArrayType arrayType, + MarshalAsDescriptor marshalAs, + bool isAnsi) + { + TypeDesc elementType = arrayType.ElementType; + NativeTypeKind nativeType = NativeTypeKind.Default; + TypeSystemContext context = arrayType.Context; + + if (marshalAs != null) + nativeType = (NativeTypeKind)marshalAs.ArraySubType; + + if (elementType.IsPrimitive) + { + switch (elementType.Category) + { + case TypeFlags.Char: + switch (nativeType) + { + case NativeTypeKind.I1: + case NativeTypeKind.U1: + return MarshallerKind.AnsiChar; + case NativeTypeKind.I2: + case NativeTypeKind.U2: + return MarshallerKind.UnicodeChar; + default: + if (isAnsi) + return MarshallerKind.AnsiChar; + else + return MarshallerKind.UnicodeChar; + } + + case TypeFlags.Boolean: + switch (nativeType) + { + case NativeTypeKind.Boolean: + return MarshallerKind.Bool; + case NativeTypeKind.I1: + case NativeTypeKind.U1: + return MarshallerKind.CBool; + case NativeTypeKind.Default: + default: + return MarshallerKind.Bool; + } + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + return MarshallerKind.BlittableValue; + + case TypeFlags.Void: + return MarshallerKind.Invalid; + + case TypeFlags.SByte: + case TypeFlags.Int16: + case TypeFlags.Int32: + case TypeFlags.Int64: + case TypeFlags.Byte: + case TypeFlags.UInt16: + case TypeFlags.UInt32: + case TypeFlags.UInt64: + case TypeFlags.Single: + case TypeFlags.Double: + return MarshallerKind.BlittableValue; + default: + return MarshallerKind.Invalid; + } + } + else if (elementType.IsValueType) + { + if (elementType.IsEnum) + return MarshallerKind.Enum; + + if (InteropTypes.IsSystemDecimal(context, elementType)) + { + switch (nativeType) + { + case NativeTypeKind.Default: + case NativeTypeKind.Struct: + return MarshallerKind.Decimal; + + case NativeTypeKind.LPStruct: + return MarshallerKind.BlittableStructPtr; + + default: + return MarshallerKind.Invalid; + } + } + else if (InteropTypes.IsSystemGuid(context, elementType)) + { + switch (nativeType) + { + case NativeTypeKind.Default: + case NativeTypeKind.Struct: + return MarshallerKind.BlittableValue; + + case NativeTypeKind.LPStruct: + return MarshallerKind.BlittableStructPtr; + + default: + return MarshallerKind.Invalid; + } + } + else if (InteropTypes.IsSystemDateTime(context, elementType)) + { + if (nativeType == NativeTypeKind.Default || + nativeType == NativeTypeKind.Struct) + { + return MarshallerKind.OleDateTime; + } + else + { + return MarshallerKind.Invalid; + } + } + else if (InteropTypes.IsHandleRef(context, elementType)) + { + if (nativeType == NativeTypeKind.Default) + return MarshallerKind.HandleRef; + else + return MarshallerKind.Invalid; + } + else + { + if (MarshalUtils.IsBlittableType(elementType)) + { + switch (nativeType) + { + case NativeTypeKind.Default: + case NativeTypeKind.Struct: + return MarshallerKind.BlittableStruct; + + default: + return MarshallerKind.Invalid; + } + } + else + { + // TODO: Differentiate between struct and Union, we only need to support struct not union here + return MarshallerKind.Struct; + } + } + } + else if (elementType.IsPointer || elementType.IsFunctionPointer) + { + if (nativeType == NativeTypeKind.Default) + return MarshallerKind.BlittableValue; + else + return MarshallerKind.Invalid; + } + else if (elementType.IsString) + { + switch (nativeType) + { + case NativeTypeKind.Default: + if (isAnsi) + return MarshallerKind.AnsiString; + else + return MarshallerKind.UnicodeString; + case NativeTypeKind.LPStr: + return MarshallerKind.AnsiString; + case NativeTypeKind.LPWStr: + return MarshallerKind.UnicodeString; + default: + return MarshallerKind.Invalid; + } + } + // else if (elementType.IsObject) + // { + // if (nativeType == NativeTypeKind.Invalid) + // return MarshallerKind.Variant; + // else + // return MarshallerKind.Invalid; + // } + else + { + return MarshallerKind.Invalid; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalUtils.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalUtils.cs new file mode 100644 index 00000000000..ce0897a1177 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalUtils.cs @@ -0,0 +1,74 @@ +// 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; + +namespace Internal.TypeSystem.Interop +{ + public static class MarshalUtils + { + /// + /// Returns true if this type has a common representation in both managed and unmanaged memory + /// and does not require special handling by the interop marshaler. + /// + public static bool IsBlittableType(TypeDesc type) + { + if (!type.IsDefType) + { + return false; + } + + TypeDesc baseType = type.BaseType; + bool hasNonTrivialParent = baseType != null + && !baseType.IsWellKnownType(WellKnownType.Object) + && !baseType.IsWellKnownType(WellKnownType.ValueType); + + if (hasNonTrivialParent && !IsBlittableType(baseType)) + { + return false; + } + + var mdType = (MetadataType)type; + + if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout) + { + return false; + } + + foreach (FieldDesc field in type.GetFields()) + { + if (field.IsStatic) + { + continue; + } + + if (!field.FieldType.IsValueType) + { + // Types with fields of non-value types cannot be blittable + // This check prevents possible infinite recursion where GetMarshallerKind would call back to IsBlittable e.g. for + // the case of classes with pointer members to the class itself. + return false; + } + + MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind( + field.FieldType, + field.GetMarshalAsDescriptor(), + isReturn: false, + isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass, + MarshallerType.Field, + elementMarshallerKind: out var _); + + if (marshallerKind != MarshallerKind.Enum + && marshallerKind != MarshallerKind.BlittableValue + && marshallerKind != MarshallerKind.BlittableStruct + && marshallerKind != MarshallerKind.UnicodeChar) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/Marshaller.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/Marshaller.cs new file mode 100644 index 00000000000..f037e12b780 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/Marshaller.cs @@ -0,0 +1,1956 @@ +// 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.Runtime.InteropServices; +using Internal.IL.Stubs; +using Internal.IL; + +using Debug = System.Diagnostics.Debug; +using ILLocalVariable = Internal.IL.Stubs.ILLocalVariable; + +namespace Internal.TypeSystem.Interop +{ + enum MarshallerKind + { + Unknown, + BlittableValue, + Array, + BlittableArray, + Bool, // 4 byte bool + CBool, // 1 byte bool + Enum, + AnsiChar, // Marshal char (Unicode 16bits) for byte (Ansi 8bits) + UnicodeChar, + AnsiCharArray, + ByValArray, + ByValAnsiCharArray, // Particular case of ByValArray because the conversion between wide Char and Byte need special treatment. + AnsiString, + UnicodeString, + UTF8String, + ByValAnsiString, + ByValUnicodeString, + AnsiStringBuilder, + UnicodeStringBuilder, + FunctionPointer, + SafeHandle, + CriticalHandle, + HandleRef, + VoidReturn, + Variant, + Object, + OleDateTime, + Decimal, + Guid, + Struct, + BlittableStruct, + BlittableStructPtr, // Additional indirection on top of blittable struct. Used by MarshalAs(LpStruct) + LayoutClass, + LayoutClassPtr, + AsAnyA, + AsAnyW, + Invalid + } + public enum MarshalDirection + { + Forward, // safe-to-unsafe / managed-to-native + Reverse, // unsafe-to-safe / native-to-managed + } + + public enum MarshallerType + { + Argument, + Element, + Field + } + + // Each type of marshaller knows how to generate the marshalling code for the argument it marshals. + // Marshallers contain method related marshalling information (which is common to all the Marshallers) + // and also argument specific marshalling informaiton + abstract partial class Marshaller + { + #region Instance state information + public TypeSystemContext Context; +#if !READYTORUN + public InteropStateManager InteropStateManager; +#endif + public MarshallerKind MarshallerKind; + public MarshallerType MarshallerType; + public MarshalAsDescriptor MarshalAsDescriptor; + public MarshallerKind ElementMarshallerKind; + public int Index; + public TypeDesc ManagedType; + public TypeDesc ManagedParameterType; + public PInvokeFlags PInvokeFlags; + protected Marshaller[] Marshallers; + private TypeDesc _nativeType; + private TypeDesc _nativeParamType; + + /// + /// Native Type of the value being marshalled + /// For by-ref scenarios (ref T), Native Type is T + /// + public TypeDesc NativeType + { + get + { + if (_nativeType == null) + { + _nativeType = MarshalHelpers.GetNativeTypeFromMarshallerKind( + ManagedType, + MarshallerKind, + ElementMarshallerKind, +#if !READYTORUN + InteropStateManager, +#endif + MarshalAsDescriptor); + Debug.Assert(_nativeType != null); + } + + return _nativeType; + } + } + + /// + /// NativeType appears in function parameters + /// For by-ref scenarios (ref T), NativeParameterType is T* + /// + public TypeDesc NativeParameterType + { + get + { + if (_nativeParamType == null) + { + TypeDesc nativeParamType = NativeType; + if (IsNativeByRef) + nativeParamType = nativeParamType.MakePointerType(); + _nativeParamType = nativeParamType; + } + + return _nativeParamType; + } + } + + /// + /// Indicates whether cleanup is necessay if this marshaller is used + /// as an element of an array marshaller + /// + internal virtual bool CleanupRequired + { + get + { + return false; + } + } + + public bool In; + public bool Out; + public bool Return; + public bool IsManagedByRef; // Whether managed argument is passed by ref + public bool IsNativeByRef; // Whether native argument is passed by byref + // There are special cases (such as LpStruct, and class) that + // isNativeByRef != IsManagedByRef + public MarshalDirection MarshalDirection; + protected PInvokeILCodeStreams _ilCodeStreams; + protected Home _managedHome; + protected Home _nativeHome; + #endregion + + enum HomeType + { + Arg, + Local, + ByRefArg, + ByRefLocal + } + + /// + /// Abstraction for handling by-ref and non-by-ref locals/arguments + /// + internal class Home + { + public Home(ILLocalVariable var, TypeDesc type, bool isByRef) + { + _homeType = isByRef ? HomeType.ByRefLocal : HomeType.Local; + _type = type; + _var = var; + } + + public Home(int argIndex, TypeDesc type, bool isByRef) + { + _homeType = isByRef ? HomeType.ByRefArg : HomeType.Arg; + _type = type; + _argIndex = argIndex; + } + + public void LoadValue(ILCodeStream stream) + { + switch (_homeType) + { + case HomeType.Arg: + stream.EmitLdArg(_argIndex); + break; + case HomeType.ByRefArg: + stream.EmitLdArg(_argIndex); + stream.EmitLdInd(_type); + break; + case HomeType.Local: + stream.EmitLdLoc(_var); + break; + case HomeType.ByRefLocal: + stream.EmitLdLoc(_var); + stream.EmitLdInd(_type); + break; + default: + Debug.Assert(false); + break; + } + } + + public void LoadAddr(ILCodeStream stream) + { + switch (_homeType) + { + case HomeType.Arg: + stream.EmitLdArga(_argIndex); + break; + case HomeType.ByRefArg: + stream.EmitLdArg(_argIndex); + break; + case HomeType.Local: + stream.EmitLdLoca(_var); + break; + case HomeType.ByRefLocal: + stream.EmitLdLoc(_var); + break; + default: + Debug.Assert(false); + break; + } + } + + public void StoreValue(ILCodeStream stream) + { + switch (_homeType) + { + case HomeType.Arg: + Debug.Fail("Unexpectting setting value on non-byref arg"); + break; + case HomeType.Local: + stream.EmitStLoc(_var); + break; + default: + // Storing by-ref arg/local is not supported because StInd require + // address to be pushed first. Instead we need to introduce a non-byref + // local and propagate value as needed for by-ref arguments + Debug.Assert(false); + break; + } + } + + HomeType _homeType; + TypeDesc _type; + ILLocalVariable _var; + int _argIndex; + } + + #region Creation of marshallers + + /// + /// Protected ctor + /// Only Marshaller.CreateMarshaller can create a marshaller + /// + protected Marshaller() + { + } + + /// + /// Create a marshaller + /// + /// type of the parameter to marshal + /// The created Marshaller + public static Marshaller CreateMarshaller(TypeDesc parameterType, + MarshallerType marshallerType, + MarshalAsDescriptor marshalAs, + MarshalDirection direction, + Marshaller[] marshallers, +#if !READYTORUN + InteropStateManager interopStateManager, +#endif + int index, + PInvokeFlags flags, + bool isIn, + bool isOut, + bool isReturn) + { + MarshallerKind elementMarshallerKind; + MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(parameterType, + marshalAs, + isReturn, + flags.CharSet == CharSet.Ansi, + marshallerType, + out elementMarshallerKind); + + TypeSystemContext context = parameterType.Context; + // Create the marshaller based on MarshallerKind + Marshaller marshaller = CreateMarshaller(marshallerKind); + marshaller.Context = context; +#if !READYTORUN + marshaller.InteropStateManager = interopStateManager; +#endif + marshaller.MarshallerKind = marshallerKind; + marshaller.MarshallerType = marshallerType; + marshaller.ElementMarshallerKind = elementMarshallerKind; + marshaller.ManagedParameterType = parameterType; + marshaller.ManagedType = parameterType.IsByRef ? parameterType.GetParameterType() : parameterType; + marshaller.Return = isReturn; + marshaller.IsManagedByRef = parameterType.IsByRef; + marshaller.IsNativeByRef = marshaller.IsManagedByRef /* || isRetVal || LpStruct /etc */; + marshaller.In = isIn; + marshaller.MarshalDirection = direction; + marshaller.MarshalAsDescriptor = marshalAs; + marshaller.Marshallers = marshallers; + marshaller.Index = index; + marshaller.PInvokeFlags = flags; + + // + // Desktop ignores [Out] on marshaling scenarios where they don't make sense + // + if (isOut) + { + // Passing as [Out] by ref is always valid. + if (!marshaller.IsManagedByRef) + { + // Ignore [Out] for ValueType, string and pointers + if (parameterType.IsValueType || parameterType.IsString || parameterType.IsPointer || parameterType.IsFunctionPointer) + { + isOut = false; + } + } + } + marshaller.Out = isOut; + + if (!marshaller.In && !marshaller.Out) + { + // + // Rules for in/out + // 1. ByRef args: [in]/[out] implied by default + // 2. StringBuilder: [in, out] by default + // 3. non-ByRef args: [In] is implied if no [In]/[Out] is specified + // + if (marshaller.IsManagedByRef) + { + marshaller.In = true; + marshaller.Out = true; + } + else if (InteropTypes.IsStringBuilder(context, parameterType)) + { + marshaller.In = true; + marshaller.Out = true; + } + else + { + marshaller.In = true; + } + } + + // For unicodestring/ansistring, ignore out when it's in + if (!marshaller.IsManagedByRef && marshaller.In) + { + if (marshaller.MarshallerKind == MarshallerKind.AnsiString || marshaller.MarshallerKind == MarshallerKind.UnicodeString) + marshaller.Out = false; + } + + return marshaller; + } + + public static Marshaller[] GetMarshallersForMethod(MethodDesc targetMethod) + { + Debug.Assert(targetMethod.IsPInvoke); + + MarshalDirection direction = MarshalDirection.Forward; + MethodSignature methodSig = targetMethod.Signature; + PInvokeFlags flags = targetMethod.GetPInvokeMethodMetadata().Flags; + + ParameterMetadata[] parameterMetadataArray = targetMethod.GetParameterMetadata(); + Marshaller[] marshallers = new Marshaller[methodSig.Length + 1]; + ParameterMetadata parameterMetadata; + + for (int i = 0, parameterIndex = 0; i < marshallers.Length; i++) + { + Debug.Assert(parameterIndex == parameterMetadataArray.Length || i <= parameterMetadataArray[parameterIndex].Index); + if (parameterIndex == parameterMetadataArray.Length || i < parameterMetadataArray[parameterIndex].Index) + { + // if we don't have metadata for the parameter, create a dummy one + parameterMetadata = new ParameterMetadata(i, ParameterMetadataAttributes.None, null); + } + else + { + Debug.Assert(i == parameterMetadataArray[parameterIndex].Index); + parameterMetadata = parameterMetadataArray[parameterIndex++]; + } + + TypeDesc parameterType = (i == 0) ? methodSig.ReturnType : methodSig[i - 1]; //first item is the return type + marshallers[i] = CreateMarshaller(parameterType, + MarshallerType.Argument, + parameterMetadata.MarshalAsDescriptor, + direction, + marshallers, + parameterMetadata.Index, + flags, + parameterMetadata.In, + parameterMetadata.Out, + parameterMetadata.Return); + } + + return marshallers; + } + #endregion + + + #region Marshalling Requirement Checking + private static bool IsMarshallingRequired(MarshallerKind kind) + { + switch (kind) + { + case MarshallerKind.Enum: + case MarshallerKind.BlittableValue: + case MarshallerKind.BlittableStruct: + case MarshallerKind.UnicodeChar: + case MarshallerKind.VoidReturn: + return false; + } + return true; + } + + private bool IsMarshallingRequired() + { + return Out || IsMarshallingRequired(MarshallerKind); + } + + public static bool IsMarshallingRequired(MethodDesc targetMethod) + { + Debug.Assert(targetMethod.IsPInvoke); + + PInvokeFlags flags = targetMethod.GetPInvokeMethodMetadata().Flags; + + if (flags.SetLastError) + return true; + + if (!flags.PreserveSig) + return true; + + var marshallers = GetMarshallersForMethod(targetMethod); + for (int i = 0; i < marshallers.Length; i++) + { + if (marshallers[i].IsMarshallingRequired()) + return true; + } + + return false; + } + + public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMetadata[] paramMetadata) + { + for (int i = 0, paramIndex = 0; i < methodSig.Length + 1; i++) + { + ParameterMetadata parameterMetadata = (paramIndex == paramMetadata.Length || i < paramMetadata[paramIndex].Index) ? + new ParameterMetadata(i, ParameterMetadataAttributes.None, null) : + paramMetadata[paramIndex++]; + + TypeDesc parameterType = (i == 0) ? methodSig.ReturnType : methodSig[i - 1]; //first item is the return type + + MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind( + parameterType, + parameterMetadata.MarshalAsDescriptor, + parameterMetadata.Return, + isAnsi: true, + MarshallerType.Argument, + out MarshallerKind elementMarshallerKind); + + if (IsMarshallingRequired(marshallerKind)) + return true; + } + + return false; + } + #endregion + + public virtual void EmitMarshallingIL(PInvokeILCodeStreams pInvokeILCodeStreams) + { + _ilCodeStreams = pInvokeILCodeStreams; + + switch (MarshallerType) + { + case MarshallerType.Argument: EmitArgumentMarshallingIL(); return; + case MarshallerType.Element: EmitElementMarshallingIL(); return; + case MarshallerType.Field: EmitFieldMarshallingIL(); return; + } + } + + private void EmitArgumentMarshallingIL() + { + switch (MarshalDirection) + { + case MarshalDirection.Forward: EmitForwardArgumentMarshallingIL(); return; + case MarshalDirection.Reverse: EmitReverseArgumentMarshallingIL(); return; + } + } + + private void EmitElementMarshallingIL() + { + switch (MarshalDirection) + { + case MarshalDirection.Forward: EmitForwardElementMarshallingIL(); return; + case MarshalDirection.Reverse: EmitReverseElementMarshallingIL(); return; + } + } + + private void EmitFieldMarshallingIL() + { + switch (MarshalDirection) + { + case MarshalDirection.Forward: EmitForwardFieldMarshallingIL(); return; + case MarshalDirection.Reverse: EmitReverseFieldMarshallingIL(); return; + } + } + + protected virtual void EmitForwardArgumentMarshallingIL() + { + if (Return) + { + EmitMarshalReturnValueManagedToNative(); + } + else + { + EmitMarshalArgumentManagedToNative(); + } + } + + protected virtual void EmitReverseArgumentMarshallingIL() + { + if (Return) + { + EmitMarshalReturnValueNativeToManaged(); + } + else + { + EmitMarshalArgumentNativeToManaged(); + } + } + + protected virtual void EmitForwardElementMarshallingIL() + { + if (In) + EmitMarshalElementManagedToNative(); + else + EmitMarshalElementNativeToManaged(); + } + + protected virtual void EmitReverseElementMarshallingIL() + { + if (In) + EmitMarshalElementNativeToManaged(); + else + EmitMarshalElementManagedToNative(); + } + + protected virtual void EmitForwardFieldMarshallingIL() + { + if (In) + EmitMarshalFieldManagedToNative(); + else + EmitMarshalFieldNativeToManaged(); + } + + protected virtual void EmitReverseFieldMarshallingIL() + { + if (In) + EmitMarshalFieldNativeToManaged(); + else + EmitMarshalFieldManagedToNative(); + } + + + protected virtual void EmitMarshalReturnValueManagedToNative() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + SetupArgumentsForReturnValueMarshalling(); + + StoreNativeValue(_ilCodeStreams.ReturnValueMarshallingCodeStream); + + AllocAndTransformNativeToManaged(_ilCodeStreams.ReturnValueMarshallingCodeStream); + } + + public virtual void LoadReturnValue(ILCodeStream codeStream) + { + Debug.Assert(Return); + + switch (MarshalDirection) + { + case MarshalDirection.Forward: LoadManagedValue(codeStream); return; + case MarshalDirection.Reverse: LoadNativeValue(codeStream); return; + } + } + + protected virtual void SetupArguments() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + if (MarshalDirection == MarshalDirection.Forward) + { + // Due to StInd order (address, value), we can't do the following: + // LoadValue + // StoreManagedValue (LdArg + StInd) + // The way to work around this is to put it in a local + if (IsManagedByRef) + _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, false); + else + _managedHome = new Home(Index - 1, ManagedType, false); + _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); + } + else + { + _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); + if (IsNativeByRef) + _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); + else + _nativeHome = new Home(Index - 1, NativeType, isByRef: false); + } + } + + protected virtual void SetupArgumentsForElementMarshalling() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); + _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); + } + + protected virtual void SetupArgumentsForFieldMarshalling() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + // + // these are temporary locals for propagating value + // + _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); + _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); + } + + protected virtual void SetupArgumentsForReturnValueMarshalling() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); + _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); + } + + protected void LoadManagedValue(ILCodeStream stream) + { + _managedHome.LoadValue(stream); + } + + protected void LoadManagedAddr(ILCodeStream stream) + { + _managedHome.LoadAddr(stream); + } + + /// + /// Loads the argument to be passed to managed functions + /// In by-ref scenarios (ref T), it is &T + /// + protected void LoadManagedArg(ILCodeStream stream) + { + if (IsManagedByRef) + _managedHome.LoadAddr(stream); + else + _managedHome.LoadValue(stream); + } + + protected void StoreManagedValue(ILCodeStream stream) + { + _managedHome.StoreValue(stream); + } + + protected void LoadNativeValue(ILCodeStream stream) + { + _nativeHome.LoadValue(stream); + } + + /// + /// Loads the argument to be passed to native functions + /// In by-ref scenarios (ref T), it is T* + /// + protected void LoadNativeArg(ILCodeStream stream) + { + if (IsNativeByRef) + _nativeHome.LoadAddr(stream); + else + _nativeHome.LoadValue(stream); + } + + protected void LoadNativeAddr(ILCodeStream stream) + { + _nativeHome.LoadAddr(stream); + } + + protected void StoreNativeValue(ILCodeStream stream) + { + _nativeHome.StoreValue(stream); + } + + + /// + /// Propagate by-ref arg to corresponding local + /// We can't load value + ldarg + ldind in the expected order, so + /// we had to use a non-by-ref local and manually propagate the value + /// + protected void PropagateFromByRefArg(ILCodeStream stream, Home home) + { + stream.EmitLdArg(Index - 1); + stream.EmitLdInd(ManagedType); + home.StoreValue(stream); + } + + /// + /// Propagate local to corresponding by-ref arg + /// We can't load value + ldarg + ldind in the expected order, so + /// we had to use a non-by-ref local and manually propagate the value + /// + protected void PropagateToByRefArg(ILCodeStream stream, Home home) + { + stream.EmitLdArg(Index - 1); + home.LoadValue(stream); + stream.EmitStInd(ManagedType); + } + + protected virtual void EmitMarshalArgumentManagedToNative() + { + SetupArguments(); + + if (IsManagedByRef && In) + { + // Propagate byref arg to local + PropagateFromByRefArg(_ilCodeStreams.MarshallingCodeStream, _managedHome); + } + + // + // marshal + // + if (IsManagedByRef && !In) + { + ReInitNativeTransform(_ilCodeStreams.MarshallingCodeStream); + } + else + { + AllocAndTransformManagedToNative(_ilCodeStreams.MarshallingCodeStream); + } + + LoadNativeArg(_ilCodeStreams.CallsiteSetupCodeStream); + + // + // unmarshal + // + if (Out) + { + if (In) + { + ClearManagedTransform(_ilCodeStreams.UnmarshallingCodestream); + } + + if (IsManagedByRef && !In) + { + AllocNativeToManaged(_ilCodeStreams.UnmarshallingCodestream); + } + + TransformNativeToManaged(_ilCodeStreams.UnmarshallingCodestream); + + if (IsManagedByRef) + { + // Propagate back to byref arguments + PropagateToByRefArg(_ilCodeStreams.UnmarshallingCodestream, _managedHome); + } + } + + EmitCleanupManaged(_ilCodeStreams.CleanupCodeStream); + } + + /// + /// Reads managed parameter from _vManaged and writes the marshalled parameter in _vNative + /// + protected virtual void AllocAndTransformManagedToNative(ILCodeStream codeStream) + { + AllocManagedToNative(codeStream); + if (In) + { + TransformManagedToNative(codeStream); + } + } + + protected virtual void AllocAndTransformNativeToManaged(ILCodeStream codeStream) + { + AllocNativeToManaged(codeStream); + TransformNativeToManaged(codeStream); + } + + protected virtual void AllocManagedToNative(ILCodeStream codeStream) + { + } + protected virtual void TransformManagedToNative(ILCodeStream codeStream) + { + LoadManagedValue(codeStream); + StoreNativeValue(codeStream); + } + + protected virtual void ClearManagedTransform(ILCodeStream codeStream) + { + } + protected virtual void AllocNativeToManaged(ILCodeStream codeStream) + { + } + + protected virtual void TransformNativeToManaged(ILCodeStream codeStream) + { + LoadNativeValue(codeStream); + StoreManagedValue(codeStream); + } + + protected virtual void EmitCleanupManaged(ILCodeStream codeStream) + { + } + + protected virtual void EmitMarshalReturnValueNativeToManaged() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + SetupArgumentsForReturnValueMarshalling(); + + StoreManagedValue(_ilCodeStreams.ReturnValueMarshallingCodeStream); + + AllocAndTransformManagedToNative(_ilCodeStreams.ReturnValueMarshallingCodeStream); + } + + protected virtual void EmitMarshalArgumentNativeToManaged() + { + SetupArguments(); + + if (IsNativeByRef && In) + { + // Propagate byref arg to local + PropagateFromByRefArg(_ilCodeStreams.MarshallingCodeStream, _nativeHome); + } + + if (IsNativeByRef && !In) + { + ReInitManagedTransform(_ilCodeStreams.MarshallingCodeStream); + } + else + { + AllocAndTransformNativeToManaged(_ilCodeStreams.MarshallingCodeStream); + } + + LoadManagedArg(_ilCodeStreams.CallsiteSetupCodeStream); + + if (Out) + { + if (IsNativeByRef) + { + AllocManagedToNative(_ilCodeStreams.UnmarshallingCodestream); + } + + TransformManagedToNative(_ilCodeStreams.UnmarshallingCodestream); + + if (IsNativeByRef) + { + // Propagate back to byref arguments + PropagateToByRefArg(_ilCodeStreams.UnmarshallingCodestream, _nativeHome); + } + } + } + + protected virtual void EmitMarshalElementManagedToNative() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeStream codeStream = _ilCodeStreams.MarshallingCodeStream; + Debug.Assert(codeStream != null); + + SetupArgumentsForElementMarshalling(); + + StoreManagedValue(codeStream); + + // marshal + AllocAndTransformManagedToNative(codeStream); + + LoadNativeValue(codeStream); + } + + protected virtual void EmitMarshalElementNativeToManaged() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeStream codeStream = _ilCodeStreams.MarshallingCodeStream; + Debug.Assert(codeStream != null); + + SetupArgumentsForElementMarshalling(); + + StoreNativeValue(codeStream); + + // unmarshal + AllocAndTransformNativeToManaged(codeStream); + LoadManagedValue(codeStream); + } + + protected virtual void EmitMarshalFieldManagedToNative() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; + + SetupArgumentsForFieldMarshalling(); + // + // For field marshalling we expect the value of the field is already loaded + // in the stack. + // + StoreManagedValue(marshallingCodeStream); + + // marshal + AllocAndTransformManagedToNative(marshallingCodeStream); + + LoadNativeValue(marshallingCodeStream); + } + + protected virtual void EmitMarshalFieldNativeToManaged() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeStream codeStream = _ilCodeStreams.MarshallingCodeStream; + + SetupArgumentsForFieldMarshalling(); + + StoreNativeValue(codeStream); + + // unmarshal + AllocAndTransformNativeToManaged(codeStream); + LoadManagedValue(codeStream); + } + + protected virtual void ReInitManagedTransform(ILCodeStream codeStream) + { + } + + protected virtual void ReInitNativeTransform(ILCodeStream codeStream) + { + } + + internal virtual void EmitElementCleanup(ILCodeStream codestream, ILEmitter emitter) + { + } + } + + class NotSupportedMarshaller : Marshaller + { + public override void EmitMarshallingIL(PInvokeILCodeStreams pInvokeILCodeStreams) + { + throw new NotSupportedException(); + } + } + + class VoidReturnMarshaller : Marshaller + { + protected override void EmitMarshalReturnValueManagedToNative() + { + } + protected override void EmitMarshalReturnValueNativeToManaged() + { + } + public override void LoadReturnValue(ILCodeStream codeStream) + { + Debug.Assert(Return); + } + } + + class BlittableValueMarshaller : Marshaller + { + protected override void EmitMarshalArgumentManagedToNative() + { + if (IsNativeByRef && MarshalDirection == MarshalDirection.Forward) + { + ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; + ILEmitter emitter = _ilCodeStreams.Emitter; + ILLocalVariable native = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); + + ILLocalVariable vPinnedByRef = emitter.NewLocal(ManagedParameterType, true); + marshallingCodeStream.EmitLdArg(Index - 1); + marshallingCodeStream.EmitStLoc(vPinnedByRef); + marshallingCodeStream.EmitLdLoc(vPinnedByRef); + marshallingCodeStream.Emit(ILOpcode.conv_i); + marshallingCodeStream.EmitStLoc(native); + _ilCodeStreams.CallsiteSetupCodeStream.EmitLdLoc(native); + } + else + { + _ilCodeStreams.CallsiteSetupCodeStream.EmitLdArg(Index - 1); + } + } + + protected override void EmitMarshalArgumentNativeToManaged() + { + if (Out) + { + base.EmitMarshalArgumentNativeToManaged(); + } + else + { + _ilCodeStreams.CallsiteSetupCodeStream.EmitLdArg(Index - 1); + } + } + } + + class BlittableStructPtrMarshaller : Marshaller + { + protected override void TransformManagedToNative(ILCodeStream codeStream) + { + if (Out) + { + // TODO: https://github.com/dotnet/corert/issues/4466 + throw new NotSupportedException("Marshalling an LPStruct argument not yet implemented"); + } + else + { + LoadManagedAddr(codeStream); + StoreNativeValue(codeStream); + } + } + + protected override void TransformNativeToManaged(ILCodeStream codeStream) + { + // TODO: https://github.com/dotnet/corert/issues/4466 + throw new NotSupportedException("Marshalling an LPStruct argument not yet implemented"); + } + } + + class ArrayMarshaller : Marshaller + { + private Marshaller _elementMarshaller; + + protected TypeDesc ManagedElementType + { + get + { + Debug.Assert(ManagedType is ArrayType); + var arrayType = (ArrayType)ManagedType; + return arrayType.ElementType; + } + } + + protected TypeDesc NativeElementType + { + get + { + Debug.Assert(NativeType is PointerType); + return ((PointerType)NativeType).ParameterType; + } + } + + protected Marshaller GetElementMarshaller(MarshalDirection direction) + { + if (_elementMarshaller == null) + { + _elementMarshaller = CreateMarshaller(ElementMarshallerKind); + _elementMarshaller.MarshallerKind = ElementMarshallerKind; + _elementMarshaller.MarshallerType = MarshallerType.Element; +#if !READYTORUN + _elementMarshaller.InteropStateManager = InteropStateManager; +#endif + _elementMarshaller.Return = Return; + _elementMarshaller.Context = Context; + _elementMarshaller.ManagedType = ManagedElementType; + _elementMarshaller.MarshalAsDescriptor = MarshalAsDescriptor; + _elementMarshaller.PInvokeFlags = PInvokeFlags; + } + _elementMarshaller.In = (direction == MarshalDirection); + _elementMarshaller.Out = !In; + _elementMarshaller.MarshalDirection = MarshalDirection; + + return _elementMarshaller; + } + + protected virtual void EmitElementCount(ILCodeStream codeStream, MarshalDirection direction) + { + if (direction == MarshalDirection.Forward) + { + // In forward direction we skip whatever is passed through SizeParamIndex, because the + // size of the managed array is already known + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.ldlen); + codeStream.Emit(ILOpcode.conv_i4); + + } + else if (MarshalDirection == MarshalDirection.Forward + && MarshallerType == MarshallerType.Argument + && !Return + && !IsManagedByRef) + { + EmitElementCount(codeStream, MarshalDirection.Forward); + } + else + { + + uint? sizeParamIndex = MarshalAsDescriptor != null ? MarshalAsDescriptor.SizeParamIndex : null; + uint? sizeConst = MarshalAsDescriptor != null ? MarshalAsDescriptor.SizeConst : null; + + if (sizeConst.HasValue) + { + codeStream.EmitLdc((int)sizeConst.Value); + } + + if (sizeParamIndex.HasValue) + { + uint index = sizeParamIndex.Value; + + if (index < 0 || index >= Marshallers.Length - 1) + { + throw new InvalidProgramException("Invalid SizeParamIndex, must be between 0 and parameter count"); + } + + //zero-th index is for return type + index++; + var indexType = Marshallers[index].ManagedType; + switch (indexType.Category) + { + case TypeFlags.Byte: + case TypeFlags.SByte: + case TypeFlags.Int16: + case TypeFlags.UInt16: + case TypeFlags.Int32: + case TypeFlags.UInt32: + case TypeFlags.Int64: + case TypeFlags.UInt64: + case TypeFlags.IntPtr: + case TypeFlags.UIntPtr: + break; + default: + throw new InvalidProgramException("Invalid SizeParamIndex, parameter must be of type int/uint"); + } + + // @TODO - We can use LoadManagedValue, but that requires byref arg propagation happen in a special setup stream + // otherwise there is an ordering issue + codeStream.EmitLdArg(Marshallers[index].Index - 1); + if (Marshallers[index].IsManagedByRef) + codeStream.EmitLdInd(indexType); + + if (sizeConst.HasValue) + codeStream.Emit(ILOpcode.add); + } + + if (!sizeConst.HasValue && !sizeParamIndex.HasValue) + { + // if neither sizeConst or sizeParamIndex are specified, default to 1 + codeStream.EmitLdc(1); + } + } + } + + protected override void AllocManagedToNative(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeLabel lNullArray = emitter.NewCodeLabel(); + + codeStream.EmitLdc(0); + codeStream.Emit(ILOpcode.conv_u); + StoreNativeValue(codeStream); + + // Check for null array + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNullArray); + + // allocate memory + // nativeParameter = (byte**)CoTaskMemAllocAndZeroMemory((IntPtr)(checked(managedParameter.Length * sizeof(byte*)))); + + // loads the number of elements + EmitElementCount(codeStream, MarshalDirection.Forward); + + TypeDesc nativeElementType = NativeElementType; + codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); + + codeStream.Emit(ILOpcode.mul_ovf); + + codeStream.Emit(ILOpcode.call, emitter.NewToken( + InteropTypes.GetMarshal(Context).GetKnownMethod("AllocCoTaskMem", null))); + StoreNativeValue(codeStream); + + codeStream.EmitLabel(lNullArray); + } + + protected override void TransformManagedToNative(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + var elementType = ManagedElementType; + + var lRangeCheck = emitter.NewCodeLabel(); + var lLoopHeader = emitter.NewCodeLabel(); + var lNullArray = emitter.NewCodeLabel(); + + var vNativeTemp = emitter.NewLocal(NativeType); + var vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); + var vSizeOf = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); + var vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); + + // Check for null array + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNullArray); + + // loads the number of elements + EmitElementCount(codeStream, MarshalDirection.Forward); + codeStream.EmitStLoc(vLength); + + TypeDesc nativeElementType = NativeElementType; + codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); + + codeStream.EmitStLoc(vSizeOf); + + LoadNativeValue(codeStream); + codeStream.EmitStLoc(vNativeTemp); + + codeStream.EmitLdc(0); + codeStream.EmitStLoc(vIndex); + codeStream.Emit(ILOpcode.br, lRangeCheck); + + codeStream.EmitLabel(lLoopHeader); + codeStream.EmitLdLoc(vNativeTemp); + + LoadManagedValue(codeStream); + codeStream.EmitLdLoc(vIndex); + codeStream.EmitLdElem(elementType); + // generate marshalling IL for the element + GetElementMarshaller(MarshalDirection.Forward) + .EmitMarshallingIL(new PInvokeILCodeStreams(_ilCodeStreams.Emitter, codeStream)); + + codeStream.EmitStInd(nativeElementType); + codeStream.EmitLdLoc(vIndex); + codeStream.EmitLdc(1); + codeStream.Emit(ILOpcode.add); + codeStream.EmitStLoc(vIndex); + codeStream.EmitLdLoc(vNativeTemp); + codeStream.EmitLdLoc(vSizeOf); + codeStream.Emit(ILOpcode.add); + codeStream.EmitStLoc(vNativeTemp); + + codeStream.EmitLabel(lRangeCheck); + + codeStream.EmitLdLoc(vIndex); + codeStream.EmitLdLoc(vLength); + codeStream.Emit(ILOpcode.blt, lLoopHeader); + codeStream.EmitLabel(lNullArray); + } + + protected override void TransformNativeToManaged(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + var elementType = ManagedElementType; + var nativeElementType = NativeElementType; + + ILLocalVariable vSizeOf = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); + ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); + + ILCodeLabel lRangeCheck = emitter.NewCodeLabel(); + ILCodeLabel lLoopHeader = emitter.NewCodeLabel(); + var lNullArray = emitter.NewCodeLabel(); + + // Check for null array + if (!IsManagedByRef) + { + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNullArray); + } + + EmitElementCount(codeStream, MarshalDirection.Reverse); + + codeStream.EmitStLoc(vLength); + + if (IsManagedByRef) + { + codeStream.EmitLdLoc(vLength); + codeStream.Emit(ILOpcode.newarr, emitter.NewToken(ManagedElementType)); + StoreManagedValue(codeStream); + } + + codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); + + codeStream.EmitStLoc(vSizeOf); + + var vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); + ILLocalVariable vNativeTemp = emitter.NewLocal(NativeType); + + LoadNativeValue(codeStream); + codeStream.EmitStLoc(vNativeTemp); + codeStream.EmitLdc(0); + codeStream.EmitStLoc(vIndex); + codeStream.Emit(ILOpcode.br, lRangeCheck); + + + codeStream.EmitLabel(lLoopHeader); + + LoadManagedValue(codeStream); + + codeStream.EmitLdLoc(vIndex); + codeStream.EmitLdLoc(vNativeTemp); + + codeStream.EmitLdInd(nativeElementType); + + // generate marshalling IL for the element + GetElementMarshaller(MarshalDirection.Reverse) + .EmitMarshallingIL(new PInvokeILCodeStreams(_ilCodeStreams.Emitter, codeStream)); + + codeStream.EmitStElem(elementType); + + codeStream.EmitLdLoc(vIndex); + codeStream.EmitLdc(1); + codeStream.Emit(ILOpcode.add); + codeStream.EmitStLoc(vIndex); + codeStream.EmitLdLoc(vNativeTemp); + codeStream.EmitLdLoc(vSizeOf); + codeStream.Emit(ILOpcode.add); + codeStream.EmitStLoc(vNativeTemp); + + + codeStream.EmitLabel(lRangeCheck); + codeStream.EmitLdLoc(vIndex); + codeStream.EmitLdLoc(vLength); + codeStream.Emit(ILOpcode.blt, lLoopHeader); + codeStream.EmitLabel(lNullArray); + } + + protected override void AllocNativeToManaged(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + var elementType = ManagedElementType; + EmitElementCount(codeStream, MarshalDirection.Reverse); + codeStream.Emit(ILOpcode.newarr, emitter.NewToken(elementType)); + StoreManagedValue(codeStream); + } + + protected override void EmitCleanupManaged(ILCodeStream codeStream) + { + Marshaller elementMarshaller = GetElementMarshaller(MarshalDirection.Forward); + ILEmitter emitter = _ilCodeStreams.Emitter; + + var lNullArray = emitter.NewCodeLabel(); + + // Check for null array + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNullArray); + + // generate cleanup code only if it is necessary + if (elementMarshaller.CleanupRequired) + { + // + // for (index=0; index< array.length; index++) + // Cleanup(array[i]); + // + var vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); + ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); + + ILCodeLabel lRangeCheck = emitter.NewCodeLabel(); + ILCodeLabel lLoopHeader = emitter.NewCodeLabel(); + ILLocalVariable vSizeOf = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); + + var nativeElementType = NativeElementType; + // calculate sizeof(array[i]) + codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); + + codeStream.EmitStLoc(vSizeOf); + + + // calculate array.length + EmitElementCount(codeStream, MarshalDirection.Forward); + codeStream.EmitStLoc(vLength); + + // load native value + ILLocalVariable vNativeTemp = emitter.NewLocal(NativeType); + LoadNativeValue(codeStream); + codeStream.EmitStLoc(vNativeTemp); + + // index = 0 + codeStream.EmitLdc(0); + codeStream.EmitStLoc(vIndex); + codeStream.Emit(ILOpcode.br, lRangeCheck); + + codeStream.EmitLabel(lLoopHeader); + codeStream.EmitLdLoc(vNativeTemp); + codeStream.EmitLdInd(nativeElementType); + // generate cleanup code for this element + elementMarshaller.EmitElementCleanup(codeStream, emitter); + + codeStream.EmitLdLoc(vIndex); + codeStream.EmitLdc(1); + codeStream.Emit(ILOpcode.add); + codeStream.EmitStLoc(vIndex); + codeStream.EmitLdLoc(vNativeTemp); + codeStream.EmitLdLoc(vSizeOf); + codeStream.Emit(ILOpcode.add); + codeStream.EmitStLoc(vNativeTemp); + + codeStream.EmitLabel(lRangeCheck); + + codeStream.EmitLdLoc(vIndex); + codeStream.EmitLdLoc(vLength); + codeStream.Emit(ILOpcode.blt, lLoopHeader); + } + + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken(InteropTypes.GetMarshal(Context).GetKnownMethod("FreeCoTaskMem", null))); + codeStream.EmitLabel(lNullArray); + } + } + + class BlittableArrayMarshaller : ArrayMarshaller + { + protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeLabel lNullArray = emitter.NewCodeLabel(); + + MethodDesc getRawSzArrayDataMethod = InteropTypes.GetRuntimeHelpers(Context).GetKnownMethod("GetRawSzArrayData", null); + + // Check for null array + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNullArray); + + if (IsManagedByRef) + { + base.AllocManagedToNative(codeStream); + + LoadNativeValue(codeStream); + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken(getRawSzArrayDataMethod)); + EmitElementCount(codeStream, MarshalDirection.Forward); + codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(ManagedElementType)); + codeStream.Emit(ILOpcode.mul_ovf); + codeStream.Emit(ILOpcode.cpblk); + + codeStream.EmitLabel(lNullArray); + } + else + { + ILLocalVariable vPinnedFirstElement = emitter.NewLocal(ManagedElementType.MakeByRefType(), true); + + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.ldlen); + codeStream.Emit(ILOpcode.conv_i4); + codeStream.Emit(ILOpcode.brfalse, lNullArray); + + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken(getRawSzArrayDataMethod)); + codeStream.EmitStLoc(vPinnedFirstElement); + + // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit. + codeStream.EmitLabel(lNullArray); + codeStream.EmitLdLoc(vPinnedFirstElement); + codeStream.Emit(ILOpcode.conv_i); + StoreNativeValue(codeStream); + } + } + + protected override void ReInitNativeTransform(ILCodeStream codeStream) + { + codeStream.EmitLdc(0); + codeStream.Emit(ILOpcode.conv_u); + StoreNativeValue(codeStream); + } + + protected override void TransformNativeToManaged(ILCodeStream codeStream) + { + if (IsManagedByRef || (MarshalDirection == MarshalDirection.Reverse && MarshallerType == MarshallerType.Argument)) + base.TransformNativeToManaged(codeStream); + } + + protected override void EmitCleanupManaged(ILCodeStream codeStream) + { + if (IsManagedByRef) + base.EmitCleanupManaged(codeStream); + } + } + + class BooleanMarshaller : Marshaller + { + protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) + { + LoadManagedValue(codeStream); + codeStream.EmitLdc(0); + codeStream.Emit(ILOpcode.ceq); + codeStream.EmitLdc(0); + codeStream.Emit(ILOpcode.ceq); + StoreNativeValue(codeStream); + } + + protected override void AllocAndTransformNativeToManaged(ILCodeStream codeStream) + { + LoadNativeValue(codeStream); + codeStream.EmitLdc(0); + codeStream.Emit(ILOpcode.ceq); + codeStream.EmitLdc(0); + codeStream.Emit(ILOpcode.ceq); + StoreManagedValue(codeStream); + } + } + + class UnicodeStringMarshaller : Marshaller + { + private bool ShouldBePinned + { + get + { + return MarshalDirection == MarshalDirection.Forward + && MarshallerType != MarshallerType.Field + && !IsManagedByRef + && In + && !Out; + } + } + + internal override bool CleanupRequired + { + get + { + return !ShouldBePinned; //cleanup is only required when it is not pinned + } + } + + internal override void EmitElementCleanup(ILCodeStream codeStream, ILEmitter emitter) + { + codeStream.Emit(ILOpcode.call, emitter.NewToken( + Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); + } + + protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + if (ShouldBePinned) + { + // + // Pin the string and push a pointer to the first character on the stack. + // + TypeDesc stringType = Context.GetWellKnownType(WellKnownType.String); + + ILLocalVariable vPinnedString = emitter.NewLocal(stringType, true); + ILCodeLabel lNullString = emitter.NewCodeLabel(); + + LoadManagedValue(codeStream); + codeStream.EmitStLoc(vPinnedString); + codeStream.EmitLdLoc(vPinnedString); + + codeStream.Emit(ILOpcode.conv_i); + codeStream.Emit(ILOpcode.dup); + + // Marshalling a null string? + codeStream.Emit(ILOpcode.brfalse, lNullString); + + codeStream.Emit(ILOpcode.call, emitter.NewToken( + Context.SystemModule. + GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers"). + GetKnownMethod("get_OffsetToStringData", null))); + + codeStream.Emit(ILOpcode.add); + + codeStream.EmitLabel(lNullString); + StoreNativeValue(codeStream); + } + else + { + var helper = Context.GetHelperEntryPoint("InteropHelpers", "StringToUnicodeBuffer"); + LoadManagedValue(codeStream); + + codeStream.Emit(ILOpcode.call, emitter.NewToken(helper)); + + StoreNativeValue(codeStream); + } + } + + protected override void TransformNativeToManaged(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + var charPtrConstructor = Context.GetWellKnownType(WellKnownType.String).GetMethod(".ctor", + new MethodSignature( + MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.Void), + new TypeDesc[] { + Context.GetWellKnownType(WellKnownType.Char).MakePointerType() } + )); + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.newobj, emitter.NewToken(charPtrConstructor)); + StoreManagedValue(codeStream); + } + + protected override void EmitCleanupManaged(ILCodeStream codeStream) + { + if (CleanupRequired) + { + var emitter = _ilCodeStreams.Emitter; + var lNullCheck = emitter.NewCodeLabel(); + + // Check for null array + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNullCheck); + + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken( + InteropTypes.GetMarshal(Context).GetKnownMethod("FreeCoTaskMem", null))); + + codeStream.EmitLabel(lNullCheck); + } + } + } + + class AnsiStringMarshaller : Marshaller + { + internal override bool CleanupRequired + { + get + { + return true; + } + } + + internal override void EmitElementCleanup(ILCodeStream codeStream, ILEmitter emitter) + { + codeStream.Emit(ILOpcode.call, emitter.NewToken( + Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); + } + + protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + // + // ANSI marshalling. Allocate a byte array, copy characters + // + +#if READYTORUN + var stringToAnsi = + Context.SystemModule.GetKnownType("System.StubHelpers", "AnsiBSTRMarshaler") + .GetKnownMethod("ConvertToNative", null); + int flags = (PInvokeFlags.BestFitMapping ? 0x1 : 0) + | (PInvokeFlags.ThrowOnUnmappableChar ? 0x100 : 0); + codeStream.EmitLdc(flags); + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi)); +#else + LoadManagedValue(codeStream); + var stringToAnsi = Context.GetHelperEntryPoint("InteropHelpers", "StringToAnsiString"); + + codeStream.Emit(PInvokeFlags.BestFitMapping ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0); + codeStream.Emit(PInvokeFlags.ThrowOnUnmappableChar ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0); + + codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi)); +#endif + + StoreNativeValue(codeStream); + } + + protected override void TransformNativeToManaged(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + +#if READYTORUN + var ansiToString = + Context.SystemModule.GetKnownType("System.StubHelpers", "AnsiBSTRMarshaler") + .GetKnownMethod("ConvertToManaged", null); +#else + var ansiToString = Context.GetHelperEntryPoint("InteropHelpers", "AnsiStringToString"); +#endif + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken(ansiToString)); + StoreManagedValue(codeStream); + } + + protected override void EmitCleanupManaged(ILCodeStream codeStream) + { + var emitter = _ilCodeStreams.Emitter; +#if READYTORUN + MethodDesc clearNative = + Context.SystemModule.GetKnownType("System.StubHelpers", "AnsiBSTRMarshaler") + .GetKnownMethod("ClearNative", null); + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken(clearNative)); +#else + var lNullCheck = emitter.NewCodeLabel(); + + // Check for null array + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNullCheck); + + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken( + Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); + + codeStream.EmitLabel(lNullCheck); +#endif + } + } + + class UTF8StringMarshaller : Marshaller + { + internal override bool CleanupRequired + { + get + { + return true; + } + } + + internal override void EmitElementCleanup(ILCodeStream codeStream, ILEmitter emitter) + { + codeStream.Emit(ILOpcode.call, emitter.NewToken( + Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); + } + + protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + + // + // UTF8 marshalling. Allocate a byte array, copy characters + // + var stringToAnsi = Context.GetHelperEntryPoint("InteropHelpers", "StringToUTF8String"); + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi)); + StoreNativeValue(codeStream); + } + + protected override void TransformNativeToManaged(ILCodeStream codeStream) + { + ILEmitter emitter = _ilCodeStreams.Emitter; + var ansiToString = Context.GetHelperEntryPoint("InteropHelpers", "UTF8StringToString"); + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken(ansiToString)); + StoreManagedValue(codeStream); + } + + protected override void EmitCleanupManaged(ILCodeStream codeStream) + { + var emitter = _ilCodeStreams.Emitter; + var lNullCheck = emitter.NewCodeLabel(); + + // Check for null array + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNullCheck); + + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.call, emitter.NewToken( + Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); + + codeStream.EmitLabel(lNullCheck); + } + } + + class SafeHandleMarshaller : Marshaller + { + private void AllocSafeHandle(ILCodeStream codeStream) + { + var ctor = ManagedType.GetParameterlessConstructor(); + if (ctor == null || ((MetadataType)ManagedType).IsAbstract) + { +#if READYTORUN + // Let the runtime generate the proper MissingMemberException for this. + throw new NotSupportedException(); +#else + var emitter = _ilCodeStreams.Emitter; + + MethodSignature ctorSignature = new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), + new TypeDesc[] { + Context.GetWellKnownType(WellKnownType.String) + }); + MethodDesc exceptionCtor = InteropTypes.GetMissingMemberException(Context).GetKnownMethod(".ctor", ctorSignature); + + string name = ((MetadataType)ManagedType).Name; + codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(String.Format("'{0}' does not have a default constructor. Subclasses of SafeHandle must have a default constructor to support marshaling a Windows HANDLE into managed code.", name))); + codeStream.Emit(ILOpcode.newobj, emitter.NewToken(exceptionCtor)); + codeStream.Emit(ILOpcode.throw_); + + return; +#endif + } + + codeStream.Emit(ILOpcode.newobj, _ilCodeStreams.Emitter.NewToken(ctor)); + } + + protected override void EmitMarshalReturnValueManagedToNative() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; + ILCodeStream returnValueMarshallingCodeStream = _ilCodeStreams.ReturnValueMarshallingCodeStream; + + SetupArgumentsForReturnValueMarshalling(); + + AllocSafeHandle(marshallingCodeStream); + StoreManagedValue(marshallingCodeStream); + + StoreNativeValue(returnValueMarshallingCodeStream); + + LoadManagedValue(returnValueMarshallingCodeStream); + LoadNativeValue(returnValueMarshallingCodeStream); + returnValueMarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( + InteropTypes.GetSafeHandle(Context).GetKnownMethod("SetHandle", null))); + } + + protected override void EmitMarshalArgumentManagedToNative() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; + ILCodeStream callsiteCodeStream = _ilCodeStreams.CallsiteSetupCodeStream; + ILCodeStream unmarshallingCodeStream = _ilCodeStreams.UnmarshallingCodestream; + ILCodeStream cleanupCodeStream = _ilCodeStreams.CleanupCodeStream; + + SetupArguments(); + + if (IsManagedByRef && In) + { + PropagateFromByRefArg(marshallingCodeStream, _managedHome); + } + + var safeHandleType = InteropTypes.GetSafeHandle(Context); + + if (In) + { + if (IsManagedByRef) + PropagateFromByRefArg(marshallingCodeStream, _managedHome); + + var vAddRefed = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Boolean)); + LoadManagedValue(marshallingCodeStream); + marshallingCodeStream.EmitLdLoca(vAddRefed); + marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( + safeHandleType.GetKnownMethod("DangerousAddRef", + new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), + new TypeDesc[] { Context.GetWellKnownType(WellKnownType.Boolean).MakeByRefType() })))); + + LoadManagedValue(marshallingCodeStream); + marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( + safeHandleType.GetKnownMethod("DangerousGetHandle", + new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.IntPtr), TypeDesc.EmptyTypes)))); + StoreNativeValue(marshallingCodeStream); + + ILCodeLabel lNotAddrefed = emitter.NewCodeLabel(); + cleanupCodeStream.EmitLdLoc(vAddRefed); + cleanupCodeStream.Emit(ILOpcode.brfalse, lNotAddrefed); + LoadManagedValue(cleanupCodeStream); + cleanupCodeStream.Emit(ILOpcode.call, emitter.NewToken( + safeHandleType.GetKnownMethod("DangerousRelease", + new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), TypeDesc.EmptyTypes)))); + cleanupCodeStream.EmitLabel(lNotAddrefed); + } + + if (Out && IsManagedByRef) + { + // 1) If this is an output parameter we need to preallocate a SafeHandle to wrap the new native handle value. We + // must allocate this before the native call to avoid a failure point when we already have a native resource + // allocated. We must allocate a new SafeHandle even if we have one on input since both input and output native + // handles need to be tracked and released by a SafeHandle. + // 2) Initialize a local IntPtr that will be passed to the native call. + // 3) After the native call, the new handle value is written into the output SafeHandle and that SafeHandle + // is propagated back to the caller. + var vSafeHandle = emitter.NewLocal(ManagedType); + AllocSafeHandle(marshallingCodeStream); + marshallingCodeStream.EmitStLoc(vSafeHandle); + + var lSkipPropagation = emitter.NewCodeLabel(); + if (In) + { + // Propagate the value only if it has changed + ILLocalVariable vOriginalValue = emitter.NewLocal(NativeType); + LoadNativeValue(marshallingCodeStream); + marshallingCodeStream.EmitStLoc(vOriginalValue); + + cleanupCodeStream.EmitLdLoc(vOriginalValue); + LoadNativeValue(cleanupCodeStream); + cleanupCodeStream.Emit(ILOpcode.beq, lSkipPropagation); + } + + cleanupCodeStream.EmitLdLoc(vSafeHandle); + LoadNativeValue(cleanupCodeStream); + cleanupCodeStream.Emit(ILOpcode.call, emitter.NewToken( + safeHandleType.GetKnownMethod("SetHandle", + new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), + new TypeDesc[] { Context.GetWellKnownType(WellKnownType.IntPtr) })))); + + cleanupCodeStream.EmitLdArg(Index - 1); + cleanupCodeStream.EmitLdLoc(vSafeHandle); + cleanupCodeStream.EmitStInd(ManagedType); + + cleanupCodeStream.EmitLabel(lSkipPropagation); + } + + LoadNativeArg(callsiteCodeStream); + } + + protected override void EmitMarshalArgumentNativeToManaged() + { + throw new NotSupportedException(); + } + + protected override void EmitMarshalElementNativeToManaged() + { + throw new NotSupportedException(); + } + + protected override void EmitMarshalElementManagedToNative() + { + throw new NotSupportedException(); + } + + protected override void EmitMarshalFieldManagedToNative() + { + throw new NotSupportedException(); + } + + protected override void EmitMarshalFieldNativeToManaged() + { + throw new NotSupportedException(); + } + } + + class DelegateMarshaller : Marshaller + { + protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) + { + LoadManagedValue(codeStream); + + codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken( + InteropTypes.GetMarshal(Context).GetKnownMethod("GetFunctionPointerForDelegate", + new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.IntPtr), + new TypeDesc[] { Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType } + )))); + + StoreNativeValue(codeStream); + } + + protected override void TransformNativeToManaged(ILCodeStream codeStream) + { + LoadNativeValue(codeStream); + + TypeDesc systemType = Context.SystemModule.GetKnownType("System", "Type"); + + codeStream.Emit(ILOpcode.ldtoken, _ilCodeStreams.Emitter.NewToken(ManagedType)); + codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(systemType.GetKnownMethod("GetTypeFromHandle", null))); + + codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken( + InteropTypes.GetMarshal(Context).GetKnownMethod("GetDelegateForFunctionPointer", + new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType, + new TypeDesc[] { Context.GetWellKnownType(WellKnownType.IntPtr), systemType } + )))); + + StoreManagedValue(codeStream); + } + + protected override void EmitCleanupManaged(ILCodeStream codeStream) + { + if (In + && MarshalDirection == MarshalDirection.Forward + && MarshallerType == MarshallerType.Argument) + { + LoadManagedValue(codeStream); + codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(InteropTypes.GetGC(Context).GetKnownMethod("KeepAlive", null))); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/InstantiatedType.Interop.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/InstantiatedType.Interop.cs new file mode 100644 index 00000000000..4f9cbad960e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/InstantiatedType.Interop.cs @@ -0,0 +1,17 @@ +// 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 +{ + public partial class InstantiatedType + { + public override PInvokeStringFormat PInvokeStringFormat + { + get + { + return _typeDef.PInvokeStringFormat; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/InteropTypes.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/InteropTypes.cs new file mode 100644 index 00000000000..3e7d8156e3d --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/InteropTypes.cs @@ -0,0 +1,152 @@ +// 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 Internal.IL; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem.Interop +{ + public static class InteropTypes + { + public static MetadataType GetGC(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System", "GC"); + } + + public static MetadataType GetSafeHandle(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "SafeHandle"); + } + + public static MetadataType GetCriticalHandle(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "CriticalHandle"); + } + + public static MetadataType GetHandleRef(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "HandleRef"); + } + + public static MetadataType GetMissingMemberException(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System", "MissingMemberException"); + } + + public static MetadataType GetPInvokeMarshal(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "PInvokeMarshal"); + } + + public static MetadataType GetMarshal(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "Marshal"); + } + + public static MetadataType GetRuntimeHelpers(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers"); + } + + public static MetadataType GetStubHelpers(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.StubHelpers", "StubHelpers"); + } + + public static MetadataType GetNativeFunctionPointerWrapper(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "NativeFunctionPointerWrapper"); + } + + public static bool IsSafeHandle(TypeSystemContext context, TypeDesc type) + { + return IsOrDerivesFromType(type, GetSafeHandle(context)); + } + + public static bool IsCriticalHandle(TypeSystemContext context, TypeDesc type) + { + return IsOrDerivesFromType(type, GetCriticalHandle(context)); + } + + private static bool IsCoreNamedType(TypeSystemContext context, TypeDesc type, string @namespace, string name) + { + return type is MetadataType mdType && + mdType.Name == name && + mdType.Namespace == @namespace && + mdType.Module == context.SystemModule; + } + + public static bool IsHandleRef(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System.Runtime.InteropServices", "HandleRef"); + } + + public static bool IsSystemDateTime(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System", "DateTime"); + } + + public static bool IsStringBuilder(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System.Text", "StringBuilder"); + } + + public static bool IsSystemDecimal(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System", "Decimal"); + } + + public static bool IsSystemGuid(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System", "Guid"); + } + + public static bool IsSystemArgIterator(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System", "ArgIterator"); + } + + public static bool IsSystemByReference(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System", "ByReference`1"); + } + + public static bool IsSystemNullable(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System", "Nullable`1"); + } + + public static bool IsSystemRuntimeIntrinsicsVector64T(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector64`1"); + } + + public static bool IsSystemRuntimeIntrinsicsVector128T(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector128`1"); + } + + public static bool IsSystemRuntimeIntrinsicsVector256T(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector256`1"); + } + + public static bool IsSystemNumericsVectorT(TypeSystemContext context, TypeDesc type) + { + return IsCoreNamedType(context, type, "System.Numerics", "Vector`1"); + } + + private static bool IsOrDerivesFromType(TypeDesc type, MetadataType targetType) + { + while (type != null) + { + if (type == targetType) + return true; + type = type.BaseType; + } + return false; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/MarshalAsDescriptor.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/MarshalAsDescriptor.cs new file mode 100644 index 00000000000..2131581d4fe --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/MarshalAsDescriptor.cs @@ -0,0 +1,59 @@ +// 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.Runtime.CompilerServices; +using System; + +namespace Internal.TypeSystem +{ + public enum NativeTypeKind : byte + { + Boolean = 0x2, + I1 = 0x3, + U1 = 0x4, + I2 = 0x5, + U2 = 0x6, + I4 = 0x7, + U4 = 0x8, + I8 = 0x9, + U8 = 0xa, + R4 = 0xb, + R8 = 0xc, + LPStr = 0x14, + LPWStr = 0x15, + LPTStr = 0x16, // Ptr to OS preferred (SBCS/Unicode) string + ByValTStr = 0x17, // OS preferred (SBCS/Unicode) inline string (only valid in structs) + Struct = 0x1b, + SafeArray = 0x1d, + ByValArray = 0x1e, + SysInt = 0x1f, + SysUInt = 0x20, + Int = 0x1f, + UInt = 0x20, + Func = 0x26, + AsAny = 0x28, + Array = 0x2a, + LPStruct = 0x2b, // This is not defined in Ecma-335(II.23.4) + CustomMarshaler = 0x2c, + LPUTF8Str = 0x30, + Default = 0x50, // This is the default value + Variant = 0x51, + } + + public class MarshalAsDescriptor + { + public NativeTypeKind Type { get; } + public NativeTypeKind ArraySubType { get; } + public uint? SizeParamIndex { get; } + public uint? SizeConst { get; } + + public MarshalAsDescriptor(NativeTypeKind type, NativeTypeKind arraySubType, uint? sizeParamIndex, uint? sizeConst) + { + Type = type; + ArraySubType = arraySubType; + SizeParamIndex = sizeParamIndex; + SizeConst = sizeConst; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/MetadataType.Interop.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/MetadataType.Interop.cs new file mode 100644 index 00000000000..3f586dcb3f5 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/MetadataType.Interop.cs @@ -0,0 +1,37 @@ +// 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; + +namespace Internal.TypeSystem +{ + public enum PInvokeStringFormat + { + /// + /// LPTSTR is interpreted as ANSI in this class. + /// + AnsiClass = 0x00000000, + + /// + /// LPTSTR is interpreted as UNICODE. + /// + UnicodeClass = 0x00010000, + + /// + /// LPTSTR is interpreted automatically. + /// + AutoClass = 0x00020000, + } + + public partial class MetadataType + { + /// + /// Gets a value indicating how strings should be handled for native interop. + /// + public abstract PInvokeStringFormat PInvokeStringFormat + { + get; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/MethodDelegator.Interop.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/MethodDelegator.Interop.cs new file mode 100644 index 00000000000..73c11109d24 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/MethodDelegator.Interop.cs @@ -0,0 +1,21 @@ +// 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 +{ + partial class MethodDelegator + { + public override bool IsPInvoke => _wrappedMethod.IsPInvoke; + + public override PInvokeMetadata GetPInvokeMethodMetadata() + { + return _wrappedMethod.GetPInvokeMethodMetadata(); + } + + public override ParameterMetadata[] GetParameterMetadata() + { + return _wrappedMethod.GetParameterMetadata(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/MethodDesc.Interop.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/MethodDesc.Interop.cs new file mode 100644 index 00000000000..d496dcf0d1a --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/MethodDesc.Interop.cs @@ -0,0 +1,370 @@ +// 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.Runtime.InteropServices; + +namespace Internal.TypeSystem +{ + // Additional extensions to MethodDesc related to interop + partial class MethodDesc + { + /// + /// Gets a value indicating whether this method is a (native unmanaged) platform invoke. + /// Use to retrieve the platform invoke detail information. + /// + public virtual bool IsPInvoke + { + get + { + return false; + } + } + + /// + /// If is true, retrieves the metadata related to the platform invoke. + /// + public virtual PInvokeMetadata GetPInvokeMethodMetadata() + { + return default(PInvokeMetadata); + } + + /// + /// Retrieves the metadata related to the parameters of the method. + /// + public virtual ParameterMetadata[] GetParameterMetadata() + { + return Array.Empty(); + } + } + + [Flags] + public enum ParameterMetadataAttributes + { + None = 0, + In = 1, + Out = 2, + Optional = 16, + HasDefault = 4096, + HasFieldMarshal = 8192 + } + + public struct ParameterMetadata + { + private readonly ParameterMetadataAttributes _attributes; + public readonly MarshalAsDescriptor MarshalAsDescriptor; + + /// + /// Gets a 1-based index of the parameter within the signature the metadata refers to. + /// Index 0 is the return value. + /// + public readonly int Index; + + public bool In { get { return (_attributes & ParameterMetadataAttributes.In) == ParameterMetadataAttributes.In; } } + public bool Out { get { return (_attributes & ParameterMetadataAttributes.Out) == ParameterMetadataAttributes.Out; } } + public bool Return { get { return Index == 0; } } + public bool Optional { get { return (_attributes & ParameterMetadataAttributes.Optional) == ParameterMetadataAttributes.Optional; } } + public bool HasDefault { get { return (_attributes & ParameterMetadataAttributes.HasDefault) == ParameterMetadataAttributes.HasDefault; } } + public bool HasFieldMarshal { get { return (_attributes & ParameterMetadataAttributes.HasFieldMarshal) == ParameterMetadataAttributes.HasFieldMarshal; } } + + + public ParameterMetadata(int index, ParameterMetadataAttributes attributes, MarshalAsDescriptor marshalAsDescriptor) + { + Index = index; + _attributes = attributes; + MarshalAsDescriptor = marshalAsDescriptor; + } + } + + [Flags] + public enum PInvokeAttributes + { + // These should match System.Reflection.MethodImportAttributes + None = 0, + ExactSpelling = 1, + CharSetAnsi = 2, + CharSetUnicode = 4, + CharSetAuto = 6, + CharSetMask = 6, + BestFitMappingEnable = 16, + BestFitMappingDisable = 32, + BestFitMappingMask = 48, + SetLastError = 64, + CallingConventionWinApi = 256, + CallingConventionCDecl = 512, + CallingConventionStdCall = 768, + CallingConventionThisCall = 1024, + CallingConventionFastCall = 1280, + CallingConventionMask = 1792, + ThrowOnUnmappableCharEnable = 4096, + ThrowOnUnmappableCharDisable = 8192, + ThrowOnUnmappableCharMask = 12288, + + // Not actually part of MethodImportAttributes. + // MethodImportAttributes is limited to `short`. This enum is based on int + // and we have 16 spare bytes. + PreserveSig = 0x10000, + } + + public struct PInvokeFlags : IEquatable, IComparable + { + private PInvokeAttributes _attributes; + public PInvokeAttributes Attributes + { + get + { + return _attributes; + } + } + + public PInvokeFlags(PInvokeAttributes attributes) + { + _attributes = attributes; + } + + public CharSet CharSet + { + get + { + PInvokeAttributes mask = _attributes & PInvokeAttributes.CharSetMask; + + // ECMA-335 II.10.1.5 - Default value is Ansi. + CharSet charset = CharSet.Ansi; + + if (mask == PInvokeAttributes.CharSetUnicode || mask == PInvokeAttributes.CharSetAuto) + { + charset = CharSet.Unicode; + } + return charset; + } + + set + { + // clear the charset bits; + _attributes &= ~(PInvokeAttributes.CharSetMask); + if (value == CharSet.Unicode || (short)value == 4) // CharSet.Auto has value 4, but not in the enum + { + _attributes |= PInvokeAttributes.CharSetUnicode; + } + else + { + _attributes |= PInvokeAttributes.CharSetAnsi; + } + } + } + + public MethodSignatureFlags UnmanagedCallingConvention + { + get + { + switch (_attributes & PInvokeAttributes.CallingConventionMask) + { + case PInvokeAttributes.CallingConventionWinApi: + return MethodSignatureFlags.UnmanagedCallingConventionStdCall; // TODO: CDecl for varargs + case PInvokeAttributes.CallingConventionCDecl: + return MethodSignatureFlags.UnmanagedCallingConventionCdecl; + case PInvokeAttributes.CallingConventionStdCall: + return MethodSignatureFlags.UnmanagedCallingConventionStdCall; + case PInvokeAttributes.CallingConventionThisCall: + return MethodSignatureFlags.UnmanagedCallingConventionThisCall; + case PInvokeAttributes.None: + return MethodSignatureFlags.None; + default: + throw new BadImageFormatException(); + } + } + set + { + _attributes &= ~(PInvokeAttributes.CallingConventionMask); + switch (value) + { + + case MethodSignatureFlags.UnmanagedCallingConventionStdCall: + _attributes |= PInvokeAttributes.CallingConventionStdCall; + break; + case MethodSignatureFlags.UnmanagedCallingConventionCdecl: + _attributes |= PInvokeAttributes.CallingConventionCDecl; + break; + case MethodSignatureFlags.UnmanagedCallingConventionThisCall: + _attributes |= PInvokeAttributes.CallingConventionThisCall; + break; + default: + System.Diagnostics.Debug.Fail("Unexpected Unmanaged Calling Convention."); + break; + } + } + } + + public bool SetLastError + { + get + { + return (_attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError; + } + set + { + if (value) + { + _attributes |= PInvokeAttributes.SetLastError; + } + else + { + _attributes &= ~(PInvokeAttributes.SetLastError); + } + } + } + + public bool ExactSpelling + { + get + { + return (_attributes & PInvokeAttributes.ExactSpelling) == PInvokeAttributes.ExactSpelling; + } + set + { + if (value) + { + _attributes |= PInvokeAttributes.ExactSpelling; + } + else + { + _attributes &= ~(PInvokeAttributes.ExactSpelling); + } + } + } + + public bool BestFitMapping + { + get + { + PInvokeAttributes mask = _attributes & PInvokeAttributes.BestFitMappingMask; + if (mask == PInvokeAttributes.BestFitMappingDisable) + { + return false; + } + // default value is true + return true; + } + set + { + _attributes &= ~(PInvokeAttributes.BestFitMappingMask); + if (value) + { + _attributes |= PInvokeAttributes.BestFitMappingEnable; + } + else + { + _attributes |= PInvokeAttributes.BestFitMappingDisable; + } + } + } + + public bool ThrowOnUnmappableChar + { + get + { + PInvokeAttributes mask = _attributes & PInvokeAttributes.ThrowOnUnmappableCharMask; + if (mask == PInvokeAttributes.ThrowOnUnmappableCharEnable) + { + return true; + } + // default value is false + return false; + } + set + { + _attributes &= ~(PInvokeAttributes.ThrowOnUnmappableCharMask); + if (value) + { + _attributes |= PInvokeAttributes.ThrowOnUnmappableCharEnable; + } + else + { + _attributes |= PInvokeAttributes.ThrowOnUnmappableCharDisable; + } + } + } + + public bool PreserveSig + { + get + { + return (_attributes & PInvokeAttributes.PreserveSig) != 0; + } + set + { + if (value) + { + _attributes |= PInvokeAttributes.PreserveSig; + } + else + { + _attributes &= ~PInvokeAttributes.PreserveSig; + } + } + } + + public int CompareTo(PInvokeFlags other) + { + return Attributes.CompareTo(other.Attributes); + } + + public bool Equals(PInvokeFlags other) + { + return Attributes == other.Attributes; + } + + public override bool Equals(object obj) + { + return obj is PInvokeFlags other && Equals(other); + } + + public override int GetHashCode() + { + return Attributes.GetHashCode(); + } + } + + /// + /// Represents details about a pinvokeimpl method import. + /// + public struct PInvokeMetadata + { + public readonly string Name; + + public readonly string Module; + + public readonly PInvokeFlags Flags; + + public PInvokeMetadata(string module, string entrypoint, PInvokeAttributes attributes) + { + Name = entrypoint; + Module = module; + Flags = new PInvokeFlags(attributes); + } + + public PInvokeMetadata(string module, string entrypoint, PInvokeFlags flags) + { + Name = entrypoint; + Module = module; + Flags = flags; + } + } + + partial class InstantiatedMethod + { + public override ParameterMetadata[] GetParameterMetadata() + { + return _methodDef.GetParameterMetadata(); + } + } + + partial class MethodForInstantiatedType + { + public override ParameterMetadata[] GetParameterMetadata() + { + return _typicalMethodDef.GetParameterMetadata(); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledMethod.cs b/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledMethod.cs new file mode 100644 index 00000000000..7e06aa83d26 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledMethod.cs @@ -0,0 +1,23 @@ +// 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 +{ + /// + /// When implemented by a or , instructs a name mangler to use the same mangled name + /// as another entity while prepending a specific prefix to that mangled name. + /// + public interface IPrefixMangledMethod + { + /// + /// Method whose mangled name to use. + /// + MethodDesc BaseMethod { get; } + + /// + /// Prefix to apply when mangling. + /// + string Prefix { get; } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledSignature.cs b/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledSignature.cs new file mode 100644 index 00000000000..3dabbc53a67 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledSignature.cs @@ -0,0 +1,23 @@ +// 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 +{ + /// + /// When implemented by a , instructs a name mangler to use the same mangled name + /// as another entity while prepending a specific prefix to that mangled name. + /// + public interface IPrefixMangledSignature + { + /// + /// Signature whose mangled name to use. + /// + MethodSignature BaseSignature { get; } + + /// + /// Prefix to apply when mangling. + /// + string Prefix { get; } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledType.cs b/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledType.cs new file mode 100644 index 00000000000..8ea628abdc1 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Mangling/IPrefixMangledType.cs @@ -0,0 +1,23 @@ +// 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 +{ + /// + /// When implemented by a or , instructs a name mangler to use the same mangled name + /// as another entity while prepending a specific prefix to that mangled name. + /// + public interface IPrefixMangledType + { + /// + /// Type whose mangled name to use. + /// + TypeDesc BaseType { get; } + + /// + /// Prefix to apply when mangling. + /// + string Prefix { get; } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ArrayType.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ArrayType.RuntimeDetermined.cs new file mode 100644 index 00000000000..08983940ffa --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ArrayType.RuntimeDetermined.cs @@ -0,0 +1,34 @@ +// 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 +{ + partial class ArrayType + { + public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc parameterTypeConverted = ParameterType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); + if (ParameterType != parameterTypeConverted) + { + return Context.GetArrayType(parameterTypeConverted, _rank); + } + + return this; + } + } + + partial class ArrayMethod + { + public override MethodDesc GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc owningType = this.OwningType; + TypeDesc instantiatedOwningType = owningType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); + + if (owningType != instantiatedOwningType) + return ((ArrayType)instantiatedOwningType).GetArrayMethod(_kind); + else + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ByRefType.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ByRefType.RuntimeDetermined.cs new file mode 100644 index 00000000000..a10a9c8e5e7 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ByRefType.RuntimeDetermined.cs @@ -0,0 +1,20 @@ +// 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 +{ + partial class ByRefType + { + public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc parameterTypeConverted = ParameterType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); + if (ParameterType != parameterTypeConverted) + { + return Context.GetByRefType(parameterTypeConverted); + } + + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs new file mode 100644 index 00000000000..02d1b252339 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs @@ -0,0 +1,87 @@ +// 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 +{ + partial class DefType + { + public override bool IsRuntimeDeterminedSubtype + { + get + { + // Handles situation when shared code refers to uninstantiated generic + // type definitions (think: LDTOKEN). + // Walking the instantiation would make us assert. This is simply + // not a runtime determined type. + if (IsGenericDefinition) + return false; + + foreach (TypeDesc type in Instantiation) + { + if (type.IsRuntimeDeterminedSubtype) + return true; + } + return false; + } + } + + /// + /// Converts the type to the shared runtime determined form where the types this type is instantiatied + /// over become bound to the generic parameters of this type. + /// + public DefType ConvertToSharedRuntimeDeterminedForm() + { + Instantiation instantiation = Instantiation; + if (instantiation.Length > 0) + { + MetadataType typeDefinition = (MetadataType)GetTypeDefinition(); + + bool changed; + Instantiation sharedInstantiation = RuntimeDeterminedTypeUtilities.ConvertInstantiationToSharedRuntimeForm( + instantiation, typeDefinition.Instantiation, out changed); + if (changed) + { + return Context.GetInstantiatedType(typeDefinition, sharedInstantiation); + } + } + + return this; + } + + public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc typeDefinition = GetTypeDefinition(); + if (this == typeDefinition) + return this; + + Instantiation instantiation = Instantiation; + TypeDesc[] clone = null; + + for (int i = 0; i < instantiation.Length; i++) + { + TypeDesc uninst = instantiation[i]; + TypeDesc inst = uninst.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); + if (inst != uninst) + { + if (clone == null) + { + clone = new TypeDesc[instantiation.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = instantiation[j]; + } + } + clone[i] = inst; + } + } + + if (clone != null) + { + return Context.GetInstantiatedType((MetadataType)typeDefinition, new Instantiation(clone)); + } + + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/FieldDesc.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/FieldDesc.RuntimeDetermined.cs new file mode 100644 index 00000000000..c3bd99565e8 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/FieldDesc.RuntimeDetermined.cs @@ -0,0 +1,21 @@ +// 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 +{ + partial class FieldDesc + { + public FieldDesc GetNonRuntimeDeterminedFieldFromRuntimeDeterminedFieldViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + DefType owningType = OwningType; + TypeDesc owningTypeInstantiated = owningType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); + if (owningTypeInstantiated != owningType) + { + return Context.GetFieldForInstantiatedType(GetTypicalFieldDefinition(), (InstantiatedType)owningTypeInstantiated); + } + + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/FunctionPointerType.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/FunctionPointerType.RuntimeDetermined.cs new file mode 100644 index 00000000000..3ad0e6e701f --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/FunctionPointerType.RuntimeDetermined.cs @@ -0,0 +1,32 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + partial class FunctionPointerType + { + public override bool IsRuntimeDeterminedSubtype + { + get + { + if (_signature.ReturnType.IsRuntimeDeterminedSubtype) + return true; + + for (int i = 0; i < _signature.Length; i++) + if (_signature[i].IsRuntimeDeterminedSubtype) + return true; + + return false; + } + } + + public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + Debug.Assert(false); + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/GenericParameterDesc.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/GenericParameterDesc.RuntimeDetermined.cs new file mode 100644 index 00000000000..79b2b7b429e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/GenericParameterDesc.RuntimeDetermined.cs @@ -0,0 +1,26 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + partial class GenericParameterDesc + { + public sealed override bool IsRuntimeDeterminedSubtype + { + get + { + Debug.Fail("IsRuntimeDeterminedSubtype of an indefinite type"); + return false; + } + } + + public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + Debug.Assert(false); + return this; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs new file mode 100644 index 00000000000..8fd47116dd9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs @@ -0,0 +1,141 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + partial class MethodDesc + { + /// + /// Gets the shared runtime determined form of the method. This is a canonical form of the method + /// where generic arguments of the method and the owning type have been converted to runtime determined types. + /// + public MethodDesc GetSharedRuntimeFormMethodTarget() + { + MethodDesc result = this; + + DefType owningType = OwningType as DefType; + if (owningType != null) + { + // First find the method on the shared runtime form of the owning type + DefType sharedRuntimeOwningType = owningType.ConvertToSharedRuntimeDeterminedForm(); + if (sharedRuntimeOwningType != owningType) + { + result = Context.GetMethodForInstantiatedType( + GetTypicalMethodDefinition(), (InstantiatedType)sharedRuntimeOwningType); + } + + // Now convert the method instantiation to the shared runtime form + if (result.HasInstantiation) + { + MethodDesc uninstantiatedMethod = result.GetMethodDefinition(); + + bool changed; + Instantiation sharedInstantiation = RuntimeDeterminedTypeUtilities.ConvertInstantiationToSharedRuntimeForm( + Instantiation, uninstantiatedMethod.Instantiation, out changed); + + // If either the instantiation changed, or we switched the owning type, we need to find the matching + // instantiated method. + if (changed || result != this) + { + result = Context.GetInstantiatedMethod(uninstantiatedMethod, sharedInstantiation); + } + } + } + + return result; + } + + /// + /// Gets the type which holds the implementation of this method. This is typically the owning method, + /// unless this method models a target of a constrained method call. + /// + public TypeDesc ImplementationType + { + get + { + // TODO: IsConstrainedMethod + return OwningType; + } + } + + /// + /// Gets a value indicating whether this is a shared method body. + /// + public bool IsSharedByGenericInstantiations + { + get + { + return IsCanonicalMethod(CanonicalFormKind.Any); + } + } + + /// + /// Gets a value indicating whether this is a canonical method that will only become concrete + /// at runtime (after supplying the generic context). + /// + public bool IsRuntimeDeterminedExactMethod + { + get + { + TypeDesc containingType = ImplementationType; + if (containingType.IsRuntimeDeterminedSubtype) + return true; + + // Handles situation when shared code refers to uninstantiated generic + // method definitions (think: LDTOKEN). + // Walking the instantiation would make us assert. This is simply + // not a runtime determined method. + if (IsGenericMethodDefinition) + return false; + + foreach (TypeDesc typeArg in Instantiation) + { + if (typeArg.IsRuntimeDeterminedSubtype) + return true; + } + + return false; + } + } + + public virtual MethodDesc GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + Instantiation instantiation = Instantiation; + TypeDesc[] clone = null; + + for (int i = 0; i < instantiation.Length; i++) + { + TypeDesc uninst = instantiation[i]; + TypeDesc inst = uninst.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); + if (inst != uninst) + { + if (clone == null) + { + clone = new TypeDesc[instantiation.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = instantiation[j]; + } + } + clone[i] = inst; + } + } + + MethodDesc method = this; + + TypeDesc owningType = method.OwningType; + TypeDesc instantiatedOwningType = owningType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); + if (owningType != instantiatedOwningType) + { + method = Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType); + if (clone == null && instantiation.Length != 0) + return Context.GetInstantiatedMethod(method, instantiation); + } + + return (clone == null) ? method : Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone)); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.cs new file mode 100644 index 00000000000..3aa3b441fd6 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.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 +{ + partial class MethodForRuntimeDeterminedType + { + public override string DiagnosticName => _typicalMethodDef.DiagnosticName; + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Sorting.cs new file mode 100644 index 00000000000..dd318b30ce9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Sorting.cs @@ -0,0 +1,23 @@ +// 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 +{ + // Functionality related to deterministic ordering of types + partial class MethodForRuntimeDeterminedType + { + protected internal override int ClassCode => 719937490; + + protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) + { + var otherMethod = (MethodForRuntimeDeterminedType)other; + + int result = comparer.CompareWithinClass(_rdType, otherMethod._rdType); + if (result != 0) + return result; + + return comparer.Compare(_typicalMethodDef, otherMethod._typicalMethodDef); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs new file mode 100644 index 00000000000..2ae3380ad12 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs @@ -0,0 +1,62 @@ +// 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; + +namespace Internal.TypeSystem +{ + public sealed partial class MethodForRuntimeDeterminedType : MethodDesc + { + private MethodDesc _typicalMethodDef; + private RuntimeDeterminedType _rdType; + + internal MethodForRuntimeDeterminedType(MethodDesc typicalMethodDef, RuntimeDeterminedType rdType) + { + Debug.Assert(typicalMethodDef.IsTypicalMethodDefinition); + + _typicalMethodDef = typicalMethodDef; + _rdType = rdType; + } + + // This constructor is a performance optimization - it allows supplying the hash code if it has already + // been computed prior to the allocation of this type. The supplied hash code still has to match the + // hash code this type would compute on it's own (and we assert to enforce that). + internal MethodForRuntimeDeterminedType(MethodDesc typicalMethodDef, RuntimeDeterminedType rdType, int hashcode) + : this(typicalMethodDef, rdType) + { + SetHashCode(hashcode); + } + + public override TypeSystemContext Context => _typicalMethodDef.Context; + public override TypeDesc OwningType => _rdType; + public override MethodSignature Signature => _typicalMethodDef.Signature; + public override bool IsVirtual => _typicalMethodDef.IsVirtual; + public override bool IsNewSlot => _typicalMethodDef.IsNewSlot; + public override bool IsAbstract => _typicalMethodDef.IsAbstract; + public override bool IsFinal => _typicalMethodDef.IsFinal; + public override bool IsDefaultConstructor => _typicalMethodDef.IsDefaultConstructor; + public override string Name => _typicalMethodDef.Name; + public override MethodDesc GetTypicalMethodDefinition() => _typicalMethodDef; + public override Instantiation Instantiation => _typicalMethodDef.Instantiation; + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) + { + return _typicalMethodDef.HasCustomAttribute(attributeNamespace, attributeName); + } + + public override bool IsCanonicalMethod(CanonicalFormKind policy) + { + // Owning type is a RuntimeDeterminedType, so it can never be canonical. + // Instantiation for the method can also never be canonical since it's a typical method definition. + return false; + } + + public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) + { + TypeDesc canonicalizedTypeOfTargetMethod = _rdType.CanonicalType.ConvertToCanonForm(kind); + return Context.GetMethodForInstantiatedType(_typicalMethodDef, (InstantiatedType)canonicalizedTypeOfTargetMethod); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ParameterizedType.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ParameterizedType.RuntimeDetermined.cs new file mode 100644 index 00000000000..f48325c7ebd --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/ParameterizedType.RuntimeDetermined.cs @@ -0,0 +1,17 @@ +// 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 +{ + partial class ParameterizedType + { + public sealed override bool IsRuntimeDeterminedSubtype + { + get + { + return _parameterType.IsRuntimeDeterminedSubtype; + } + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/PointerType.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/PointerType.RuntimeDetermined.cs new file mode 100644 index 00000000000..f3ef66f3712 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/PointerType.RuntimeDetermined.cs @@ -0,0 +1,20 @@ +// 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 +{ + partial class PointerType + { + public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc parameterTypeConverted = ParameterType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); + if (ParameterType != parameterTypeConverted) + { + return Context.GetPointerType(parameterTypeConverted); + } + + return this; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedCanonicalizationAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedCanonicalizationAlgorithm.cs new file mode 100644 index 00000000000..f1ea5fc96b0 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedCanonicalizationAlgorithm.cs @@ -0,0 +1,151 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Contains utility functionality for canonicalization used by multiple types. + /// This implementation can handle runtime determined types and the various fallouts from using them + /// (e.g. the ability to upgrade to + /// if somewhere within the construction of the type we encounter a universal form). + /// + public static class RuntimeDeterminedCanonicalizationAlgorithm + { + public static Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) + { + TypeDesc[] canonInstantiation = null; + + CanonicalFormKind currentKind = kind; + CanonicalFormKind startLoopKind; + + // This logic is wrapped in a loop because we might potentially need to restart canonicalization if the policy + // changes due to one of the instantiation arguments already being universally canonical. + do + { + startLoopKind = currentKind; + + for (int instantiationIndex = 0; instantiationIndex < instantiation.Length; instantiationIndex++) + { + TypeDesc typeToConvert = instantiation[instantiationIndex]; + TypeDesc canonForm = ConvertToCanon(typeToConvert, ref currentKind); + if (typeToConvert != canonForm || canonInstantiation != null) + { + if (canonInstantiation == null) + { + canonInstantiation = new TypeDesc[instantiation.Length]; + for (int i = 0; i < instantiationIndex; i++) + canonInstantiation[i] = instantiation[i]; + } + + canonInstantiation[instantiationIndex] = canonForm; + } + } + + // Optimization: even if canonical policy changed, we don't actually need to re-run the loop + // for instantiations that only have a single element. + if (instantiation.Length == 1) + { + break; + } + + } while (currentKind != startLoopKind); + + + changed = canonInstantiation != null; + if (changed) + { + return new Instantiation(canonInstantiation); + } + + return instantiation; + } + + public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) + { + // Wrap the call to the version that potentially modifies the parameter. External + // callers are not interested in that. + return ConvertToCanon(typeToConvert, ref kind); + } + + public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) + { + TypeSystemContext context = typeToConvert.Context; + if (kind == CanonicalFormKind.Universal) + { + return context.UniversalCanonType; + } + else if (kind == CanonicalFormKind.Specific) + { + if (typeToConvert == context.UniversalCanonType) + { + kind = CanonicalFormKind.Universal; + return context.UniversalCanonType; + } + else if (typeToConvert.IsSignatureVariable) + { + return typeToConvert; + } + else if (typeToConvert.IsDefType) + { + if (!typeToConvert.IsValueType) + { + return context.CanonType; + } + else if (typeToConvert.HasInstantiation) + { + TypeDesc canonicalType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); + + // This is a generic struct type. If the generic struct is instantiated over universal canon, + // the entire struct becomes universally canonical. + if (canonicalType.IsCanonicalSubtype(CanonicalFormKind.Universal)) + { + kind = CanonicalFormKind.Universal; + return context.UniversalCanonType; + } + + return canonicalType; + } + else if (typeToConvert.IsRuntimeDeterminedType) + { + // For non-universal canon cases, RuntimeDeterminedType's passed into this function are either + // reference types (which are turned into normal Canon), or instantiated types (which are handled + // by the above case.). But for UniversalCanon, we can have non-instantiated universal canon + // which will reach this case. + + // We should only ever reach this for T__UniversalCanon. + Debug.Assert(((RuntimeDeterminedType)typeToConvert).CanonicalType == context.UniversalCanonType); + + kind = CanonicalFormKind.Universal; + return context.UniversalCanonType; + } + else + { + return typeToConvert; + } + } + else if (typeToConvert.IsArray) + { + return context.CanonType; + } + else + { + if (typeToConvert.IsCanonicalSubtype(CanonicalFormKind.Universal)) + { + kind = CanonicalFormKind.Universal; + return context.UniversalCanonType; + } + + return typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); + } + } + else + { + Debug.Assert(false); + return null; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs new file mode 100644 index 00000000000..75039d735b2 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs @@ -0,0 +1,70 @@ +// 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.Collections.Generic; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// RuntimeDeterminedFieldLayoutAlgorithm algorithm which can be used to compute field layout + /// for any RuntimeDeterminedType + /// Only useable for accessing the instance field size + /// + public class RuntimeDeterminedFieldLayoutAlgorithm : FieldLayoutAlgorithm + { + public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind) + { + // Individual field offset layout for a RuntimeDeterminedType is not a supported operation + if (layoutKind != InstanceLayoutKind.TypeOnly) + throw new NotSupportedException(); + + RuntimeDeterminedType type = (RuntimeDeterminedType)defType; + DefType canonicalType = type.CanonicalType; + + ComputedInstanceFieldLayout result = new ComputedInstanceFieldLayout + { + ByteCountUnaligned = canonicalType.InstanceByteCountUnaligned, + ByteCountAlignment = canonicalType.InstanceByteAlignment, + FieldAlignment = canonicalType.InstanceFieldAlignment, + FieldSize = canonicalType.InstanceFieldSize, + Offsets = Array.Empty() + }; + + return result; + } + + public unsafe override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind) + { + // Static field layout for a RuntimeDeterminedType is not a supported operation + throw new NotSupportedException(); + } + + public override bool ComputeContainsGCPointers(DefType type) + { + RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type; + DefType canonicalType = runtimeDeterminedType.CanonicalType; + + return canonicalType.ContainsGCPointers; + } + + public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) + { + RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type; + DefType canonicalType = runtimeDeterminedType.CanonicalType; + + return canonicalType.ValueTypeShapeCharacteristics; + } + + public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) + { + RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type; + DefType canonicalType = runtimeDeterminedType.CanonicalType; + + return canonicalType.HfaElementType; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs new file mode 100644 index 00000000000..8b9a7cca1d5 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs @@ -0,0 +1,25 @@ +// 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 +{ + partial class RuntimeDeterminedType + { + public override string DiagnosticName + { + get + { + return _rawCanonType.DiagnosticName; + } + } + + public override string DiagnosticNamespace + { + get + { + return _rawCanonType.DiagnosticNamespace; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Sorting.cs new file mode 100644 index 00000000000..685bf46ad08 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Sorting.cs @@ -0,0 +1,22 @@ +// 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 +{ + // Functionality related to determinstic ordering of types + partial class RuntimeDeterminedType + { + protected internal override int ClassCode => 351938209; + + protected internal sealed override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + var otherType = (RuntimeDeterminedType)other; + int result = comparer.Compare(_rawCanonType, otherType._rawCanonType); + if (result != 0) + return result; + + return comparer.Compare(_runtimeDeterminedDetailsType, otherType._runtimeDeterminedDetailsType); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.cs new file mode 100644 index 00000000000..48abf82860a --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.cs @@ -0,0 +1,189 @@ +// 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.Collections.Generic; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Represents a runtime determined type. Runtime determined types are used to represent types + /// within shared generic method bodies and generic dictionaries. The concrete type will only + /// be known at runtime (when executing a shared generic method body under a specific generic context). + /// + /// + /// The use of runtime determined types is limited to the dependency analysis and to communicating + /// with the codegen backend during shared generic code generation. They should not show up within + /// the system otherwise. + /// + /// Runtime determined types behave mostly like the canonical type they are wrapping. Most of the overrides + /// this type implements will forward the implementation to the 's + /// implementation. + /// + /// Runtime determined types also behave like signature variables in the sense that they allow being + /// substituted during signature instantiation. + /// + public sealed partial class RuntimeDeterminedType : DefType + { + private DefType _rawCanonType; + private GenericParameterDesc _runtimeDeterminedDetailsType; + + public RuntimeDeterminedType(DefType rawCanonType, GenericParameterDesc runtimeDeterminedDetailsType) + { + _rawCanonType = rawCanonType; + _runtimeDeterminedDetailsType = runtimeDeterminedDetailsType; + } + + /// + /// Gets the generic parameter this runtime determined type represents. + /// + public GenericParameterDesc RuntimeDeterminedDetailsType + { + get + { + return _runtimeDeterminedDetailsType; + } + } + + /// + /// Gets the canonical type wrapped by this runtime determined type. + /// + public DefType CanonicalType + { + get + { + return _rawCanonType; + } + } + + public override TypeSystemContext Context + { + get + { + return _rawCanonType.Context; + } + } + + public override bool IsRuntimeDeterminedSubtype + { + get + { + return true; + } + } + + public override DefType BaseType + { + get + { + return _rawCanonType.BaseType; + } + } + + public override Instantiation Instantiation + { + get + { + return _rawCanonType.Instantiation; + } + } + + public override string Name + { + get + { + return _rawCanonType.Name; + } + } + + public override string Namespace + { + get + { + return String.Concat(_runtimeDeterminedDetailsType.Name, "_", _rawCanonType.Namespace); + } + } + + public override IEnumerable GetMethods() + { + foreach (var method in _rawCanonType.GetMethods()) + { + yield return Context.GetMethodForRuntimeDeterminedType(method.GetTypicalMethodDefinition(), this); + } + } + + public override MethodDesc GetMethod(string name, MethodSignature signature) + { + MethodDesc method = _rawCanonType.GetMethod(name, signature); + if (method == null) + return null; + return Context.GetMethodForRuntimeDeterminedType(method.GetTypicalMethodDefinition(), this); + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + if ((mask & TypeFlags.CategoryMask) != 0) + { + flags |= _rawCanonType.GetTypeFlags(mask); + } + + if ((mask & TypeFlags.HasGenericVarianceComputed) != 0) + { + flags |= _rawCanonType.GetTypeFlags(mask); + } + + if ((mask & TypeFlags.AttributeCacheComputed) != 0) + { + flags |= _rawCanonType.GetTypeFlags(mask); + } + + // Might need to define the behavior if we ever hit this. + Debug.Assert((flags & mask) != 0); + return flags; + } + + public override TypeDesc GetTypeDefinition() + { + // TODO: this is needed because NameMangler calls it to see if we're dealing with genericness. Revise? + if (_rawCanonType.HasInstantiation) + { + return Context.GetRuntimeDeterminedType((DefType)_rawCanonType.GetTypeDefinition(), _runtimeDeterminedDetailsType); + } + + return this; + } + + public override int GetHashCode() + { + return _rawCanonType.GetHashCode(); + } + + protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) + { + return _rawCanonType.ConvertToCanonForm(kind); + } + + public override bool IsCanonicalSubtype(CanonicalFormKind policy) + { + return false; + } + + public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + if (_runtimeDeterminedDetailsType.Kind == GenericParameterKind.Type) + { + return typeInstantiation[_runtimeDeterminedDetailsType.Index]; + } + else + { + Debug.Assert(_runtimeDeterminedDetailsType.Kind == GenericParameterKind.Method); + return methodInstantiation[_runtimeDeterminedDetailsType.Index]; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedTypeUtilities.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedTypeUtilities.cs new file mode 100644 index 00000000000..d8411a65b12 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedTypeUtilities.cs @@ -0,0 +1,71 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + internal static class RuntimeDeterminedTypeUtilities + { + public static Instantiation ConvertInstantiationToSharedRuntimeForm(Instantiation instantiation, Instantiation openInstantiation, out bool changed) + { + Debug.Assert(instantiation.Length == openInstantiation.Length); + + TypeDesc[] sharedInstantiation = null; + + CanonicalFormKind currentPolicy = CanonicalFormKind.Specific; + CanonicalFormKind startLoopPolicy; + + do + { + startLoopPolicy = currentPolicy; + + for (int instantiationIndex = 0; instantiationIndex < instantiation.Length; instantiationIndex++) + { + TypeDesc typeToConvert = instantiation[instantiationIndex]; + TypeSystemContext context = typeToConvert.Context; + TypeDesc canonForm = context.ConvertToCanon(typeToConvert, ref currentPolicy); + TypeDesc runtimeDeterminedForm = typeToConvert; + + Debug.Assert(openInstantiation[instantiationIndex] is GenericParameterDesc); + + if ((typeToConvert != canonForm) || typeToConvert.IsCanonicalType) + { + Debug.Assert(canonForm is DefType); + if (sharedInstantiation == null) + { + sharedInstantiation = new TypeDesc[instantiation.Length]; + for (int i = 0; i < instantiationIndex; i++) + sharedInstantiation[i] = instantiation[i]; + } + + runtimeDeterminedForm = context.GetRuntimeDeterminedType( + (DefType)canonForm, (GenericParameterDesc)openInstantiation[instantiationIndex]); + } + + if (sharedInstantiation != null) + { + sharedInstantiation[instantiationIndex] = runtimeDeterminedForm; + } + } + + // Optimization: even if canonical policy changed, we don't actually need to re-run the loop + // for instantiations that only have a single element. + if (instantiation.Length == 1) + { + break; + } + + } while (currentPolicy != startLoopPolicy); + + changed = sharedInstantiation != null; + if (changed) + { + return new Instantiation(sharedInstantiation); + } + + return instantiation; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/SignatureVariable.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/SignatureVariable.RuntimeDetermined.cs new file mode 100644 index 00000000000..416cc19d1c9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/SignatureVariable.RuntimeDetermined.cs @@ -0,0 +1,26 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + partial class SignatureVariable + { + public sealed override bool IsRuntimeDeterminedSubtype + { + get + { + Debug.Fail("IsRuntimeDeterminedSubtype of an indefinite type"); + return false; + } + } + + public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + Debug.Assert(false); + return this; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/TypeDesc.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/TypeDesc.RuntimeDetermined.cs new file mode 100644 index 00000000000..c21ee835aaf --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/TypeDesc.RuntimeDetermined.cs @@ -0,0 +1,35 @@ +// 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 +{ + partial class TypeDesc + { + /// + /// Gets a value indicating whether the concrete type this object represents is unknown + /// at compile time. For a constructed type, returns true if any of the constituents are + /// unknown at compile time. Use to check if + /// this is a runtime determined type without checking constituents. + /// + public abstract bool IsRuntimeDeterminedSubtype + { + get; + } + + /// + /// Gets a value indicating whether this is a runtime determined type. This will not + /// check the composition of constructed types for runtime determined types. Use + /// to do that. + /// + public bool IsRuntimeDeterminedType + { + get + { + return this.GetType() == typeof(RuntimeDeterminedType); + } + } + + public abstract TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/TypeSystemContext.RuntimeDetermined.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/TypeSystemContext.RuntimeDetermined.cs new file mode 100644 index 00000000000..e84d8752421 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/TypeSystemContext.RuntimeDetermined.cs @@ -0,0 +1,142 @@ +// 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.NativeFormat; + +namespace Internal.TypeSystem +{ + partial class TypeSystemContext + { + private struct RuntimeDeterminedTypeKey + { + private DefType _plainCanonType; + private GenericParameterDesc _detailsType; + + public RuntimeDeterminedTypeKey(DefType plainCanonType, GenericParameterDesc detailsType) + { + _plainCanonType = plainCanonType; + _detailsType = detailsType; + } + + public class RuntimeDeterminedTypeKeyHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(RuntimeDeterminedTypeKey key) + { + return key._detailsType.GetHashCode() ^ key._plainCanonType.GetHashCode(); + } + + protected override int GetValueHashCode(RuntimeDeterminedType value) + { + return value.RuntimeDeterminedDetailsType.GetHashCode() ^ value.CanonicalType.GetHashCode(); + } + + protected override bool CompareKeyToValue(RuntimeDeterminedTypeKey key, RuntimeDeterminedType value) + { + return key._detailsType == value.RuntimeDeterminedDetailsType && key._plainCanonType == value.CanonicalType; + } + + protected override bool CompareValueToValue(RuntimeDeterminedType value1, RuntimeDeterminedType value2) + { + return value1.RuntimeDeterminedDetailsType == value2.RuntimeDeterminedDetailsType + && value1.CanonicalType == value2.CanonicalType; + } + + protected override RuntimeDeterminedType CreateValueFromKey(RuntimeDeterminedTypeKey key) + { + return new RuntimeDeterminedType(key._plainCanonType, key._detailsType); + } + } + } + + private RuntimeDeterminedTypeKey.RuntimeDeterminedTypeKeyHashtable _runtimeDeterminedTypes = new RuntimeDeterminedTypeKey.RuntimeDeterminedTypeKeyHashtable(); + + public RuntimeDeterminedType GetRuntimeDeterminedType(DefType plainCanonType, GenericParameterDesc detailsType) + { + return _runtimeDeterminedTypes.GetOrCreateValue(new RuntimeDeterminedTypeKey(plainCanonType, detailsType)); + } + + protected internal virtual TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) + { + throw new NotSupportedException(); + } + + // + // Methods for runtime determined type + // + + private struct MethodForRuntimeDeterminedTypeKey + { + private MethodDesc _typicalMethodDef; + private RuntimeDeterminedType _rdType; + private int _hashcode; + + public MethodForRuntimeDeterminedTypeKey(MethodDesc typicalMethodDef, RuntimeDeterminedType rdType) + { + _typicalMethodDef = typicalMethodDef; + _rdType = rdType; + _hashcode = TypeHashingAlgorithms.ComputeMethodHashCode(rdType.CanonicalType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(typicalMethodDef.Name)); + } + + public MethodDesc TypicalMethodDef + { + get + { + return _typicalMethodDef; + } + } + + public RuntimeDeterminedType RDType + { + get + { + return _rdType; + } + } + + public class MethodForRuntimeDeterminedTypeKeyHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(MethodForRuntimeDeterminedTypeKey key) + { + return key._hashcode; + } + + protected override int GetValueHashCode(MethodForRuntimeDeterminedType value) + { + return value.GetHashCode(); + } + + protected override bool CompareKeyToValue(MethodForRuntimeDeterminedTypeKey key, MethodForRuntimeDeterminedType value) + { + if (key._typicalMethodDef != value.GetTypicalMethodDefinition()) + return false; + + return key._rdType == value.OwningType; + } + + protected override bool CompareValueToValue(MethodForRuntimeDeterminedType value1, MethodForRuntimeDeterminedType value2) + { + return (value1.GetTypicalMethodDefinition() == value2.GetTypicalMethodDefinition()) && (value1.OwningType == value2.OwningType); + } + + protected override MethodForRuntimeDeterminedType CreateValueFromKey(MethodForRuntimeDeterminedTypeKey key) + { + return new MethodForRuntimeDeterminedType(key.TypicalMethodDef, key.RDType, key._hashcode); + } + } + } + + private MethodForRuntimeDeterminedTypeKey.MethodForRuntimeDeterminedTypeKeyHashtable _methodForRDTypes = new MethodForRuntimeDeterminedTypeKey.MethodForRuntimeDeterminedTypeKeyHashtable(); + + public MethodDesc GetMethodForRuntimeDeterminedType(MethodDesc typicalMethodDef, RuntimeDeterminedType rdType) + { + Debug.Assert(!(typicalMethodDef is MethodForRuntimeDeterminedType)); + Debug.Assert(typicalMethodDef.IsTypicalMethodDefinition); + + return _methodForRDTypes.GetOrCreateValue(new MethodForRuntimeDeterminedTypeKey(typicalMethodDef, rdType)); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Serialization/FieldDesc.Serialization.cs b/src/coreclr/src/tools/Common/TypeSystem/Serialization/FieldDesc.Serialization.cs new file mode 100644 index 00000000000..9f5afef28a2 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Serialization/FieldDesc.Serialization.cs @@ -0,0 +1,33 @@ +// 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 +{ + // Additional members of FieldDesc related to serialization. + partial class FieldDesc + { + /// + /// Gets a value indicating whether this field is not serialized. + /// specially. + /// + public virtual bool IsNotSerialized + { + get + { + return false; + } + } + } + + partial class FieldForInstantiatedType + { + public override bool IsNotSerialized + { + get + { + return _fieldDef.IsNotSerialized; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Serialization/TypeDesc.Serialization.cs b/src/coreclr/src/tools/Common/TypeSystem/Serialization/TypeDesc.Serialization.cs new file mode 100644 index 00000000000..f8ba33aedd9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Serialization/TypeDesc.Serialization.cs @@ -0,0 +1,31 @@ +// 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 +{ + partial class TypeDesc + { + /// + /// Gets a value indicating whether this type is serializable. + /// + public virtual bool IsSerializable + { + get + { + return false; + } + } + } + + partial class InstantiatedType + { + public override bool IsSerializable + { + get + { + return _typeDef.IsSerializable; + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/ArrayType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/ArrayType.Sorting.cs new file mode 100644 index 00000000000..ba20c3609db --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/ArrayType.Sorting.cs @@ -0,0 +1,37 @@ +// 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 +{ + // Functionality related to determinstic ordering of types + partial class ArrayType + { + protected internal override int ClassCode => -1274559616; + + protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + var otherType = (ArrayType)other; + int result = _rank - otherType._rank; + if (result != 0) + return result; + + return comparer.Compare(ElementType, otherType.ElementType); + } + } + + partial class ArrayMethod + { + protected internal override int ClassCode => 487354154; + + protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) + { + var otherMethod = (ArrayMethod)other; + int result = _kind - otherMethod._kind; + if (result != 0) + return result; + + return comparer.CompareWithinClass(OwningArray, otherMethod.OwningArray); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/ByRefType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/ByRefType.Sorting.cs new file mode 100644 index 00000000000..7d5a2392741 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/ByRefType.Sorting.cs @@ -0,0 +1,17 @@ +// 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 +{ + // Functionality related to determinstic ordering of types + partial class ByRefType + { + protected internal override int ClassCode => -959602231; + + protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + return comparer.Compare(ParameterType, ((ByRefType)other).ParameterType); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/FieldDesc.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/FieldDesc.Sorting.cs new file mode 100644 index 00000000000..9888013b159 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/FieldDesc.Sorting.cs @@ -0,0 +1,23 @@ +// 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 +{ + // Functionality related to deterministic ordering of types and members + partial class FieldDesc + { + /// + /// Gets an identifier that is the same for all instances of this + /// descendant, but different from the of any other descendant. + /// + /// + /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". + /// If two manage to conflict (which is pretty unlikely), just make a new one... + /// + protected internal abstract int ClassCode { get; } + + // Note to implementers: the type of `other` is actually the same as the type of `this`. + protected internal abstract int CompareToImpl(FieldDesc other, TypeSystemComparer comparer); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/FieldForInstantiatedType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/FieldForInstantiatedType.Sorting.cs new file mode 100644 index 00000000000..720ab2362ca --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/FieldForInstantiatedType.Sorting.cs @@ -0,0 +1,23 @@ +// 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 +{ + // Functionality related to deterministic ordering of types and members + partial class FieldForInstantiatedType + { + protected internal override int ClassCode => 1140200283; + + protected internal override int CompareToImpl(FieldDesc other, TypeSystemComparer comparer) + { + var otherField = (FieldForInstantiatedType)other; + + int result = comparer.CompareWithinClass(_instantiatedType, otherField._instantiatedType); + if (result != 0) + return result; + + return comparer.Compare(_fieldDef, otherField._fieldDef); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/FunctionPointerType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/FunctionPointerType.Sorting.cs new file mode 100644 index 00000000000..d87745d39d7 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/FunctionPointerType.Sorting.cs @@ -0,0 +1,17 @@ +// 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 +{ + // Functionality related to determinstic ordering of types + partial class FunctionPointerType + { + protected internal override int ClassCode => -914739489; + + protected internal sealed override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + return _signature.CompareTo(((FunctionPointerType)other)._signature, comparer); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs new file mode 100644 index 00000000000..17b270780ce --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs @@ -0,0 +1,33 @@ +// 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 +{ + // Functionality related to deterministic ordering of types + partial class InstantiatedMethod + { + protected internal override int ClassCode => -873941872; + + protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) + { + var otherMethod = (InstantiatedMethod)other; + int result = _instantiation.Length - otherMethod._instantiation.Length; + if (result != 0) + return result; + + result = comparer.Compare(_methodDef, otherMethod._methodDef); + if (result != 0) + return result; + + for (int i = 0; i < _instantiation.Length; i++) + { + result = comparer.Compare(_instantiation[i], otherMethod._instantiation[i]); + if (result != 0) + break; + } + + return result; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs new file mode 100644 index 00000000000..f749b455940 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs @@ -0,0 +1,33 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Functionality related to determinstic ordering of types + partial class InstantiatedType + { + protected internal override int ClassCode => 1150020412; + + protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + var otherType = (InstantiatedType)other; + + int result = comparer.Compare(_typeDef, otherType._typeDef); + if (result == 0) + { + Debug.Assert(_instantiation.Length == otherType._instantiation.Length); + for (int i = 0; i < _instantiation.Length; i++) + { + result = comparer.Compare(_instantiation[i], otherType._instantiation[i]); + if (result != 0) + break; + } + } + + return result; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodDesc.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodDesc.Sorting.cs new file mode 100644 index 00000000000..a8872050614 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodDesc.Sorting.cs @@ -0,0 +1,23 @@ +// 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 +{ + // Functionality related to deterministic ordering of types and members + partial class MethodDesc + { + /// + /// Gets an identifier that is the same for all instances of this + /// descendant, but different from the of any other descendant. + /// + /// + /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". + /// If two manage to conflict (which is pretty unlikely), just make a new one... + /// + protected internal abstract int ClassCode { get; } + + // Note to implementers: the type of `other` is actually the same as the type of `this`. + protected internal abstract int CompareToImpl(MethodDesc other, TypeSystemComparer comparer); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodForInstantiatedType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodForInstantiatedType.Sorting.cs new file mode 100644 index 00000000000..3c66f37acc9 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodForInstantiatedType.Sorting.cs @@ -0,0 +1,23 @@ +// 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 +{ + // Functionality related to deterministic ordering of types + partial class MethodForInstantiatedType + { + protected internal override int ClassCode => 1359759636; + + protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) + { + var otherMethod = (MethodForInstantiatedType)other; + + int result = comparer.CompareWithinClass(_instantiatedType, otherMethod._instantiatedType); + if (result != 0) + return result; + + return comparer.Compare(_typicalMethodDef, otherMethod._typicalMethodDef); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodSignature.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodSignature.Sorting.cs new file mode 100644 index 00000000000..162a87907ff --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/MethodSignature.Sorting.cs @@ -0,0 +1,40 @@ +// 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 +{ + // Functionality related to determinstic ordering of types + partial class MethodSignature + { + internal int CompareTo(MethodSignature other, TypeSystemComparer comparer) + { + int result = _parameters.Length - other._parameters.Length; + if (result != 0) + return result; + + result = (int)_flags - (int)other._flags; + if (result != 0) + return result; + + result = _genericParameterCount - other._genericParameterCount; + if (result != 0) + return result; + + // Most expensive checks last + + result = comparer.Compare(_returnType, other._returnType); + if (result != 0) + return result; + + for (int i = 0; i < _parameters.Length; i++) + { + result = comparer.Compare(_parameters[i], other._parameters[i]); + if (result != 0) + break; + } + + return result; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/PointerType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/PointerType.Sorting.cs new file mode 100644 index 00000000000..30d3d297c89 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/PointerType.Sorting.cs @@ -0,0 +1,17 @@ +// 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 +{ + // Functionality related to determinstic ordering of types + partial class PointerType + { + protected internal override int ClassCode => -2124247792; + + protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + return comparer.Compare(ParameterType, ((PointerType)other).ParameterType); + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/SignatureVariable.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/SignatureVariable.Sorting.cs new file mode 100644 index 00000000000..cb5cae9399c --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/SignatureVariable.Sorting.cs @@ -0,0 +1,40 @@ +// 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; + +namespace Internal.TypeSystem +{ + // Functionality related to determinstic ordering of types + partial class SignatureVariable + { + protected internal sealed override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) + { + return ((SignatureVariable)other).Index - Index; + } + } + + partial class SignatureTypeVariable + { + protected internal override int ClassCode + { + get + { + return 1042124696; + } + } + } + + partial class SignatureMethodVariable + { + protected internal override int ClassCode + { + get + { + return 144542889; + } + } + + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/TypeDesc.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/TypeDesc.Sorting.cs new file mode 100644 index 00000000000..b0398f960e1 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/TypeDesc.Sorting.cs @@ -0,0 +1,23 @@ +// 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 +{ + // Functionality related to determinstic ordering of types and members + partial class TypeDesc + { + /// + /// Gets an identifier that is the same for all instances of this + /// descendant, but different from the of any other descendant. + /// + /// + /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". + /// If two manage to conflict (which is pretty unlikely), just make a new one... + /// + protected internal abstract int ClassCode { get; } + + // Note to implementers: the type of `other` is actually the same as the type of `this`. + protected internal abstract int CompareToImpl(TypeDesc other, TypeSystemComparer comparer); + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/TypeSystemComparer.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/TypeSystemComparer.cs new file mode 100644 index 00000000000..ee71c5bf245 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/TypeSystemComparer.cs @@ -0,0 +1,131 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + // Functionality related to determinstic ordering of types and members + // + // Many places within a compiler need a way to generate deterministically ordered lists + // that may be a result of non-deterministic processes. Multi-threaded compilation is a good + // example of such source of nondeterminism. Even though the order of the results of a multi-threaded + // compilation may be non-deterministic, the output of the compiler needs to be deterministic. + // The compiler achieves that by sorting the results of the compilation. + // + // While it's easy to compare types that are in the same category (e.g. named types within an assembly + // could be compared by their names or tokens), it's difficult to have a scheme where each category would know + // how to compare itself to other categories (does "array of pointers to uint" sort before a "byref + // to an object"?). The nature of the type system potentially allows for an unlimited number of TypeDesc + // descendants. + // + // We solve this problem by only requiring each TypeDesc or MethodDesc descendant to know how + // to sort itself with respect to other instances of the same type. + // Comparisons between different categories of types are centralized to a single location that + // can provide rules to sort them. + public class TypeSystemComparer + { + public int Compare(TypeDesc x, TypeDesc y) + { + if (x == y) + { + return 0; + } + + int codeX = x.ClassCode; + int codeY = y.ClassCode; + if (codeX == codeY) + { + Debug.Assert(x.GetType() == y.GetType()); + + int result = x.CompareToImpl(y, this); + + // We did a reference equality check above so an "Equal" result is not expected + Debug.Assert(result != 0); + + return result; + } + else + { + Debug.Assert(x.GetType() != y.GetType()); + return codeX > codeY ? -1 : 1; + } + } + + internal int CompareWithinClass(T x, T y) where T : TypeDesc + { + Debug.Assert(x.GetType() == y.GetType()); + + if (x == y) + return 0; + + int result = x.CompareToImpl(y, this); + + // We did a reference equality check above so an "Equal" result is not expected + Debug.Assert(result != 0); + + return result; + } + + public int Compare(MethodDesc x, MethodDesc y) + { + if (x == y) + { + return 0; + } + + int codeX = x.ClassCode; + int codeY = y.ClassCode; + if (codeX == codeY) + { + Debug.Assert(x.GetType() == y.GetType()); + + int result = x.CompareToImpl(y, this); + + // We did a reference equality check above so an "Equal" result is not expected + Debug.Assert(result != 0); + + return result; + } + else + { + Debug.Assert(x.GetType() != y.GetType()); + return codeX > codeY ? -1 : 1; + } + } + + public int Compare(FieldDesc x, FieldDesc y) + { + if (x == y) + { + return 0; + } + + int codeX = x.ClassCode; + int codeY = y.ClassCode; + if (codeX == codeY) + { + Debug.Assert(x.GetType() == y.GetType()); + + int result = x.CompareToImpl(y, this); + + // We did a reference equality check above so an "Equal" result is not expected + Debug.Assert(result != 0); + + return result; + } + else + { + Debug.Assert(x.GetType() != y.GetType()); + return codeX > codeY ? -1 : 1; + } + } + + public int Compare(MethodSignature x, MethodSignature y) + { + return x.CompareTo(y, this); + } + } +} + diff --git a/src/coreclr/src/tools/crossgen2/Common/CommandLine/CommandLineException.cs b/src/coreclr/src/tools/crossgen2/Common/CommandLine/CommandLineException.cs deleted file mode 100644 index e51837ca944..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/CommandLine/CommandLineException.cs +++ /dev/null @@ -1,16 +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; - -namespace Internal.CommandLine -{ - internal class CommandLineException : Exception - { - public CommandLineException(string message) - : base(message) - { - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/CommandLine/CommandLineHelpers.cs b/src/coreclr/src/tools/crossgen2/Common/CommandLine/CommandLineHelpers.cs deleted file mode 100644 index 35618e005e5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/CommandLine/CommandLineHelpers.cs +++ /dev/null @@ -1,65 +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 System.Collections.Generic; -using System.IO; - -namespace Internal.CommandLine -{ - // - // Helpers for command line processing - // - internal class Helpers - { - // Helper to create a collection of paths unique in their simple names. - public static void AppendExpandedPaths(Dictionary dictionary, string pattern, bool strict) - { - bool empty = true; - - string directoryName = Path.GetDirectoryName(pattern); - string searchPattern = Path.GetFileName(pattern); - - if (directoryName == "") - directoryName = "."; - - if (Directory.Exists(directoryName)) - { - foreach (string fileName in Directory.EnumerateFiles(directoryName, searchPattern)) - { - string fullFileName = Path.GetFullPath(fileName); - - string simpleName = Path.GetFileNameWithoutExtension(fileName); - - if (dictionary.ContainsKey(simpleName)) - { - if (strict) - { - throw new CommandLineException("Multiple input files matching same simple name " + - fullFileName + " " + dictionary[simpleName]); - } - } - else - { - dictionary.Add(simpleName, fullFileName); - } - - empty = false; - } - } - - if (empty) - { - if (strict) - { - throw new CommandLineException("No files matching " + pattern); - } - else - { - Console.WriteLine("Warning: No files matching " + pattern); - } - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/CodeGenerationFailedException.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/CodeGenerationFailedException.cs deleted file mode 100644 index ab4a47be400..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/CodeGenerationFailedException.cs +++ /dev/null @@ -1,28 +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.TypeSystem; - -namespace ILCompiler -{ - public class CodeGenerationFailedException : InternalCompilerErrorException - { - private const string MessageText = "Code generation failed for method '{0}'"; - - public MethodDesc Method { get; } - - public CodeGenerationFailedException(MethodDesc method) - : this(method, null) - { - } - - public CodeGenerationFailedException(MethodDesc method, Exception inner) - : base(String.Format(MessageText, method), inner) - { - Method = method; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilationBuilder.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilationBuilder.cs deleted file mode 100644 index 7fd7ad1769f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilationBuilder.cs +++ /dev/null @@ -1,110 +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 System.Collections.Generic; - -using ILCompiler.DependencyAnalysis; -using ILCompiler.DependencyAnalysisFramework; - -using Internal.IL; - -namespace ILCompiler -{ - public abstract partial class CompilationBuilder - { - protected readonly CompilerTypeSystemContext _context; - protected readonly CompilationModuleGroup _compilationGroup; - protected readonly NameMangler _nameMangler; - - // These need to provide reasonable defaults so that the user can optionally skip - // calling the Use/Configure methods and still get something reasonable back. - protected Logger _logger = Logger.Null; - private DependencyTrackingLevel _dependencyTrackingLevel = DependencyTrackingLevel.None; - protected IEnumerable _compilationRoots = Array.Empty(); - protected OptimizationMode _optimizationMode = OptimizationMode.None; - - public CompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup compilationGroup, NameMangler nameMangler) - { - _context = context; - _compilationGroup = compilationGroup; - _nameMangler = nameMangler; - InitializePartial(); - } - - // Partial class specific initialization - partial void InitializePartial(); - - public CompilationBuilder UseLogger(Logger logger) - { - _logger = logger; - return this; - } - - public CompilationBuilder UseCompilationUnitPrefix(string prefix) - { - _nameMangler.CompilationUnitPrefix = prefix; - return this; - } - - public CompilationBuilder UseDependencyTracking(DependencyTrackingLevel trackingLevel) - { - _dependencyTrackingLevel = trackingLevel; - return this; - } - - public CompilationBuilder UseCompilationRoots(IEnumerable compilationRoots) - { - _compilationRoots = compilationRoots; - return this; - } - - public CompilationBuilder UseOptimizationMode(OptimizationMode mode) - { - _optimizationMode = mode; - return this; - } - - public abstract CompilationBuilder UseBackendOptions(IEnumerable options); - - public abstract CompilationBuilder UseILProvider(ILProvider ilProvider); - - protected abstract ILProvider GetILProvider(); - - public abstract CompilationBuilder UseJitPath(string jitPath); - - protected DependencyAnalyzerBase CreateDependencyGraph(NodeFactory factory, IComparer> comparer = null) - { - return _dependencyTrackingLevel.CreateDependencyGraph(factory, comparer); - } - - public abstract ICompilation ToCompilation(); - } - - /// - /// Represents the level of optimizations performed by the compiler. - /// - public enum OptimizationMode - { - /// - /// Do not optimize. - /// - None, - - /// - /// Minimize code space. - /// - PreferSize, - - /// - /// Generate blended code. (E.g. favor size for rarely executed code such as class constructors.) - /// - Blended, - - /// - /// Maximize execution speed. - /// - PreferSpeed, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilationModuleGroup.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilationModuleGroup.cs deleted file mode 100644 index 1feb14c46c0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilationModuleGroup.cs +++ /dev/null @@ -1,26 +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 Internal.TypeSystem; - -namespace ILCompiler -{ - public abstract partial class CompilationModuleGroup - { - /// - /// If true, "type" is in the set of input assemblies being compiled - /// - public abstract bool ContainsType(TypeDesc type); - /// - /// If true, "method" is in the set of input assemblies being compiled - /// - public abstract bool ContainsMethodBody(MethodDesc method, bool unboxingStub); - /// - /// Decide whether a given call may get inlined by JIT. - /// - /// Calling method the assembly code of is about to receive the callee code - /// The called method to be inlined into the caller - public virtual bool CanInline(MethodDesc callerMethod, MethodDesc calleeMethod) => true; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilerTypeSystemContext.Validation.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilerTypeSystemContext.Validation.cs deleted file mode 100644 index 50314850660..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilerTypeSystemContext.Validation.cs +++ /dev/null @@ -1,151 +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 Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace ILCompiler -{ - // Validates types to the extent that is required to make sure the compilation won't fail - // in unpredictable spots. - partial class CompilerTypeSystemContext - { - /// - /// Ensures that the type can be fully loaded. The method will throw one of the type system - /// exceptions if the type is not loadable. - /// - public void EnsureLoadableType(TypeDesc type) - { - _validTypes.GetOrCreateValue(type); - } - - class ValidTypeHashTable : LockFreeReaderHashtable - { - protected override bool CompareKeyToValue(TypeDesc key, TypeDesc value) => key == value; - protected override bool CompareValueToValue(TypeDesc value1, TypeDesc value2) => value1 == value2; - protected override TypeDesc CreateValueFromKey(TypeDesc key) => EnsureLoadableTypeUncached(key); - protected override int GetKeyHashCode(TypeDesc key) => key.GetHashCode(); - protected override int GetValueHashCode(TypeDesc value) => value.GetHashCode(); - } - private readonly ValidTypeHashTable _validTypes = new ValidTypeHashTable(); - - private static TypeDesc EnsureLoadableTypeUncached(TypeDesc type) - { - if (type.IsParameterizedType) - { - // Validate parameterized types - var parameterizedType = (ParameterizedType)type; - - TypeDesc parameterType = parameterizedType.ParameterType; - - // Make sure type of the parameter is loadable. - ((CompilerTypeSystemContext)type.Context).EnsureLoadableType(parameterType); - - // Validate we're not constructing a type over a ByRef - if (parameterType.IsByRef) - { - // CLR compat note: "ldtoken int32&&" will actually fail with a message about int32&; "ldtoken int32&[]" - // will fail with a message about being unable to create an array of int32&. This is a middle ground. - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - // Validate the parameter is not an uninstantiated generic. - if (parameterType.IsGenericDefinition) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - if (parameterizedType.IsArray) - { - if (parameterType.IsFunctionPointer) - { - // Arrays of function pointers are not currently supported - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - LayoutInt elementSize = parameterType.GetElementSize(); - if (!elementSize.IsIndeterminate && elementSize.AsInt >= ushort.MaxValue) - { - // Element size over 64k can't be encoded in the GCDesc - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadValueClassTooLarge, parameterType); - } - - if (((ArrayType)parameterizedType).Rank > 32) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadRankTooLarge, type); - } - - if (parameterType.IsByRefLike) - { - // Arrays of byref-like types are not allowed - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - // It might seem reasonable to disallow array of void, but the CLR doesn't prevent that too hard. - // E.g. "newarr void" will fail, but "newarr void[]" or "ldtoken void[]" will succeed. - } - } - else if (type.IsFunctionPointer) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - else - { - // Validate classes, structs, enums, interfaces, and delegates - Debug.Assert(type.IsDefType); - - // Don't validate generic definitons - if (type.IsGenericDefinition) - { - return type; - } - - // System.__Canon or System.__UniversalCanon - if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) - { - return type; - } - - // We need to be able to load interfaces - foreach (var intf in type.RuntimeInterfaces) - { - ((CompilerTypeSystemContext)type.Context).EnsureLoadableType(intf.NormalizeInstantiation()); - } - - var defType = (DefType)type; - - // Ensure we can compute the type layout - defType.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields); - defType.ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizesAndFields); - - // Make sure instantiation length matches the expectation - if (defType.Instantiation.Length != defType.GetTypeDefinition().Instantiation.Length) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - foreach (TypeDesc typeArg in defType.Instantiation) - { - // ByRefs, pointers, function pointers, and System.Void are never valid instantiation arguments - if (typeArg.IsByRef - || typeArg.IsPointer - || typeArg.IsFunctionPointer - || typeArg.IsVoid - || typeArg.IsByRefLike) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - // TODO: validate constraints - } - - // Check the type doesn't have bogus MethodImpls or overrides and we can get the finalizer. - defType.GetFinalizer(); - } - - return type; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilerTypeSystemContext.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilerTypeSystemContext.cs deleted file mode 100644 index 7463ec7cc86..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/CompilerTypeSystemContext.cs +++ /dev/null @@ -1,353 +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 System.IO; -using System.IO.MemoryMappedFiles; -using System.Diagnostics; -using System.Collections.Generic; -using System.Reflection.Metadata; -using System.Reflection.PortableExecutable; - -using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; - -namespace ILCompiler -{ - public partial class CompilerTypeSystemContext : MetadataTypeSystemContext, IMetadataStringDecoderProvider - { - private readonly MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); - private readonly MetadataVirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm(); - - private MetadataStringDecoder _metadataStringDecoder; - - private class ModuleData - { - public string SimpleName; - public string FilePath; - - public EcmaModule Module; - public MemoryMappedViewAccessor MappedViewAccessor; - } - - private class ModuleHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(EcmaModule key) - { - return key.GetHashCode(); - } - protected override int GetValueHashCode(ModuleData value) - { - return value.Module.GetHashCode(); - } - protected override bool CompareKeyToValue(EcmaModule key, ModuleData value) - { - return Object.ReferenceEquals(key, value.Module); - } - protected override bool CompareValueToValue(ModuleData value1, ModuleData value2) - { - return Object.ReferenceEquals(value1.Module, value2.Module); - } - protected override ModuleData CreateValueFromKey(EcmaModule key) - { - Debug.Fail("CreateValueFromKey not supported"); - return null; - } - } - private readonly ModuleHashtable _moduleHashtable = new ModuleHashtable(); - - private class SimpleNameHashtable : LockFreeReaderHashtable - { - StringComparer _comparer = StringComparer.OrdinalIgnoreCase; - - protected override int GetKeyHashCode(string key) - { - return _comparer.GetHashCode(key); - } - protected override int GetValueHashCode(ModuleData value) - { - return _comparer.GetHashCode(value.SimpleName); - } - protected override bool CompareKeyToValue(string key, ModuleData value) - { - return _comparer.Equals(key, value.SimpleName); - } - protected override bool CompareValueToValue(ModuleData value1, ModuleData value2) - { - return _comparer.Equals(value1.SimpleName, value2.SimpleName); - } - protected override ModuleData CreateValueFromKey(string key) - { - Debug.Fail("CreateValueFromKey not supported"); - return null; - } - } - private readonly SimpleNameHashtable _simpleNameHashtable = new SimpleNameHashtable(); - - private readonly SharedGenericsMode _genericsMode; - - public IReadOnlyDictionary InputFilePaths - { - get; - set; - } - - public IReadOnlyDictionary ReferenceFilePaths - { - get; - set; - } - - public override ModuleDesc ResolveAssembly(System.Reflection.AssemblyName name, bool throwIfNotFound) - { - // TODO: catch typesystem BadImageFormatException and throw a new one that also captures the - // assembly name that caused the failure. (Along with the reason, which makes this rather annoying). - return GetModuleForSimpleName(name.Name, throwIfNotFound); - } - - public ModuleDesc GetModuleForSimpleName(string simpleName, bool throwIfNotFound = true) - { - ModuleData existing; - if (_simpleNameHashtable.TryGetValue(simpleName, out existing)) - return existing.Module; - - string filePath; - if (!InputFilePaths.TryGetValue(simpleName, out filePath)) - { - if (!ReferenceFilePaths.TryGetValue(simpleName, out filePath)) - { - // We allow the CanonTypesModule to not be an EcmaModule. - if (((IAssemblyDesc)CanonTypesModule).GetName().Name == simpleName) - return CanonTypesModule; - - // TODO: the exception is wrong for two reasons: for one, this should be assembly full name, not simple name. - // The other reason is that on CoreCLR, the exception also captures the reason. We should be passing two - // string IDs. This makes this rather annoying. - if (throwIfNotFound) - ThrowHelper.ThrowFileNotFoundException(ExceptionStringID.FileLoadErrorGeneric, simpleName); - return null; - } - } - - return AddModule(filePath, simpleName, true); - } - - public EcmaModule GetModuleFromPath(string filePath) - { - return GetOrAddModuleFromPath(filePath, true); - } - - public EcmaModule GetMetadataOnlyModuleFromPath(string filePath) - { - return GetOrAddModuleFromPath(filePath, false); - } - - private EcmaModule GetOrAddModuleFromPath(string filePath, bool useForBinding) - { - // This method is not expected to be called frequently. Linear search is acceptable. - foreach (var entry in ModuleHashtable.Enumerator.Get(_moduleHashtable)) - { - if (entry.FilePath == filePath) - return entry.Module; - } - - return AddModule(filePath, null, useForBinding); - } - - public static unsafe PEReader OpenPEFile(string filePath, out MemoryMappedViewAccessor mappedViewAccessor) - { - // System.Reflection.Metadata has heuristic that tries to save virtual address space. This heuristic does not work - // well for us since it can make IL access very slow (call to OS for each method IL query). We will map the file - // ourselves to get the desired performance characteristics reliably. - - FileStream fileStream = null; - MemoryMappedFile mappedFile = null; - MemoryMappedViewAccessor accessor = null; - try - { - // Create stream because CreateFromFile(string, ...) uses FileShare.None which is too strict - fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false); - mappedFile = MemoryMappedFile.CreateFromFile( - fileStream, null, fileStream.Length, MemoryMappedFileAccess.Read, HandleInheritability.None, true); - accessor = mappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); - - var safeBuffer = accessor.SafeMemoryMappedViewHandle; - var peReader = new PEReader((byte*)safeBuffer.DangerousGetHandle(), (int)safeBuffer.ByteLength); - - // MemoryMappedFile does not need to be kept around. MemoryMappedViewAccessor is enough. - - mappedViewAccessor = accessor; - accessor = null; - - return peReader; - } - finally - { - if (accessor != null) - accessor.Dispose(); - if (mappedFile != null) - mappedFile.Dispose(); - if (fileStream != null) - fileStream.Dispose(); - } - } - - private EcmaModule AddModule(string filePath, string expectedSimpleName, bool useForBinding) - { - MemoryMappedViewAccessor mappedViewAccessor = null; - PdbSymbolReader pdbReader = null; - try - { - PEReader peReader = OpenPEFile(filePath, out mappedViewAccessor); - pdbReader = OpenAssociatedSymbolFile(filePath, peReader); - - EcmaModule module = EcmaModule.Create(this, peReader, containingAssembly: null, pdbReader); - - MetadataReader metadataReader = module.MetadataReader; - string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); - - if (expectedSimpleName != null && !simpleName.Equals(expectedSimpleName, StringComparison.OrdinalIgnoreCase)) - throw new FileNotFoundException("Assembly name does not match filename " + filePath); - - ModuleData moduleData = new ModuleData() - { - SimpleName = simpleName, - FilePath = filePath, - Module = module, - MappedViewAccessor = mappedViewAccessor - }; - - lock (this) - { - if (useForBinding) - { - ModuleData actualModuleData = _simpleNameHashtable.AddOrGetExisting(moduleData); - if (actualModuleData != moduleData) - { - if (actualModuleData.FilePath != filePath) - throw new FileNotFoundException("Module with same simple name already exists " + filePath); - return actualModuleData.Module; - } - } - mappedViewAccessor = null; // Ownership has been transfered - pdbReader = null; // Ownership has been transferred - - _moduleHashtable.AddOrGetExisting(moduleData); - } - - return module; - } - finally - { - if (mappedViewAccessor != null) - mappedViewAccessor.Dispose(); - if (pdbReader != null) - pdbReader.Dispose(); - } - } - - protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) - { - return _metadataRuntimeInterfacesAlgorithm; - } - - public override VirtualMethodAlgorithm GetVirtualMethodAlgorithmForType(TypeDesc type) - { - Debug.Assert(!type.IsArray, "Wanted to call GetClosestMetadataType?"); - - return _virtualMethodAlgorithm; - } - - protected override Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) - { - if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes) - return RuntimeDeterminedCanonicalizationAlgorithm.ConvertInstantiationToCanonForm(instantiation, kind, out changed); - - Debug.Assert(_genericsMode == SharedGenericsMode.Disabled); - changed = false; - return instantiation; - } - - protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) - { - if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes) - return RuntimeDeterminedCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind); - - Debug.Assert(_genericsMode == SharedGenericsMode.Disabled); - return typeToConvert; - } - - protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) - { - if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes) - return RuntimeDeterminedCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, ref kind); - - Debug.Assert(_genericsMode == SharedGenericsMode.Disabled); - return typeToConvert; - } - - public override bool SupportsUniversalCanon => false; - public override bool SupportsCanon => _genericsMode != SharedGenericsMode.Disabled; - - public MetadataStringDecoder GetMetadataStringDecoder() - { - if (_metadataStringDecoder == null) - _metadataStringDecoder = new CachingMetadataStringDecoder(0x10000); // TODO: Tune the size - return _metadataStringDecoder; - } - - // - // Symbols - // - - private PdbSymbolReader OpenAssociatedSymbolFile(string peFilePath, PEReader peReader) - { - // Assume that the .pdb file is next to the binary - var pdbFilename = Path.ChangeExtension(peFilePath, ".pdb"); - string searchPath = ""; - - if (!File.Exists(pdbFilename)) - { - pdbFilename = null; - - // If the file doesn't exist, try the path specified in the CodeView section of the image - foreach (DebugDirectoryEntry debugEntry in peReader.ReadDebugDirectory()) - { - if (debugEntry.Type != DebugDirectoryEntryType.CodeView) - continue; - - string candidateFileName = peReader.ReadCodeViewDebugDirectoryData(debugEntry).Path; - if (Path.IsPathRooted(candidateFileName) && File.Exists(candidateFileName)) - { - pdbFilename = candidateFileName; - searchPath = Path.GetDirectoryName(pdbFilename); - break; - } - } - - if (pdbFilename == null) - return null; - } - - // Try to open the symbol file as portable pdb first - PdbSymbolReader reader = PortablePdbSymbolReader.TryOpen(pdbFilename, GetMetadataStringDecoder()); - if (reader == null) - { - // Fallback to the diasymreader for non-portable pdbs - reader = UnmanagedPdbSymbolReader.TryOpenSymbolReaderForMetadataFile(peFilePath, searchPath); - } - - return reader; - } - } - - /// - /// Specifies the mode in which canonicalization should occur. - /// - public enum SharedGenericsMode - { - Disabled, - CanonicalReferenceTypes, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/CoreRTNameMangler.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/CoreRTNameMangler.cs deleted file mode 100644 index fe5b722d723..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/CoreRTNameMangler.cs +++ /dev/null @@ -1,641 +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 System.Collections.Generic; -using System.Collections.Immutable; -using System.Security.Cryptography; -using System.Text; - -using Internal.Text; -using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; -using System.Diagnostics; - -namespace ILCompiler -{ - public class CoreRTNameMangler : NameMangler - { - private SHA256 _sha256; - -#if !READYTORUN - private readonly bool _mangleForCplusPlus; - - public CoreRTNameMangler(NodeMangler nodeMangler, bool mangleForCplusPlus) : base(nodeMangler) - { - _mangleForCplusPlus = mangleForCplusPlus; - } -#else - private readonly bool _mangleForCplusPlus = false; -#endif - - private string _compilationUnitPrefix; - - public override string CompilationUnitPrefix - { - set { _compilationUnitPrefix = SanitizeNameWithHash(value); } - get - { - Debug.Assert(_compilationUnitPrefix != null); - return _compilationUnitPrefix; - } - } - - // - // Turn a name into a valid C/C++ identifier - // - public override string SanitizeName(string s, bool typeName = false) - { - StringBuilder sb = null; - for (int i = 0; i < s.Length; i++) - { - char c = s[i]; - - if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) - { - if (sb != null) - sb.Append(c); - continue; - } - - if ((c >= '0') && (c <= '9')) - { - // C identifiers cannot start with a digit. Prepend underscores. - if (i == 0) - { - if (sb == null) - sb = new StringBuilder(s.Length + 2); - sb.Append("_"); - } - if (sb != null) - sb.Append(c); - continue; - } - - if (sb == null) - sb = new StringBuilder(s, 0, i, s.Length); - - // For CppCodeGen, replace "." (C# namespace separator) with "::" (C++ namespace separator) - if (typeName && c == '.' && _mangleForCplusPlus) - { - sb.Append("::"); - continue; - } - - // Everything else is replaced by underscore. - // TODO: We assume that there won't be collisions with our own or C++ built-in identifiers. - sb.Append("_"); - } - - string sanitizedName = (sb != null) ? sb.ToString() : s; - - // The character sequences denoting generic instantiations, arrays, byrefs, or pointers must be - // restricted to that use only. Replace them if they happened to be used in any identifiers in - // the compilation input. - return _mangleForCplusPlus - ? sanitizedName.Replace(EnterNameScopeSequence, "_AA_").Replace(ExitNameScopeSequence, "_VV_") - : sanitizedName; - } - - private static byte[] GetBytesFromString(string literal) - { - byte[] bytes = new byte[checked(literal.Length * 2)]; - for (int i = 0; i < literal.Length; i++) - { - int iByteBase = i * 2; - char c = literal[i]; - bytes[iByteBase] = (byte)c; - bytes[iByteBase + 1] = (byte)(c >> 8); - } - return bytes; - } - - private string SanitizeNameWithHash(string literal) - { - string mangledName = SanitizeName(literal); - - if (mangledName.Length > 30) - mangledName = mangledName.Substring(0, 30); - - if (mangledName != literal) - { - byte[] hash; - lock (this) - { - if (_sha256 == null) - { - // Use SHA256 hash here to provide a high degree of uniqueness to symbol names without requiring them to be long - // This hash function provides an exceedingly high likelihood that no two strings will be given equal symbol names - // This is not considered used for security purpose; however collisions would be highly unfortunate as they will cause compilation - // failure. - _sha256 = SHA256.Create(); - } - - hash = _sha256.ComputeHash(GetBytesFromString(literal)); - } - - mangledName += "_" + BitConverter.ToString(hash).Replace("-", ""); - } - - return mangledName; - } - - /// - /// Dictionary given a mangled name for a given - /// - private ImmutableDictionary _mangledTypeNames = ImmutableDictionary.Empty; - - /// - /// Given a set of names check if - /// is unique, if not add a numbered suffix until it becomes unique. - /// - /// Name to check for uniqueness. - /// Set of names already used. - /// A name based on that is not part of . - private string DisambiguateName(string origName, ISet set) - { - int iter = 0; - string result = origName; - while (set.Contains(result)) - { - result = string.Concat(origName, "_", (iter++).ToStringInvariant()); - } - return result; - } - - public override string GetMangledTypeName(TypeDesc type) - { - string mangledName; - if (_mangledTypeNames.TryGetValue(type, out mangledName)) - return mangledName; - - return ComputeMangledTypeName(type); - } - - private string EnterNameScopeSequence => _mangleForCplusPlus ? "_A_" : "<"; - private string ExitNameScopeSequence => _mangleForCplusPlus ? "_V_" : ">"; - private string DelimitNameScopeSequence => _mangleForCplusPlus? "_C_" : ","; - - protected string NestMangledName(string name) - { - return EnterNameScopeSequence + name + ExitNameScopeSequence; - } - - /// - /// If given is an precompute its mangled type name - /// along with all the other types from the same module as . - /// Otherwise, it is a constructed type and to the EcmaType's mangled name we add a suffix to - /// show what kind of constructed type it is (e.g. appending __Array for an array type). - /// - /// Type to mangled - /// Mangled name for . - private string ComputeMangledTypeName(TypeDesc type) - { - if (type is EcmaType) - { - EcmaType ecmaType = (EcmaType)type; - - string assemblyName = ((EcmaAssembly)ecmaType.EcmaModule).GetName().Name; - bool isSystemPrivate = assemblyName.StartsWith("System.Private."); - - // Abbreviate System.Private to S.P. This might conflict with user defined assembly names, - // but we already have a problem due to running SanitizeName without disambiguating the result - // This problem needs a better fix. - if (isSystemPrivate && !_mangleForCplusPlus) - assemblyName = "S.P." + assemblyName.Substring(15); - string prependAssemblyName = SanitizeName(assemblyName); - - var deduplicator = new HashSet(); - - // Add consistent names for all types in the module, independent on the order in which - // they are compiled - lock (this) - { - bool isSystemModule = ecmaType.Module == ecmaType.Context.SystemModule; - - if (!_mangledTypeNames.ContainsKey(type)) - { - foreach (MetadataType t in ecmaType.EcmaModule.GetAllTypes()) - { - string name = t.GetFullName(); - - // Include encapsulating type - DefType containingType = t.ContainingType; - while (containingType != null) - { - name = containingType.GetFullName() + "_" + name; - containingType = containingType.ContainingType; - } - - name = SanitizeName(name, true); - - if (_mangleForCplusPlus) - { - // Always generate a fully qualified name - name = "::" + prependAssemblyName + "::" + name; - } - else - { - name = prependAssemblyName + "_" + name; - - // If this is one of the well known types, use a shorter name - // We know this won't conflict because all the other types are - // prefixed by the assembly name. - if (isSystemModule) - { - switch (t.Category) - { - case TypeFlags.Boolean: name = "Bool"; break; - case TypeFlags.Byte: name = "UInt8"; break; - case TypeFlags.SByte: name = "Int8"; break; - case TypeFlags.UInt16: name = "UInt16"; break; - case TypeFlags.Int16: name = "Int16"; break; - case TypeFlags.UInt32: name = "UInt32"; break; - case TypeFlags.Int32: name = "Int32"; break; - case TypeFlags.UInt64: name = "UInt64"; break; - case TypeFlags.Int64: name = "Int64"; break; - case TypeFlags.Char: name = "Char"; break; - case TypeFlags.Double: name = "Double"; break; - case TypeFlags.Single: name = "Single"; break; - case TypeFlags.IntPtr: name = "IntPtr"; break; - case TypeFlags.UIntPtr: name = "UIntPtr"; break; - default: - if (t.IsObject) - name = "Object"; - else if (t.IsString) - name = "String"; - break; - } - } - } - - // Ensure that name is unique and update our tables accordingly. - name = DisambiguateName(name, deduplicator); - deduplicator.Add(name); - _mangledTypeNames = _mangledTypeNames.Add(t, name); - } - } - } - - return _mangledTypeNames[type]; - } - - string mangledName; - - switch (type.Category) - { - case TypeFlags.Array: - mangledName = "__MDArray" + - EnterNameScopeSequence + - GetMangledTypeName(((ArrayType)type).ElementType) + - DelimitNameScopeSequence + - ((ArrayType)type).Rank.ToStringInvariant() + - ExitNameScopeSequence; - break; - case TypeFlags.SzArray: - mangledName = "__Array" + NestMangledName(GetMangledTypeName(((ArrayType)type).ElementType)); - break; - case TypeFlags.ByRef: - mangledName = GetMangledTypeName(((ByRefType)type).ParameterType) + NestMangledName("ByRef"); - break; - case TypeFlags.Pointer: - mangledName = GetMangledTypeName(((PointerType)type).ParameterType) + NestMangledName("Pointer"); - break; - default: - // Case of a generic type. If `type' is a type definition we use the type name - // for mangling, otherwise we use the mangling of the type and its generic type - // parameters, e.g. A becomes A_<___B_>_ in RyuJIT compilation, or A_A___B_V_ - // in C++ compilation. - var typeDefinition = type.GetTypeDefinition(); - if (typeDefinition != type) - { - mangledName = GetMangledTypeName(typeDefinition); - - var inst = type.Instantiation; - string mangledInstantiation = ""; - for (int i = 0; i < inst.Length; i++) - { - string instArgName = GetMangledTypeName(inst[i]); - if (_mangleForCplusPlus) - instArgName = instArgName.Replace("::", "_"); - if (i > 0) - mangledInstantiation += "__"; - - mangledInstantiation += instArgName; - } - mangledName += NestMangledName(mangledInstantiation); - } - else if (type is IPrefixMangledMethod) - { - mangledName = GetPrefixMangledMethodName((IPrefixMangledMethod)type).ToString(); - } - else if (type is IPrefixMangledType) - { - mangledName = GetPrefixMangledTypeName((IPrefixMangledType)type).ToString(); - } - else - { - // This is a type definition. Since we didn't fall in the `is EcmaType` case above, - // it's likely a compiler-generated type. - mangledName = SanitizeName(((DefType)type).GetFullName(), true); - - // Always generate a fully qualified name - if (_mangleForCplusPlus) - mangledName = "::" + mangledName; - } - break; - } - - lock (this) - { - // Ensure that name is unique and update our tables accordingly. - if (!_mangledTypeNames.ContainsKey(type)) - _mangledTypeNames = _mangledTypeNames.Add(type, mangledName); - } - - return mangledName; - } - - private ImmutableDictionary _mangledMethodNames = ImmutableDictionary.Empty; - private ImmutableDictionary _unqualifiedMangledMethodNames = ImmutableDictionary.Empty; - - public override Utf8String GetMangledMethodName(MethodDesc method) - { - if (_mangleForCplusPlus) - { - return GetUnqualifiedMangledMethodName(method); - } - else - { - Utf8String utf8MangledName; - if (_mangledMethodNames.TryGetValue(method, out utf8MangledName)) - return utf8MangledName; - - Utf8StringBuilder sb = new Utf8StringBuilder(); - sb.Append(GetMangledTypeName(method.OwningType)); - sb.Append("__"); - sb.Append(GetUnqualifiedMangledMethodName(method)); - utf8MangledName = sb.ToUtf8String(); - - lock (this) - { - if (!_mangledMethodNames.ContainsKey(method)) - _mangledMethodNames = _mangledMethodNames.Add(method, utf8MangledName); - } - - return utf8MangledName; - } - } - - private Utf8String GetUnqualifiedMangledMethodName(MethodDesc method) - { - Utf8String mangledName; - if (_unqualifiedMangledMethodNames.TryGetValue(method, out mangledName)) - return mangledName; - - return ComputeUnqualifiedMangledMethodName(method); - } - - private Utf8String GetPrefixMangledTypeName(IPrefixMangledType prefixMangledType) - { - Utf8StringBuilder sb = new Utf8StringBuilder(); - sb.Append(EnterNameScopeSequence).Append(prefixMangledType.Prefix).Append(ExitNameScopeSequence); - - if (_mangleForCplusPlus) - { - string name = GetMangledTypeName(prefixMangledType.BaseType).ToString().Replace("::", "_"); - sb.Append(name); - } - else - { - sb.Append(GetMangledTypeName(prefixMangledType.BaseType)); - } - - return sb.ToUtf8String(); - } - - private Utf8String GetPrefixMangledSignatureName(IPrefixMangledSignature prefixMangledSignature) - { - Utf8StringBuilder sb = new Utf8StringBuilder(); - sb.Append(EnterNameScopeSequence).Append(prefixMangledSignature.Prefix).Append(ExitNameScopeSequence); - - var signature = prefixMangledSignature.BaseSignature; - sb.Append(signature.Flags.ToStringInvariant()); - - sb.Append(EnterNameScopeSequence); - - string sigRetTypeName = GetMangledTypeName(signature.ReturnType); - if (_mangleForCplusPlus) - sigRetTypeName = sigRetTypeName.Replace("::", "_"); - sb.Append(sigRetTypeName); - - for (int i = 0; i < signature.Length; i++) - { - sb.Append("__"); - string sigArgName = GetMangledTypeName(signature[i]); - if (_mangleForCplusPlus) - sigArgName = sigArgName.Replace("::", "_"); - sb.Append(sigArgName); - } - - sb.Append(ExitNameScopeSequence); - - return sb.ToUtf8String(); - } - - private Utf8String GetPrefixMangledMethodName(IPrefixMangledMethod prefixMangledMetod) - { - Utf8StringBuilder sb = new Utf8StringBuilder(); - sb.Append(EnterNameScopeSequence).Append(prefixMangledMetod.Prefix).Append(ExitNameScopeSequence); - - if (_mangleForCplusPlus) - { - string name = GetMangledMethodName(prefixMangledMetod.BaseMethod).ToString().Replace("::", "_"); - sb.Append(name); - } - else - { - sb.Append(GetMangledMethodName(prefixMangledMetod.BaseMethod)); - } - - return sb.ToUtf8String(); - } - - private Utf8String ComputeUnqualifiedMangledMethodName(MethodDesc method) - { - if (method is EcmaMethod) - { - var deduplicator = new HashSet(); - - // Add consistent names for all methods of the type, independent on the order in which - // they are compiled - lock (this) - { - if (!_unqualifiedMangledMethodNames.ContainsKey(method)) - { - foreach (var m in method.OwningType.GetMethods()) - { - string name = SanitizeName(m.Name); - - name = DisambiguateName(name, deduplicator); - deduplicator.Add(name); - - _unqualifiedMangledMethodNames = _unqualifiedMangledMethodNames.Add(m, name); - } - } - } - - return _unqualifiedMangledMethodNames[method]; - } - - Utf8String utf8MangledName; - - var methodDefinition = method.GetMethodDefinition(); - if (methodDefinition != method) - { - // Instantiated generic method - Utf8StringBuilder sb = new Utf8StringBuilder(); - sb.Append(GetUnqualifiedMangledMethodName(methodDefinition.GetTypicalMethodDefinition())); - - sb.Append(EnterNameScopeSequence); - - var inst = method.Instantiation; - for (int i = 0; i < inst.Length; i++) - { - string instArgName = GetMangledTypeName(inst[i]); - if (_mangleForCplusPlus) - instArgName = instArgName.Replace("::", "_"); - if (i > 0) - sb.Append("__"); - sb.Append(instArgName); - } - - sb.Append(ExitNameScopeSequence); - - utf8MangledName = sb.ToUtf8String(); - } - else - { - var typicalMethodDefinition = method.GetTypicalMethodDefinition(); - if (typicalMethodDefinition != method) - { - // Method on an instantiated type - utf8MangledName = GetUnqualifiedMangledMethodName(typicalMethodDefinition); - } - else if (method is IPrefixMangledMethod) - { - utf8MangledName = GetPrefixMangledMethodName((IPrefixMangledMethod)method); - } - else if (method is IPrefixMangledType) - { - utf8MangledName = GetPrefixMangledTypeName((IPrefixMangledType)method); - } - else if (method is IPrefixMangledSignature) - { - utf8MangledName = GetPrefixMangledSignatureName((IPrefixMangledSignature)method); - } - else - { - // Assume that Name is unique for all other methods - utf8MangledName = new Utf8String(SanitizeName(method.Name)); - } - } - - // Unless we're doing CPP mangling, there's no point in caching the unqualified - // method name. We only needed it to construct the fully qualified name. Nobody - // is going to ask for the unqualified name again. - if (_mangleForCplusPlus) - { - lock (this) - { - if (!_unqualifiedMangledMethodNames.ContainsKey(method)) - _unqualifiedMangledMethodNames = _unqualifiedMangledMethodNames.Add(method, utf8MangledName); - } - } - - return utf8MangledName; - } - - private ImmutableDictionary _mangledFieldNames = ImmutableDictionary.Empty; - - public override Utf8String GetMangledFieldName(FieldDesc field) - { - Utf8String mangledName; - if (_mangledFieldNames.TryGetValue(field, out mangledName)) - return mangledName; - - return ComputeMangledFieldName(field); - } - - private Utf8String ComputeMangledFieldName(FieldDesc field) - { - string prependTypeName = null; - if (!_mangleForCplusPlus) - prependTypeName = GetMangledTypeName(field.OwningType); - - if (field is EcmaField) - { - var deduplicator = new HashSet(); - - // Add consistent names for all fields of the type, independent on the order in which - // they are compiled - lock (this) - { - if (!_mangledFieldNames.ContainsKey(field)) - { - foreach (var f in field.OwningType.GetFields()) - { - string name = SanitizeName(f.Name); - - name = DisambiguateName(name, deduplicator); - deduplicator.Add(name); - - if (prependTypeName != null) - name = prependTypeName + "__" + name; - - _mangledFieldNames = _mangledFieldNames.Add(f, name); - } - } - } - - return _mangledFieldNames[field]; - } - - - string mangledName = SanitizeName(field.Name); - - if (prependTypeName != null) - mangledName = prependTypeName + "__" + mangledName; - - Utf8String utf8MangledName = new Utf8String(mangledName); - - lock (this) - { - if (!_mangledFieldNames.ContainsKey(field)) - _mangledFieldNames = _mangledFieldNames.Add(field, utf8MangledName); - } - - return utf8MangledName; - } - - private ImmutableDictionary _mangledStringLiterals = ImmutableDictionary.Empty; - - public override string GetMangledStringName(string literal) - { - string mangledName; - if (_mangledStringLiterals.TryGetValue(literal, out mangledName)) - return mangledName; - - mangledName = SanitizeNameWithHash(literal); - - lock (this) - { - if (!_mangledStringLiterals.ContainsKey(literal)) - _mangledStringLiterals = _mangledStringLiterals.Add(literal, mangledName); - } - - return mangledName; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs deleted file mode 100644 index 4287b78b032..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs +++ /dev/null @@ -1,122 +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 System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using ILCompiler.DependencyAnalysisFramework; -using Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - public interface IHasStartSymbol - { - ObjectAndOffsetSymbolNode StartSymbol { get; } - } - - /// - /// Represents an array of nodes. The contents of this node will be emitted - /// by placing a starting symbol, followed by contents of nodes (optionally - /// sorted using provided comparer), followed by ending symbol. - /// - public class ArrayOfEmbeddedDataNode : EmbeddedDataContainerNode, IHasStartSymbol - where TEmbedded : EmbeddedObjectNode - { - private HashSet _nestedNodes = new HashSet(); - private List _nestedNodesList = new List(); - private IComparer _sorter; - - public ArrayOfEmbeddedDataNode(string startSymbolMangledName, string endSymbolMangledName, IComparer nodeSorter) : base(startSymbolMangledName, endSymbolMangledName) - { - _sorter = nodeSorter; - } - - public void AddEmbeddedObject(TEmbedded symbol) - { - lock (_nestedNodes) - { - if (_nestedNodes.Add(symbol)) - { - _nestedNodesList.Add(symbol); - } - symbol.ContainingNode = this; - } - } - - protected override string GetName(NodeFactory factory) => $"Region {StartSymbol.GetMangledName(factory.NameMangler)}"; - - public override ObjectNodeSection Section => ObjectNodeSection.DataSection; - public override bool IsShareable => false; - - public override bool StaticDependenciesAreComputed => true; - - protected IEnumerable NodesList => _nestedNodesList; - private TEmbedded _nextElementToEncode; - public TEmbedded NextElementToEncode => _nextElementToEncode; - - protected virtual void GetElementDataForNodes(ref ObjectDataBuilder builder, NodeFactory factory, bool relocsOnly) - { - int index = 0; - _nextElementToEncode = null; - for (int i = 0; i < _nestedNodesList.Count; i++) - { - TEmbedded node = _nestedNodesList[i]; - if ((i + 1) < _nestedNodesList.Count) - _nextElementToEncode = _nestedNodesList[i + 1]; - else - _nextElementToEncode = null; - - if (!relocsOnly) - { - node.InitializeOffsetFromBeginningOfArray(builder.CountBytes); - node.InitializeIndexFromBeginningOfArray(index++); - } - - node.EncodeData(ref builder, factory, relocsOnly); - if (node is ISymbolDefinitionNode symbolDef) - { - builder.AddSymbol(symbolDef); - } - } - } - - public override ObjectData GetData(NodeFactory factory, bool relocsOnly) - { - ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); - builder.RequireInitialPointerAlignment(); - - if (_sorter != null) - _nestedNodesList.Sort(_sorter); - - builder.AddSymbol(StartSymbol); - - GetElementDataForNodes(ref builder, factory, relocsOnly); - - EndSymbol.SetSymbolOffset(builder.CountBytes); - builder.AddSymbol(EndSymbol); - - ObjectData objData = builder.ToObjectData(); - return objData; - } - - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) - { - return _nestedNodesList.Count == 0; - } - - protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) - { - DependencyList dependencies = new DependencyList(); - dependencies.Add(StartSymbol, "StartSymbol"); - dependencies.Add(EndSymbol, "EndSymbol"); - - return dependencies; - } - - protected internal override int Phase => (int)ObjectNodePhase.Ordered; - - public override int ClassCode => (int)ObjectNodeOrder.ArrayOfEmbeddedDataNode; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedPointersNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedPointersNode.cs deleted file mode 100644 index ed4ce4a7281..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ArrayOfEmbeddedPointersNode.cs +++ /dev/null @@ -1,135 +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 System.Collections.Generic; - -using Internal.Text; - -namespace ILCompiler.DependencyAnalysis -{ - interface ISimpleEmbeddedPointerIndirectionNode - where TTarget : ISortableSymbolNode - { - TTarget Target { get; } - } - - /// - /// Represents an array of pointers to symbols. is the type - /// of node each pointer within the vector points to. - /// - public sealed class ArrayOfEmbeddedPointersNode : ArrayOfEmbeddedDataNode> - where TTarget : ISortableSymbolNode - { - private int _nextId; - private string _startSymbolMangledName; - - /// - /// Provides a callback mechanism for notification when an EmbeddedPointerIndirectionNode is marked and added to the - /// parent ArrayOfEmbeddedPointersNode's internal list - /// - public delegate void OnMarkedDelegate(EmbeddedPointerIndirectionNode embeddedObject); - - public ArrayOfEmbeddedPointersNode(string startSymbolMangledName, string endSymbolMangledName, IComparer> nodeSorter) - : base( - startSymbolMangledName, - endSymbolMangledName, - nodeSorter) - { - _startSymbolMangledName = startSymbolMangledName; - } - - public EmbeddedObjectNode NewNode(TTarget target) - { - return new SimpleEmbeddedPointerIndirectionNode(this, target); - } - - public EmbeddedObjectNode NewNodeWithSymbol(TTarget target) - { - return new EmbeddedPointerIndirectionWithSymbolNode(this, target, GetNextId()); - } - - int GetNextId() - { - return System.Threading.Interlocked.Increment(ref _nextId); - } - - protected internal override int Phase => (int)ObjectNodePhase.Ordered; - - public override int ClassCode => (int)ObjectNodeOrder.ArrayOfEmbeddedPointersNode; - - public class PointerIndirectionNodeComparer : IComparer> - { - private IComparer _innerComparer; - - public PointerIndirectionNodeComparer(IComparer innerComparer) - { - _innerComparer = innerComparer; - } - - public int Compare(EmbeddedPointerIndirectionNode x, EmbeddedPointerIndirectionNode y) - { - return _innerComparer.Compare(x.Target, y.Target); - } - } - - private class SimpleEmbeddedPointerIndirectionNode : EmbeddedPointerIndirectionNode, ISimpleEmbeddedPointerIndirectionNode - { - protected ArrayOfEmbeddedPointersNode _parentNode; - - public SimpleEmbeddedPointerIndirectionNode(ArrayOfEmbeddedPointersNode futureParent, TTarget target) - : base(target) - { - _parentNode = futureParent; - } - - protected override string GetName(NodeFactory factory) => $"Embedded pointer to {Target.GetMangledName(factory.NameMangler)}"; - - protected override void OnMarked(NodeFactory factory) - { - // We don't want the child in the parent collection unless it's necessary. - // Only when this node gets marked, the parent node becomes the actual parent. - _parentNode.AddEmbeddedObject(this); - } - - public override IEnumerable GetStaticDependencies(NodeFactory factory) - { - return new[] - { - new DependencyListEntry(Target, "reloc"), - new DependencyListEntry(_parentNode, "Pointer region") - }; - } - - public override int ClassCode => -66002498; - - public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) - { - var otherNode = (ISimpleEmbeddedPointerIndirectionNode)other; - return comparer.Compare(Target, otherNode.Target); - } - } - - private class EmbeddedPointerIndirectionWithSymbolNode : SimpleEmbeddedPointerIndirectionNode, ISymbolDefinitionNode - { - private int _id; - - public EmbeddedPointerIndirectionWithSymbolNode(ArrayOfEmbeddedPointersNode futureParent, TTarget target, int id) - : base(futureParent, target) - { - _id = id; - } - - - int ISymbolNode.Offset => 0; - - int ISymbolDefinitionNode.Offset => OffsetFromBeginningOfArray; - - public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) - { - sb.Append(nameMangler.CompilationUnitPrefix).Append(_parentNode._startSymbolMangledName).Append("_").Append(_id.ToStringInvariant()); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs deleted file mode 100644 index e0bd6d7c5cf..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs +++ /dev/null @@ -1,82 +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.TypeSystem; - -using Internal.Text; - -namespace ILCompiler.DependencyAnalysis -{ - public abstract class AssemblyStubNode : ObjectNode, ISymbolDefinitionNode - { - public AssemblyStubNode() - { - } - - /// - /// Gets a value indicating whether the stub's address is visible from managed code - /// and could be a target of a managed calli. - /// - protected virtual bool IsVisibleFromManagedCode => true; - - public override ObjectNodeSection Section => ObjectNodeSection.TextSection; - - public override bool StaticDependenciesAreComputed => true; - - public abstract void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb); - public int Offset => 0; - public override bool IsShareable => false; - - public override ObjectData GetData(NodeFactory factory, bool relocsOnly) - { - // If the address is expected to be visible from managed code, we need to align - // at the managed code boundaries to prevent the stub from being confused with - // a fat fuction pointer. Otherwise we can align tighter. - int alignment = IsVisibleFromManagedCode ? - factory.Target.MinimumFunctionAlignment : - factory.Target.MinimumCodeAlignment; - - switch (factory.Target.Architecture) - { - case TargetArchitecture.X64: - X64.X64Emitter x64Emitter = new X64.X64Emitter(factory, relocsOnly); - EmitCode(factory, ref x64Emitter, relocsOnly); - x64Emitter.Builder.RequireInitialAlignment(alignment); - x64Emitter.Builder.AddSymbol(this); - return x64Emitter.Builder.ToObjectData(); - - case TargetArchitecture.X86: - X86.X86Emitter x86Emitter = new X86.X86Emitter(factory, relocsOnly); - EmitCode(factory, ref x86Emitter, relocsOnly); - x86Emitter.Builder.RequireInitialAlignment(alignment); - x86Emitter.Builder.AddSymbol(this); - return x86Emitter.Builder.ToObjectData(); - - case TargetArchitecture.ARM: - ARM.ARMEmitter armEmitter = new ARM.ARMEmitter(factory, relocsOnly); - EmitCode(factory, ref armEmitter, relocsOnly); - armEmitter.Builder.RequireInitialAlignment(alignment); - armEmitter.Builder.AddSymbol(this); - return armEmitter.Builder.ToObjectData(); - - case TargetArchitecture.ARM64: - ARM64.ARM64Emitter arm64Emitter = new ARM64.ARM64Emitter(factory, relocsOnly); - EmitCode(factory, ref arm64Emitter, relocsOnly); - arm64Emitter.Builder.RequireInitialAlignment(alignment); - arm64Emitter.Builder.AddSymbol(this); - return arm64Emitter.Builder.ToObjectData(); - - default: - throw new NotImplementedException(); - } - } - - protected abstract void EmitCode(NodeFactory factory, ref X64.X64Emitter instructionEncoder, bool relocsOnly); - protected abstract void EmitCode(NodeFactory factory, ref X86.X86Emitter instructionEncoder, bool relocsOnly); - protected abstract void EmitCode(NodeFactory factory, ref ARM.ARMEmitter instructionEncoder, bool relocsOnly); - protected abstract void EmitCode(NodeFactory factory, ref ARM64.ARM64Emitter instructionEncoder, bool relocsOnly); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/BlobNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/BlobNode.cs deleted file mode 100644 index 083de9bded8..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/BlobNode.cs +++ /dev/null @@ -1,53 +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.Text; -using Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - public class BlobNode : ObjectNode, ISymbolDefinitionNode - { - private Utf8String _name; - private ObjectNodeSection _section; - private byte[] _data; - private int _alignment; - - public BlobNode(Utf8String name, ObjectNodeSection section, byte[] data, int alignment) - { - _name = name; - _section = section; - _data = data; - _alignment = alignment; - } - - public override ObjectNodeSection Section => _section; - public override bool StaticDependenciesAreComputed => true; - - public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) - { - sb.Append(_name); - } - public int Offset => 0; - public override bool IsShareable => true; - - public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) - { - return new ObjectData(_data, Array.Empty(), _alignment, new ISymbolDefinitionNode[] { this }); - } - - protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); - -#if !SUPPORT_JIT - public override int ClassCode => -470351029; - - public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) - { - return _name.CompareTo(((BlobNode)other)._name); - } -#endif - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/CompilerComparer.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/CompilerComparer.cs deleted file mode 100644 index 250b327077e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/CompilerComparer.cs +++ /dev/null @@ -1,42 +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 System.Diagnostics; -using System.Collections.Generic; - -using Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - public class CompilerComparer : TypeSystemComparer, IComparer - { - public int Compare(ISortableNode x, ISortableNode y) - { - if (x == y) - { - return 0; - } - - int codeX = x.ClassCode; - int codeY = y.ClassCode; - if (codeX == codeY) - { - Debug.Assert(x.GetType() == y.GetType()); - - int result = x.CompareToImpl(y, this); - - // We did a reference equality check above so an "Equal" result is not expected - Debug.Assert(result != 0); - - return result; - } - else - { - Debug.Assert(x.GetType() != y.GetType()); - return codeY > codeX ? -1 : 1; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedDataContainerNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedDataContainerNode.cs deleted file mode 100644 index 0cffffac19b..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedDataContainerNode.cs +++ /dev/null @@ -1,36 +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 Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - /// - /// Represents a node that contains a set of embedded objects. The main function is - /// to serve as a base class, providing symbol name boundaries and node ordering. - /// - public abstract class EmbeddedDataContainerNode : ObjectNode - { - private ObjectAndOffsetSymbolNode _startSymbol; - private ObjectAndOffsetSymbolNode _endSymbol; - private string _startSymbolMangledName; - - public ObjectAndOffsetSymbolNode StartSymbol => _startSymbol; - public ObjectAndOffsetSymbolNode EndSymbol => _endSymbol; - - protected EmbeddedDataContainerNode(string startSymbolMangledName, string endSymbolMangledName) - { - _startSymbolMangledName = startSymbolMangledName; - _startSymbol = new ObjectAndOffsetSymbolNode(this, 0, startSymbolMangledName, true); - _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, endSymbolMangledName, true); - } - - public override int ClassCode => -1410622237; - - public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) - { - return _startSymbolMangledName.CompareTo(((EmbeddedDataContainerNode)other)._startSymbolMangledName); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedObjectNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedObjectNode.cs deleted file mode 100644 index 0db837e0c9d..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedObjectNode.cs +++ /dev/null @@ -1,70 +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.Collections.Generic; - -using ILCompiler.DependencyAnalysisFramework; - -using Debug = System.Diagnostics.Debug; - -namespace ILCompiler.DependencyAnalysis -{ - public abstract class EmbeddedObjectNode : SortableDependencyNode - { - private const int InvalidOffset = int.MinValue; - - private int _offset; - private int _index; - - public IHasStartSymbol ContainingNode { get; set; } - - public EmbeddedObjectNode() - { - _offset = InvalidOffset; - _index = InvalidOffset; - } - - public int OffsetFromBeginningOfArray - { - get - { - Debug.Assert(_offset != InvalidOffset); - return _offset; - } - } - - public int IndexFromBeginningOfArray - { - get - { - Debug.Assert(_index != InvalidOffset); - return _index; - } - } - - public void InitializeOffsetFromBeginningOfArray(int offset) - { - Debug.Assert(_offset == InvalidOffset || _offset == offset); - _offset = offset; - } - - public void InitializeIndexFromBeginningOfArray(int index) - { - Debug.Assert(_index == InvalidOffset || _index == index); - _index = index; - } - - public virtual bool IsShareable => false; - public virtual bool RepresentsIndirectionCell => false; - - public override bool InterestingForDynamicDependencyAnalysis => false; - public override bool HasDynamicDependencies => false; - public override bool HasConditionalStaticDependencies => false; - - public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; - public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; - - public abstract void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs deleted file mode 100644 index 5488801a39f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs +++ /dev/null @@ -1,52 +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 System.Collections.Generic; - -using Internal.Text; - -namespace ILCompiler.DependencyAnalysis -{ - /// - /// An whose sole value is a pointer to a different . - /// represents the node type this pointer points to. - /// - public abstract class EmbeddedPointerIndirectionNode : EmbeddedObjectNode, ISortableSymbolNode - where TTarget : ISortableSymbolNode - { - private TTarget _targetNode; - - /// - /// Target symbol this node points to. - /// - public TTarget Target => _targetNode; - - protected internal EmbeddedPointerIndirectionNode(TTarget target) - { - _targetNode = target; - } - - public override bool StaticDependenciesAreComputed => true; - - public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly) - { - dataBuilder.RequireInitialPointerAlignment(); - dataBuilder.EmitPointerReloc(Target); - } - - // At minimum, Target needs to be reported as a static dependency by inheritors. - public abstract override IEnumerable GetStaticDependencies(NodeFactory factory); - - int ISymbolNode.Offset => 0; - - public virtual void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) - { - sb.Append("_embedded_ptr_"); - Target.AppendMangledName(nameMangler, sb); - } - - public override int ClassCode => -2055384490; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/IMethodBodyNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/IMethodBodyNode.cs deleted file mode 100644 index b862f59b49f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/IMethodBodyNode.cs +++ /dev/null @@ -1,13 +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. - -namespace ILCompiler.DependencyAnalysis -{ - /// - /// Marker interface that identifies the node representing a compiled method body. - /// - public interface IMethodBodyNode : IMethodNode - { - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/IMethodNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/IMethodNode.cs deleted file mode 100644 index 393ee4adf54..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/IMethodNode.cs +++ /dev/null @@ -1,16 +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 Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - /// - /// A dependency analysis node that represents a method. - /// - public interface IMethodNode : ISortableSymbolNode - { - MethodDesc Method { get; } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs deleted file mode 100644 index c1b293b020e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs +++ /dev/null @@ -1,76 +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; - -namespace ILCompiler.DependencyAnalysis -{ - [Flags] - public enum FrameInfoFlags - { - Handler = 0x01, - Filter = 0x02, - - HasEHInfo = 0x04, - ReversePInvoke = 0x08, - HasAssociatedData = 0x10, - } - - public struct FrameInfo - { - public readonly FrameInfoFlags Flags; - public readonly int StartOffset; - public readonly int EndOffset; - public readonly byte[] BlobData; - - public FrameInfo(FrameInfoFlags flags, int startOffset, int endOffset, byte[] blobData) - { - Flags = flags; - StartOffset = startOffset; - EndOffset = endOffset; - BlobData = blobData; - } - } - - public struct DebugEHClauseInfo - { - public uint TryOffset; - public uint TryLength; - public uint HandlerOffset; - public uint HandlerLength; - - public DebugEHClauseInfo(uint tryOffset, uint tryLength, uint handlerOffset, uint handlerLength) - { - TryOffset = tryOffset; - TryLength = tryLength; - HandlerOffset = handlerOffset; - HandlerLength = handlerLength; - } - } - - public interface INodeWithCodeInfo - { - FrameInfo[] FrameInfos - { - get; - } - - byte[] GCInfo - { - get; - } - - DebugEHClauseInfo[] DebugEHClauseInfos - { - get; - } - - ObjectNode.ObjectData EHInfo - { - get; - } - - ISymbolNode GetAssociatedDataNode(NodeFactory factory); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/INodeWithRuntimeDeterminedDependencies.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/INodeWithRuntimeDeterminedDependencies.cs deleted file mode 100644 index 9969bba84a9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/INodeWithRuntimeDeterminedDependencies.cs +++ /dev/null @@ -1,24 +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.Collections.Generic; - -using Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - using DependencyListEntry = DependencyAnalysisFramework.DependencyNodeCore.DependencyListEntry; - - /// - /// Represents a node whose dependencies are runtime determined (they depend on the generic context) - /// and which provides means to compute concrete dependencies when given the generic context. - /// - public interface INodeWithRuntimeDeterminedDependencies - { - /// - /// Instantiates runtime determined dependencies of this node using the supplied generic context. - /// - IEnumerable InstantiateDependencies(NodeFactory factory, Instantiation typeInstantiation, Instantiation methodInstantiation); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ISortableNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ISortableNode.cs deleted file mode 100644 index ac62439b072..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ISortableNode.cs +++ /dev/null @@ -1,23 +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. - -namespace ILCompiler.DependencyAnalysis -{ - public interface ISortableNode - { -#if !SUPPORT_JIT - /// - /// Gets an identifier that is the same for all instances of this - /// descendant, but different from the of any other descendant. - /// - /// - /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". - /// If two manage to conflict (which is pretty unlikely), just make a new one... - /// - int ClassCode { get; } - - int CompareToImpl(ISortableNode other, CompilerComparer comparer); -#endif - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ISymbolNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ISymbolNode.cs deleted file mode 100644 index feca8b45e2f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ISymbolNode.cs +++ /dev/null @@ -1,97 +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 ILCompiler.DependencyAnalysisFramework; -using Internal.Text; - -namespace ILCompiler.DependencyAnalysis -{ - /// - /// Represents a reference to a symbol. The reference can potentially be offset by a value. - /// - public interface ISymbolNode : IDependencyNode - { - /// - /// Appends the mangled name of the symbol to the string builder provided. - /// - void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb); - - /// - /// Gets the offset (delta) from the symbol this references. - /// - int Offset { get; } - - /// - /// Set the return value of this property to true to indicate that this symbol - /// is an indirection cell to data that is needed, not the actual data itself. - /// Most commonly affects the code generation which accesses symbols such - /// Types which may require an indirection to access or not. - /// - bool RepresentsIndirectionCell { get; } - } - - /// - /// Represents a symbol backed by a different symbol for object emission purposes. - /// - public interface ISymbolNodeWithLinkage : ISymbolNode - { - /// - /// Return a node that is used for linkage - /// - ISymbolNode NodeForLinkage(NodeFactory factory); - } - - public interface ISortableSymbolNode : ISymbolNode, ISortableNode - { - } - - - /// - /// Represents a definition of a symbol within an . The symbol will be defined - /// at the specified offset from the beginning of the that reports this as one of - /// the symbols it defines. - /// - public interface ISymbolDefinitionNode : ISymbolNode - { - /// - /// Gets the offset (delta) from the beginning of the where this symbol should - /// be defined. Note this is different from , which is the offset to be - /// used when referencing the symbol. - /// - /// - /// Most node types will want to implement both and - /// to return 0. The name was chosen to make this convenient. If an object node implements this interface, - /// it will pretty much always want to either implement both as returning 0, or *one of them* to return - /// a non-zero value. - /// Some examples: an EEType node defines the symbol of the EEType in the middle of the object node, - /// since EETypes are prefixed by a GCDesc structure (that is not considered the beginning of the EEType). - /// This means that will return a non-zero value. When referencing the EEType by its - /// symbol, the GCDesc was already accounted for when the symbol was defined, so we want the - /// to be zero. - /// - new int Offset { get; } - } - - public static class ISymbolNodeExtensions - { - [ThreadStatic] - static Utf8StringBuilder s_cachedUtf8StringBuilder; - - public static string GetMangledName(this ISymbolNode symbolNode, NameMangler nameMangler) - { - Utf8StringBuilder sb = s_cachedUtf8StringBuilder; - if (sb == null) - sb = new Utf8StringBuilder(); - - symbolNode.AppendMangledName(nameMangler, sb); - string ret = sb.ToString(); - - sb.Clear(); - s_cachedUtf8StringBuilder = sb; - - return ret; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectAndOffsetSymbolNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectAndOffsetSymbolNode.cs deleted file mode 100644 index fb6652ff359..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectAndOffsetSymbolNode.cs +++ /dev/null @@ -1,61 +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 System.Collections.Generic; - -using ILCompiler.DependencyAnalysisFramework; - -using Internal.Text; - -namespace ILCompiler.DependencyAnalysis -{ - public class ObjectAndOffsetSymbolNode : DependencyNodeCore, ISymbolDefinitionNode - { - private ObjectNode _object; - private int _offset; - private Utf8String _name; - private bool _includeCompilationUnitPrefix; - - public ObjectAndOffsetSymbolNode(ObjectNode obj, int offset, Utf8String name, bool includeCompilationUnitPrefix) - { - _object = obj; - _offset = offset; - _name = name; - _includeCompilationUnitPrefix = includeCompilationUnitPrefix; - } - - protected override string GetName(NodeFactory factory) => $"Symbol {_name.ToString()} at offset {_offset.ToStringInvariant()}"; - - public override bool HasConditionalStaticDependencies => false; - public override bool HasDynamicDependencies => false; - public override bool InterestingForDynamicDependencyAnalysis => false; - public override bool StaticDependenciesAreComputed => true; - - public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) - { - if (_includeCompilationUnitPrefix) - sb.Append(nameMangler.CompilationUnitPrefix); - sb.Append(_name); - } - - int ISymbolNode.Offset => 0; - int ISymbolDefinitionNode.Offset => _offset; - public bool RepresentsIndirectionCell => false; - - public void SetSymbolOffset(int offset) - { - _offset = offset; - } - - public ObjectNode Target => _object; - - public override IEnumerable GetStaticDependencies(NodeFactory factory) - { - return new DependencyListEntry[] { new DependencyListEntry(_object, "ObjectAndOffsetDependency") }; - } - - public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; - public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs deleted file mode 100644 index 3af6f173921..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs +++ /dev/null @@ -1,349 +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 System.Collections.Generic; -using Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace ILCompiler.DependencyAnalysis -{ - public struct ObjectDataBuilder -#if !READYTORUN - : Internal.Runtime.ITargetBinaryWriter -#endif - { - public ObjectDataBuilder(NodeFactory factory, bool relocsOnly) : this(factory.Target, relocsOnly) - { - } - - public ObjectDataBuilder(TargetDetails target, bool relocsOnly) - { - _target = target; - _data = new ArrayBuilder(); - _relocs = new ArrayBuilder(); - Alignment = 1; - _definedSymbols = new ArrayBuilder(); -#if DEBUG - _numReservations = 0; - _checkAllSymbolDependenciesMustBeMarked = !relocsOnly; -#endif - } - - private TargetDetails _target; - private ArrayBuilder _relocs; - private ArrayBuilder _data; - public int Alignment { get; private set; } - private ArrayBuilder _definedSymbols; - -#if DEBUG - private int _numReservations; - private bool _checkAllSymbolDependenciesMustBeMarked; -#endif - - public int CountBytes - { - get - { - return _data.Count; - } - } - - public int TargetPointerSize - { - get - { - return _target.PointerSize; - } - } - - /// - /// Raise the alignment requirement of this object to . This has no effect - /// if the alignment requirement is already larger than . - /// - public void RequireInitialAlignment(int align) - { - Alignment = Math.Max(align, Alignment); - } - - /// - /// Raise the alignment requirement of this object to the target pointer size. This has no effect - /// if the alignment requirement is already larger than a pointer size. - /// - public void RequireInitialPointerAlignment() - { - RequireInitialAlignment(_target.PointerSize); - } - - public void EmitByte(byte emit) - { - _data.Add(emit); - } - - public void EmitShort(short emit) - { - EmitByte((byte)(emit & 0xFF)); - EmitByte((byte)((emit >> 8) & 0xFF)); - } - - public void EmitUShort(ushort emit) - { - EmitByte((byte)(emit & 0xFF)); - EmitByte((byte)((emit >> 8) & 0xFF)); - } - - public void EmitInt(int emit) - { - EmitByte((byte)(emit & 0xFF)); - EmitByte((byte)((emit >> 8) & 0xFF)); - EmitByte((byte)((emit >> 16) & 0xFF)); - EmitByte((byte)((emit >> 24) & 0xFF)); - } - - public void EmitUInt(uint emit) - { - EmitByte((byte)(emit & 0xFF)); - EmitByte((byte)((emit >> 8) & 0xFF)); - EmitByte((byte)((emit >> 16) & 0xFF)); - EmitByte((byte)((emit >> 24) & 0xFF)); - } - - public void EmitLong(long emit) - { - EmitByte((byte)(emit & 0xFF)); - EmitByte((byte)((emit >> 8) & 0xFF)); - EmitByte((byte)((emit >> 16) & 0xFF)); - EmitByte((byte)((emit >> 24) & 0xFF)); - EmitByte((byte)((emit >> 32) & 0xFF)); - EmitByte((byte)((emit >> 40) & 0xFF)); - EmitByte((byte)((emit >> 48) & 0xFF)); - EmitByte((byte)((emit >> 56) & 0xFF)); - } - - public void EmitNaturalInt(int emit) - { - if (_target.PointerSize == 8) - { - EmitLong(emit); - } - else - { - Debug.Assert(_target.PointerSize == 4); - EmitInt(emit); - } - } - - public void EmitHalfNaturalInt(short emit) - { - if (_target.PointerSize == 8) - { - EmitInt(emit); - } - else - { - Debug.Assert(_target.PointerSize == 4); - EmitShort(emit); - } - } - - public void EmitCompressedUInt(uint emit) - { - if (emit < 128) - { - EmitByte((byte)(emit * 2 + 0)); - } - else if (emit < 128 * 128) - { - EmitByte((byte)(emit * 4 + 1)); - EmitByte((byte)(emit >> 6)); - } - else if (emit < 128 * 128 * 128) - { - EmitByte((byte)(emit * 8 + 3)); - EmitByte((byte)(emit >> 5)); - EmitByte((byte)(emit >> 13)); - } - else if (emit < 128 * 128 * 128 * 128) - { - EmitByte((byte)(emit * 16 + 7)); - EmitByte((byte)(emit >> 4)); - EmitByte((byte)(emit >> 12)); - EmitByte((byte)(emit >> 20)); - } - else - { - EmitByte((byte)15); - EmitInt((int)emit); - } - } - - public void EmitBytes(byte[] bytes) - { - _data.Append(bytes); - } - - public void EmitBytes(byte[] bytes, int offset, int length) - { - _data.Append(bytes, offset, length); - } - - internal void EmitBytes(ArrayBuilder bytes) - { - _data.Append(bytes); - } - - public void EmitZeroPointer() - { - _data.ZeroExtend(_target.PointerSize); - } - - public void EmitZeros(int numBytes) - { - _data.ZeroExtend(numBytes); - } - - private Reservation GetReservationTicket(int size) - { -#if DEBUG - _numReservations++; -#endif - Reservation ticket = (Reservation)_data.Count; - _data.ZeroExtend(size); - return ticket; - } - - private int ReturnReservationTicket(Reservation reservation) - { -#if DEBUG - Debug.Assert(_numReservations > 0); - _numReservations--; -#endif - return (int)reservation; - } - - public Reservation ReserveByte() - { - return GetReservationTicket(1); - } - - public void EmitByte(Reservation reservation, byte emit) - { - int offset = ReturnReservationTicket(reservation); - _data[offset] = emit; - } - - public Reservation ReserveShort() - { - return GetReservationTicket(2); - } - - public void EmitShort(Reservation reservation, short emit) - { - int offset = ReturnReservationTicket(reservation); - _data[offset] = (byte)(emit & 0xFF); - _data[offset + 1] = (byte)((emit >> 8) & 0xFF); - } - - public Reservation ReserveInt() - { - return GetReservationTicket(4); - } - - public void EmitInt(Reservation reservation, int emit) - { - int offset = ReturnReservationTicket(reservation); - _data[offset] = (byte)(emit & 0xFF); - _data[offset + 1] = (byte)((emit >> 8) & 0xFF); - _data[offset + 2] = (byte)((emit >> 16) & 0xFF); - _data[offset + 3] = (byte)((emit >> 24) & 0xFF); - } - - public void EmitUInt(Reservation reservation, uint emit) - { - int offset = ReturnReservationTicket(reservation); - _data[offset] = (byte)(emit & 0xFF); - _data[offset + 1] = (byte)((emit >> 8) & 0xFF); - _data[offset + 2] = (byte)((emit >> 16) & 0xFF); - _data[offset + 3] = (byte)((emit >> 24) & 0xFF); - } - - public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0) - { -#if DEBUG - if (_checkAllSymbolDependenciesMustBeMarked) - { - var node = symbol as ILCompiler.DependencyAnalysisFramework.DependencyNodeCore; - if (node != null) - Debug.Assert(node.Marked); - } -#endif - - _relocs.Add(new Relocation(relocType, _data.Count, symbol)); - - // And add space for the reloc - switch (relocType) - { - case RelocType.IMAGE_REL_BASED_REL32: - case RelocType.IMAGE_REL_BASED_RELPTR32: - case RelocType.IMAGE_REL_BASED_ABSOLUTE: - case RelocType.IMAGE_REL_BASED_HIGHLOW: - case RelocType.IMAGE_REL_SECREL: - case RelocType.IMAGE_REL_BASED_ADDR32NB: - case RelocType.IMAGE_REL_SYMBOL_SIZE: - EmitInt(delta); - break; - case RelocType.IMAGE_REL_BASED_DIR64: - EmitLong(delta); - break; - case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: - case RelocType.IMAGE_REL_BASED_ARM64_BRANCH26: - case RelocType.IMAGE_REL_BASED_THUMB_MOV32: - case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21: - case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L: - // Do not vacate space for this kind of relocation, because - // the space is embedded in the instruction. - break; - default: - throw new NotImplementedException(); - } - } - - public void EmitPointerReloc(ISymbolNode symbol, int delta = 0) - { - EmitReloc(symbol, (_target.PointerSize == 8) ? RelocType.IMAGE_REL_BASED_DIR64 : RelocType.IMAGE_REL_BASED_HIGHLOW, delta); - } - - public ObjectNode.ObjectData ToObjectData() - { -#if DEBUG - Debug.Assert(_numReservations == 0); -#endif - - ObjectNode.ObjectData returnData = new ObjectNode.ObjectData(_data.ToArray(), - _relocs.ToArray(), - Alignment, - _definedSymbols.ToArray()); - - return returnData; - } - - public enum Reservation { } - - public void AddSymbol(ISymbolDefinitionNode node) - { - _definedSymbols.Add(node); - } - - public void PadAlignment(int align) - { - Debug.Assert((align == 2) || (align == 4) || (align == 8) || (align == 16)); - int misalignment = _data.Count & (align - 1); - if (misalignment != 0) - { - EmitZeros(align - misalignment); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectNode.cs deleted file mode 100644 index 21490cadc31..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectNode.cs +++ /dev/null @@ -1,88 +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 System.Collections.Generic; - -using ILCompiler.DependencyAnalysisFramework; -using Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - public abstract partial class ObjectNode : SortableDependencyNode - { - public class ObjectData - { - public ObjectData(byte[] data, Relocation[] relocs, int alignment, ISymbolDefinitionNode[] definedSymbols) - { - Data = data; - Relocs = relocs; - Alignment = alignment; - DefinedSymbols = definedSymbols; - } - - public readonly Relocation[] Relocs; - public readonly byte[] Data; - public readonly int Alignment; - public readonly ISymbolDefinitionNode[] DefinedSymbols; - } - - public virtual bool RepresentsIndirectionCell => false; - - public abstract ObjectData GetData(NodeFactory factory, bool relocsOnly = false); - - public abstract ObjectNodeSection Section { get; } - - /// - /// Should identical symbols emitted into separate object files be Comdat folded when linked together? - /// - public abstract bool IsShareable { get; } - - /// - /// Override this function to have a node which should be skipped when emitting - /// to the object file. (For instance, if there are two nodes describing the same - /// data structure, one of those nodes should return true here.) - /// - /// - /// - public virtual bool ShouldSkipEmittingObjectNode(NodeFactory factory) - { - return false; - } - - public override bool HasConditionalStaticDependencies => false; - public override bool HasDynamicDependencies => false; - public override bool InterestingForDynamicDependencyAnalysis => false; - - public sealed override IEnumerable GetStaticDependencies(NodeFactory factory) - { - DependencyList dependencies = ComputeNonRelocationBasedDependencies(factory); - Relocation[] relocs = GetData(factory, true).Relocs; - - if (relocs != null) - { - if (dependencies == null) - dependencies = new DependencyList(); - - foreach (Relocation reloc in relocs) - { - dependencies.Add(reloc.Target, "reloc"); - } - } - - if (dependencies == null) - return Array.Empty(); - else - return dependencies; - } - - protected virtual DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) - { - return null; - } - - public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; - public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs deleted file mode 100644 index 98829e5f30c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs +++ /dev/null @@ -1,57 +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; - -namespace ILCompiler.DependencyAnalysis -{ - public enum SectionType - { - ReadOnly, - Writeable, - Executable - } - - /// - /// Specifies the object file section a node will be placed in; ie "text" or "data" - /// - public class ObjectNodeSection - { - public string Name { get; } - public SectionType Type { get; } - public string ComdatName { get; } - - public ObjectNodeSection(string name, SectionType type, string comdatName) - { - Name = name; - Type = type; - ComdatName = comdatName; - } - - public ObjectNodeSection(string name, SectionType type) : this(name, type, null) - { } - - /// - /// Returns true if the section is a standard one (defined as text, data, or rdata currently) - /// - public bool IsStandardSection - { - get - { - return this == DataSection || this == ReadOnlyDataSection || this == FoldableReadOnlyDataSection || this == TextSection || this == XDataSection; - } - } - - public static readonly ObjectNodeSection XDataSection = new ObjectNodeSection("xdata", SectionType.ReadOnly); - public static readonly ObjectNodeSection DataSection = new ObjectNodeSection("data", SectionType.Writeable); - public static readonly ObjectNodeSection ReadOnlyDataSection = new ObjectNodeSection("rdata", SectionType.ReadOnly); - public static readonly ObjectNodeSection FoldableReadOnlyDataSection = new ObjectNodeSection("rdata$F", SectionType.ReadOnly); - public static readonly ObjectNodeSection TextSection = new ObjectNodeSection("text", SectionType.Executable); - public static readonly ObjectNodeSection TLSSection = new ObjectNodeSection("TLS", SectionType.Writeable); - public static readonly ObjectNodeSection ManagedCodeWindowsContentSection = new ObjectNodeSection(".managedcode$I", SectionType.Executable); - public static readonly ObjectNodeSection FoldableManagedCodeWindowsContentSection = new ObjectNodeSection(".managedcode$I", SectionType.Executable); - public static readonly ObjectNodeSection ManagedCodeUnixContentSection = new ObjectNodeSection("__managedcode", SectionType.Executable); - public static readonly ObjectNodeSection FoldableManagedCodeUnixContentSection = new ObjectNodeSection("__managedcode", SectionType.Executable); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Relocation.cs deleted file mode 100644 index f102131263f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Relocation.cs +++ /dev/null @@ -1,232 +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.Diagnostics; - -namespace ILCompiler.DependencyAnalysis -{ - public enum RelocType - { - IMAGE_REL_BASED_ABSOLUTE = 0x00, // No relocation required - IMAGE_REL_BASED_ADDR32NB = 0x02, // The 32-bit address without an image base (RVA) - IMAGE_REL_BASED_HIGHLOW = 0x03, // 32 bit address base - IMAGE_REL_BASED_THUMB_MOV32 = 0x07, // Thumb2: based MOVW/MOVT - IMAGE_REL_BASED_DIR64 = 0x0A, // 64 bit address base - IMAGE_REL_BASED_REL32 = 0x10, // 32-bit relative address from byte following reloc - IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, // Thumb2: based B, BL - IMAGE_REL_BASED_ARM64_BRANCH26 = 0x14, // Arm64: B, BL - IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc - // This is a special NGEN-specific relocation type - // for relative pointer (used to make NGen relocation - // section smaller) - IMAGE_REL_SECREL = 0x80, // 32 bit offset from base of section containing target - - IMAGE_REL_BASED_ARM64_PAGEBASE_REL21 = 0x81, // ADRP - IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A = 0x82, // ADD/ADDS (immediate) with zero shift, for page offset - IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L = 0x83, // LDR (indexed, unsigned immediate), for page offset - - // - // Relocations for R2R image production - // - IMAGE_REL_SYMBOL_SIZE = 0x1000, // The size of data in the image represented by the target symbol node - } - - public struct Relocation - { - public readonly RelocType RelocType; - public readonly int Offset; - public readonly ISymbolNode Target; - - //***************************************************************************** - // Extract the 16-bit immediate from ARM Thumb2 Instruction (format T2_N) - //***************************************************************************** - private static unsafe ushort GetThumb2Imm16(ushort* p) - { - uint Opcode0 = (uint)p[0]; - uint Opcode1 = (uint)p[1]; - uint Result = - ((Opcode0 << 12) & 0xf000) | - ((Opcode0 << 1) & 0x0800) | - ((Opcode1 >> 4) & 0x0700) | - ((Opcode1 >> 0) & 0x00ff); - return (ushort)Result; - } - - //***************************************************************************** - // Deposit the 16-bit immediate into ARM Thumb2 Instruction (format T2_N) - //***************************************************************************** - private static unsafe void PutThumb2Imm16(ushort* p, ushort imm16) - { - uint Opcode0 = (uint)p[0]; - uint Opcode1 = (uint)p[1]; - int val0 = (0xf000 >> 12); - int val1 = (0x0800 >> 1); - Opcode0 &= ~((uint)val0 | (uint)val1); - int val3 = (0x0700 << 4); - Opcode1 &= ~((uint)val3 | (0x00ff << 0)); - Opcode0 |= ((uint)imm16 & 0xf000) >> 12; - Opcode0 |= ((uint)imm16 & 0x0800) >> 1; - Opcode1 |= ((uint)imm16 & 0x0700) << 4; - Opcode1 |= ((uint)imm16 & 0x00ff) << 0; - p[0] = (ushort)Opcode0; - p[1] = (ushort)Opcode1; - } - - //***************************************************************************** - // Extract the 32-bit immediate from movw/movt sequence - //***************************************************************************** - private static unsafe int GetThumb2Mov32(ushort* p) - { - // Make sure we are decoding movw/movt sequence - ushort Opcode0 = *(p + 0); - ushort Opcode1 = *(p + 2); - Debug.Assert(((uint)Opcode0 & 0xFBF0) == 0xF240); - Debug.Assert(((uint)Opcode1 & 0xFBF0) == 0xF2C0); - - return (int)GetThumb2Imm16(p) + ((int)(GetThumb2Imm16(p + 2) << 16)); - } - - //***************************************************************************** - // Deposit the 32-bit immediate into movw/movt Thumb2 sequence - //***************************************************************************** - private static unsafe void PutThumb2Mov32(ushort* p, uint imm32) - { - // Make sure we are decoding movw/movt sequence - ushort Opcode0 = *(p + 0); - ushort Opcode1 = *(p + 2); - Debug.Assert(((uint)Opcode0 & 0xFBF0) == 0xF240); - Debug.Assert(((uint)Opcode1 & 0xFBF0) == 0xF2C0); - - ushort imm16 = (ushort)(imm32 & 0xffff); - PutThumb2Imm16(p, imm16); - imm16 = (ushort)(imm32 >> 16); - PutThumb2Imm16(p + 2, imm16); - - Debug.Assert((uint)GetThumb2Mov32(p) == imm32); - } - - //***************************************************************************** - // Extract the 24-bit rel offset from bl instruction - //***************************************************************************** - private static unsafe int GetThumb2BlRel24(ushort* p) - { - uint Opcode0 = (uint)p[0]; - uint Opcode1 = (uint)p[1]; - - uint S = Opcode0 >> 10; - uint J2 = Opcode1 >> 11; - uint J1 = Opcode1 >> 13; - - uint ret = - ((S << 24) & 0x1000000) | - (((J1 ^ S ^ 1) << 23) & 0x0800000) | - (((J2 ^ S ^ 1) << 22) & 0x0400000) | - ((Opcode0 << 12) & 0x03FF000) | - ((Opcode1 << 1) & 0x0000FFE); - - // Sign-extend and return - return (int)((ret << 7) >> 7); - } - - //***************************************************************************** - // Returns whether the offset fits into bl instruction - //***************************************************************************** - private static bool FitsInThumb2BlRel24(uint imm24) - { - return ((imm24 << 7) >> 7) == imm24; - } - - //***************************************************************************** - // Deposit the 24-bit rel offset into bl instruction - //***************************************************************************** - private static unsafe void PutThumb2BlRel24(ushort* p, uint imm24) - { - // Verify that we got a valid offset - Debug.Assert(FitsInThumb2BlRel24(imm24)); - - // Ensure that the ThumbBit is not set on the offset - // as it cannot be encoded. - Debug.Assert((imm24 & 1/*THUMB_CODE*/) == 0); - - uint Opcode0 = (uint)p[0]; - uint Opcode1 = (uint)p[1]; - Opcode0 &= 0xF800; - Opcode1 &= 0xD000; - - uint S = (imm24 & 0x1000000) >> 24; - uint J1 = ((imm24 & 0x0800000) >> 23) ^ S ^ 1; - uint J2 = ((imm24 & 0x0400000) >> 22) ^ S ^ 1; - - Opcode0 |= ((imm24 & 0x03FF000) >> 12) | (S << 10); - Opcode1 |= ((imm24 & 0x0000FFE) >> 1) | (J1 << 13) | (J2 << 11); - - p[0] = (ushort)Opcode0; - p[1] = (ushort)Opcode1; - - Debug.Assert((uint)GetThumb2BlRel24(p) == imm24); - } - - public Relocation(RelocType relocType, int offset, ISymbolNode target) - { - RelocType = relocType; - Offset = offset; - Target = target; - } - - public static unsafe void WriteValue(RelocType relocType, void* location, long value) - { - switch (relocType) - { - case RelocType.IMAGE_REL_BASED_ABSOLUTE: - case RelocType.IMAGE_REL_BASED_HIGHLOW: - case RelocType.IMAGE_REL_BASED_REL32: - case RelocType.IMAGE_REL_BASED_ADDR32NB: - case RelocType.IMAGE_REL_SYMBOL_SIZE: - *(int*)location = (int)value; - break; - case RelocType.IMAGE_REL_BASED_DIR64: - *(long*)location = value; - break; - case RelocType.IMAGE_REL_BASED_THUMB_MOV32: - PutThumb2Mov32((ushort*)location, (uint)value); - break; - case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: - PutThumb2BlRel24((ushort*)location, (uint)value); - break; - default: - Debug.Fail("Invalid RelocType: " + relocType); - break; - } - } - - public static unsafe long ReadValue(RelocType relocType, void* location) - { - switch (relocType) - { - case RelocType.IMAGE_REL_BASED_ABSOLUTE: - case RelocType.IMAGE_REL_BASED_ADDR32NB: - case RelocType.IMAGE_REL_BASED_HIGHLOW: - case RelocType.IMAGE_REL_BASED_REL32: - case RelocType.IMAGE_REL_BASED_RELPTR32: - case RelocType.IMAGE_REL_SECREL: - case RelocType.IMAGE_REL_SYMBOL_SIZE: - return *(int*)location; - case RelocType.IMAGE_REL_BASED_DIR64: - return *(long*)location; - case RelocType.IMAGE_REL_BASED_THUMB_MOV32: - return (long)GetThumb2Mov32((ushort*)location); - case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: - return (long)GetThumb2BlRel24((ushort*)location); - default: - Debug.Fail("Invalid RelocType: " + relocType); - return 0; - } - } - - public override string ToString() - { - return $"{Target} ({RelocType}, 0x{Offset:X})"; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ShadowConcreteMethodNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ShadowConcreteMethodNode.cs deleted file mode 100644 index 657e1100719..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/ShadowConcreteMethodNode.cs +++ /dev/null @@ -1,109 +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.Collections.Generic; - -using ILCompiler.DependencyAnalysisFramework; - -using Internal.Text; -using Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace ILCompiler.DependencyAnalysis -{ - /// - /// Represents a concrete method on a generic type (or a generic method) that doesn't - /// have code emitted in the executable because it's physically backed by a canonical - /// method body. The purpose of this node is to track the dependencies of the concrete - /// method body, as if it was generated. The node acts as a symbol for the canonical - /// method for convenience. - /// - public class ShadowConcreteMethodNode : DependencyNodeCore, IMethodNode, ISymbolNodeWithLinkage - { - /// - /// Gets the canonical method body that defines the dependencies of this node. - /// - public IMethodNode CanonicalMethodNode { get; } - - /// - /// Gets the concrete method represented by this node. - /// - public MethodDesc Method { get; } - - // Implementation of ISymbolNode that makes this node act as a symbol for the canonical body - public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) - { - CanonicalMethodNode.AppendMangledName(nameMangler, sb); - } - public int Offset => CanonicalMethodNode.Offset; - public bool RepresentsIndirectionCell => CanonicalMethodNode.RepresentsIndirectionCell; - - public override bool StaticDependenciesAreComputed - => CanonicalMethodNode.StaticDependenciesAreComputed; - - public ShadowConcreteMethodNode(MethodDesc method, IMethodNode canonicalMethod) - { - Debug.Assert(!method.IsSharedByGenericInstantiations); - Debug.Assert(!method.IsRuntimeDeterminedExactMethod); - Debug.Assert(canonicalMethod.Method.IsSharedByGenericInstantiations); - Debug.Assert(canonicalMethod.Method == method.GetCanonMethodTarget(CanonicalFormKind.Specific)); - Method = method; - CanonicalMethodNode = canonicalMethod; - } - - public ISymbolNode NodeForLinkage(NodeFactory factory) - { - return CanonicalMethodNode; - } - - public override IEnumerable GetStaticDependencies(NodeFactory factory) - { - DependencyList dependencies = new DependencyList(); - - // Make sure the canonical body gets generated - dependencies.Add(new DependencyListEntry(CanonicalMethodNode, "Canonical body")); - - // Instantiate the runtime determined dependencies of the canonical method body - // with the concrete instantiation of the method to get concrete dependencies. - Instantiation typeInst = Method.OwningType.Instantiation; - Instantiation methodInst = Method.Instantiation; - IEnumerable staticDependencies = CanonicalMethodNode.GetStaticDependencies(factory); - - if (staticDependencies != null) - { - foreach (DependencyListEntry canonDep in staticDependencies) - { - var runtimeDep = canonDep.Node as INodeWithRuntimeDeterminedDependencies; - if (runtimeDep != null) - { - dependencies.AddRange(runtimeDep.InstantiateDependencies(factory, typeInst, methodInst)); - } - } - } - - return dependencies; - } - - protected override string GetName(NodeFactory factory) => $"{Method.ToString()} backed by {CanonicalMethodNode.GetMangledName(factory.NameMangler)}"; - - public sealed override bool HasConditionalStaticDependencies => false; - public sealed override bool HasDynamicDependencies => false; - public sealed override bool InterestingForDynamicDependencyAnalysis => false; - - public sealed override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; - public sealed override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; - - int ISortableNode.ClassCode => -1440570971; - - int ISortableNode.CompareToImpl(ISortableNode other, CompilerComparer comparer) - { - var compare = comparer.Compare(Method, ((ShadowConcreteMethodNode)other).Method); - if (compare != 0) - return compare; - - return comparer.Compare(CanonicalMethodNode, ((ShadowConcreteMethodNode)other).CanonicalMethodNode); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs deleted file mode 100644 index 81aa110c9d4..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs +++ /dev/null @@ -1,192 +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 System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -using ILCompiler.DependencyAnalysisFramework; -using Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - public abstract class SortableDependencyNode : DependencyNodeCore, ISortableNode - { -#if !SUPPORT_JIT - /// - /// Allows grouping of instances such that all nodes in a lower phase - /// will be ordered before nodes in a later phase. - /// - protected internal virtual int Phase => (int)ObjectNodePhase.Unordered; - - /// - /// Gets an identifier that is the same for all instances of this - /// descendant, but different from the of any other descendant. - /// - /// - /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". - /// If two manage to conflict (which is pretty unlikely), just make a new one... - /// - public abstract int ClassCode { get; } - - // Note to implementers: the type of `other` is actually the same as the type of `this`. - public virtual int CompareToImpl(ISortableNode other, CompilerComparer comparer) - { - throw new NotImplementedException("Multiple nodes of this type are not supported"); - } - - protected enum ObjectNodePhase - { - /// - /// Nodes should only be placed in this phase if they have strict output ordering requirements that - /// affect compiler correctness. Today that includes native layout tables. - /// - Ordered, - Unordered - } - - protected enum ObjectNodeOrder - { - // - // The ordering of this sequence of nodes is deliberate and currently required for - // compiler correctness. - // - - // - // ReadyToRun Nodes - // - CorHeaderNode, - ReadyToRunHeaderNode, - ImportSectionsTableNode, - ImportSectionNode, - MethodEntrypointTableNode, - - - // - // CoreRT Nodes - // - MetadataNode, - ResourceDataNode, - ResourceIndexNode, - TypeMetadataMapNode, - ClassConstructorContextMap, - DynamicInvokeTemplateDataNode, - ReflectionInvokeMapNode, - DelegateMarshallingStubMapNode, - StructMarshallingStubMapNode, - ArrayMapNode, - ReflectionFieldMapNode, - NativeLayoutInfoNode, - ExactMethodInstantiationsNode, - GenericTypesHashtableNode, - GenericMethodsHashtableNode, - GenericVirtualMethodTableNode, - InterfaceGenericVirtualMethodTableNode, - GenericMethodsTemplateMap, - GenericTypesTemplateMap, - BlockReflectionTypeMapNode, - StaticsInfoHashtableNode, - ReflectionVirtualInvokeMapNode, - ArrayOfEmbeddedPointersNode, - DefaultConstructorMapNode, - ExternalReferencesTableNode, - StackTraceEmbeddedMetadataNode, - StackTraceMethodMappingNode, - ArrayOfEmbeddedDataNode, - WindowsDebugNeedTypeIndicesStoreNode, - WindowsDebugMethodSignatureMapSectionNode, - WindowsDebugTypeSignatureMapSectionNode, - WindowsDebugManagedNativeDictionaryInfoSectionNode, - WindowsDebugTypeRecordsSectionNode, - WindowsDebugPseudoAssemblySectionNode, - } - - public class EmbeddedObjectNodeComparer : IComparer - { - private CompilerComparer _comparer; - - public EmbeddedObjectNodeComparer(CompilerComparer comparer) - { - _comparer = comparer; - } - - public int Compare(EmbeddedObjectNode x, EmbeddedObjectNode y) - { - return CompareImpl(x, y, _comparer); - } - } - - /// - /// This comparer is used to sort the marked node list. We only care about ordering ObjectNodes - /// for emission into the binary, so any EmbeddedObjectNode or DependencyNodeCore objects are - /// skipped for efficiency. - /// - public class ObjectNodeComparer : IComparer> - { - private CompilerComparer _comparer; - - public ObjectNodeComparer(CompilerComparer comparer) - { - _comparer = comparer; - } - - public int Compare(DependencyNodeCore x1, DependencyNodeCore y1) - { - ObjectNode x = x1 as ObjectNode; - ObjectNode y = y1 as ObjectNode; - - if (x == y) - { - return 0; - } - - // Sort non-object nodes after ObjectNodes - if (x == null) - return 1; - - if (y == null) - return -1; - - return CompareImpl(x, y, _comparer); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CompareImpl(SortableDependencyNode x, SortableDependencyNode y, CompilerComparer comparer) - { - int phaseX = x.Phase; - int phaseY = y.Phase; - - if (phaseX == phaseY) - { - int codeX = x.ClassCode; - int codeY = y.ClassCode; - if (codeX == codeY) - { - Debug.Assert(x.GetType() == y.GetType() || - (x.GetType().IsConstructedGenericType && y.GetType().IsConstructedGenericType - && x.GetType().GetGenericTypeDefinition() == y.GetType().GetGenericTypeDefinition())); - - int result = x.CompareToImpl(y, comparer); - - // We did a reference equality check above so an "Equal" result is not expected - Debug.Assert(result != 0 || x == y); - - return result; - } - else - { - Debug.Assert(x.GetType() != y.GetType()); - return codeY > codeX ? -1 : 1; - } - } - else - { - return phaseX - phaseY; - } - } -#endif - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs deleted file mode 100644 index 535f13fce46..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs +++ /dev/null @@ -1,213 +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 System.Diagnostics; - -namespace ILCompiler.DependencyAnalysis.ARM -{ - public struct ARMEmitter - { - public ARMEmitter(NodeFactory factory, bool relocsOnly) - { - Builder = new ObjectDataBuilder(factory, relocsOnly); - TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem); - } - - public ObjectDataBuilder Builder; - public TargetRegisterMap TargetRegister; - - // check the value length - private static bool IsBitNumOverflow(int value, byte numBits) - { - return (value >> numBits) != 0; - } - - private static bool IsLowReg(Register reg) - { - return !IsBitNumOverflow((int)reg, 3); - } - - private static bool IsValidReg(Register reg) - { - return !IsBitNumOverflow((int)reg, 4); - } - - // mov reg, immediate - // reg range: [0..7] - // immediage range: [0..255] - public void EmitMOV(Register reg, int immediate) - { - Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); - Builder.EmitShort((short)(0x2000 + ((byte)reg << 8) + immediate)); - } - - // cmp reg, immediate - // reg range: [0..7] - // immediage range: [0..255] - public void EmitCMP(Register reg, int immediate) - { - Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); - Builder.EmitShort((short)(0x2800 + ((byte)reg << 8) + immediate)); - } - - // add reg, immediate - // reg range: [0..7] - // immediage range: [0..255] - public void EmitADD(Register reg, int immediate) - { - Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); - Builder.EmitShort((short)(0x3000 + ((byte)reg << 8) + immediate)); - } - - // sub reg, immediate - // reg range: [0..7] - // immediage range: [0..255] - public void EmitSUB(Register reg, int immediate) - { - Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); - Builder.EmitShort((short)(0x3800 + ((byte)reg << 8) + immediate)); - } - - // nop - public void EmitNOP() - { - Builder.EmitByte(0x00); - Builder.EmitByte(0xbf); - } - - // __debugbreak - public void EmitDebugBreak() - { - Builder.EmitByte(0xde); - Builder.EmitByte(0xfe); - } - - // push reg - // reg range: [0..12, LR] - public void EmitPUSH(Register reg) - { - Debug.Assert(reg >= Register.R0 && (reg <= Register.R12 || reg == TargetRegister.LR)); - Builder.EmitByte(0x4d); - Builder.EmitByte(0xf8); - Builder.EmitShort((short)(0x0d04 + ((byte)reg << 12))); - } - - // pop reg - // reg range: [0..12, LR, PC] - public void EmitPOP(Register reg) - { - Debug.Assert(IsValidReg(reg) && reg != TargetRegister.SP); - Builder.EmitByte(0x5d); - Builder.EmitByte(0xf8); - Builder.EmitShort((short)(0x0b04 + ((byte)reg << 12))); - } - - // mov reg, reg - // reg range: [0..PC] - public void EmitMOV(Register destination, Register source) - { - Debug.Assert(IsValidReg(destination) && IsValidReg(source)); - Builder.EmitShort((short)(0x4600 + (((byte)destination & 0x8) << 4) + (((byte)source & 0x8) << 3) + (((byte)source & 0x7) << 3) + ((byte)destination & 0x7))); - } - - // ldr reg, [reg] - // reg range: [0..7] - public void EmitLDR(Register destination, Register source) - { - Debug.Assert(IsLowReg(destination) && IsLowReg(source)); - Builder.EmitShort((short)(0x6800 + (((byte)source & 0x7) << 3) + ((byte)destination & 0x7))); - } - - // ldr.w reg, [reg, #offset] - // reg range: [0..PC] - // offset range: [-255..4095] - public void EmitLDR(Register destination, Register source, int offset) - { - Debug.Assert(IsValidReg(destination) && IsValidReg(source)); - Debug.Assert(offset >= -255 && offset <= 4095); - if (offset >= 0) - { - Builder.EmitShort((short)(0xf8d0 + ((byte)(source)))); - Builder.EmitShort((short)(offset + (((byte)destination) << 12))); - } - else - { - Builder.EmitShort((short)(0xf850 + ((byte)(source)))); - Builder.EmitShort((short)(-offset + (((byte)destination) << 12) + (((byte)12) << 8))); - } - } - - // movw reg, [reloc] & 0x0000FFFF - // movt reg, [reloc] & 0xFFFF0000 - // reg range: [0..12, LR] - public void EmitMOV(Register destination, ISymbolNode symbol) - { - Debug.Assert(destination >= Register.R0 && (destination <= Register.R12 || destination == TargetRegister.LR)); - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_THUMB_MOV32); - Builder.EmitShort(unchecked((short)0xf240)); - Builder.EmitShort((short)((byte)destination << 8)); - Builder.EmitShort(unchecked((short)0xf2c0)); - Builder.EmitShort((short)((byte)destination << 8)); - } - - // b.w symbol - public void EmitJMP(ISymbolNode symbol) - { - Debug.Assert(!symbol.RepresentsIndirectionCell); - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_THUMB_BRANCH24); - Builder.EmitByte(0); - Builder.EmitByte(0xF0); - Builder.EmitByte(0); - Builder.EmitByte(0xB8); - } - - // bx reg - // reg range: [0..PC] - public void EmitJMP(Register destination) - { - Debug.Assert(IsValidReg(destination)); - Builder.EmitShort((short)(0x4700 + ((byte)destination << 3))); - } - - // bx lr - public void EmitRET() - { - EmitJMP(TargetRegister.LR); - } - - // bne #offset - // offset range: [-256..254] - public void EmitBNE(int immediate) - { - Debug.Assert(immediate >= -256 && immediate <= 254); - // considering the pipeline with PC - immediate -= 4; - - Builder.EmitByte((byte)(immediate >> 1)); - Builder.EmitByte(0xD1); - } - - // beq #offset - // offset range: [-256..254] - public void EmitBEQ(int immediate) - { - Debug.Assert(immediate >= -256 && immediate <= 254); - // considering the pipeline with PC - immediate -= 4; - - Builder.EmitByte((byte)(immediate >> 1)); - Builder.EmitByte(0xD0); - } - - // bne label(+4): ret(2) + next(2) - // bx lr - // label: ... - public void EmitRETIfEqual() - { - EmitBNE(4); - EmitRET(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/Register.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/Register.cs deleted file mode 100644 index 15213c752ed..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/Register.cs +++ /dev/null @@ -1,37 +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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ILCompiler.DependencyAnalysis.ARM -{ - public enum Register - { - R0 = 0, - R1 = 1, - R2 = 2, - R3 = 3, - R4 = 4, - R5 = 5, - R6 = 6, - R7 = 7, - R8 = 8, - R9 = 9, - R10 = 10, - R11 = 11, - R12 = 12, - R13 = 13, - R14 = 14, - R15 = 15, - - None = 16, - RegDirect = 24, - - NoIndex = 128, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs deleted file mode 100644 index d3940ceaaad..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs +++ /dev/null @@ -1,39 +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.TypeSystem; - -namespace ILCompiler.DependencyAnalysis.ARM -{ - /// - /// Maps logical registers to physical registers on a specified OS. - /// - public struct TargetRegisterMap - { - public readonly Register Arg0; - public readonly Register Arg1; - public readonly Register Arg2; - public readonly Register Arg3; - public readonly Register Result; - public readonly Register InterproceduralScratch; - public readonly Register SP; - public readonly Register LR; - public readonly Register PC; - - public TargetRegisterMap(TargetOS os) - { - Arg0 = Register.R0; - Arg1 = Register.R1; - Arg2 = Register.R2; - Arg3 = Register.R3; - Result = Register.R0; - InterproceduralScratch = Register.R12; - SP = Register.R13; - LR = Register.R14; - PC = Register.R15; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs deleted file mode 100644 index da3d8b6e946..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs +++ /dev/null @@ -1,122 +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 System.Diagnostics; - -namespace ILCompiler.DependencyAnalysis.ARM64 -{ - public struct ARM64Emitter - { - public ARM64Emitter(NodeFactory factory, bool relocsOnly) - { - Builder = new ObjectDataBuilder(factory, relocsOnly); - TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem); - } - - public ObjectDataBuilder Builder; - public TargetRegisterMap TargetRegister; - - // Assembly stub creation api. TBD, actually make this general purpose - public void EmitMOV(Register regDst, ref AddrMode memory) - { - throw new NotImplementedException(); - } - - public void EmitMOV(Register regDst, Register regSrc) - { - throw new NotImplementedException(); - } - - public void EmitMOV(Register regDst, int imm32) - { - throw new NotImplementedException(); - } - - public void EmitLEAQ(Register reg, ISymbolNode symbol, int delta = 0) - { - throw new NotImplementedException(); - } - - public void EmitLEA(Register reg, ref AddrMode addrMode) - { - throw new NotImplementedException(); - } - - public void EmitCMP(ref AddrMode addrMode, sbyte immediate) - { - throw new NotImplementedException(); - } - - // add reg, immediate - public void EmitADD(Register reg, byte immediate) - { - Builder.EmitInt((int)(0x91 << 24) | (immediate << 10) | ((byte)reg << 5) | (byte) reg); - } - - public void EmitJMP(ISymbolNode symbol) - { - if (symbol.RepresentsIndirectionCell) - { - // xip0 register num is 0x10 - - // ADRP xip0, [symbol (21bit ADRP thing)] - // 0x90000000 + (xip regnum) - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21); - Builder.EmitByte(0x10); - Builder.EmitByte(0x00); - Builder.EmitByte(0x00); - Builder.EmitByte(0x90); - - // LDR xip0, [xip0 + 12bit LDR page offset reloc)] - // 0xF9400000 + ((xip0 regnum) << 5) + (xip regnum) - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L); - Builder.EmitByte(0x10); - Builder.EmitByte(0x02); - Builder.EmitByte(0x40); - Builder.EmitByte(0xF9); - - // BR xip0 - // 0xD61F0000 + (xip0 regnum) << 5) - Builder.EmitByte(0x00); - Builder.EmitByte(0x02); - Builder.EmitByte(0x1F); - Builder.EmitByte(0xD6); - } - else - { - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ARM64_BRANCH26); - Builder.EmitByte(0); - Builder.EmitByte(0); - Builder.EmitByte(0); - Builder.EmitByte(0x14); - } - } - - public void EmitINT3() - { - throw new NotImplementedException(); - } - - public void EmitJmpToAddrMode(ref AddrMode addrMode) - { - throw new NotImplementedException(); - } - - public void EmitRET() - { - throw new NotImplementedException(); - } - - public void EmitRETIfEqual() - { - throw new NotImplementedException(); - } - - private bool InSignedByteRange(int i) - { - return i == (int)(sbyte)i; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/AddrMode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/AddrMode.cs deleted file mode 100644 index f8d757359d6..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/AddrMode.cs +++ /dev/null @@ -1,35 +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; - -namespace ILCompiler.DependencyAnalysis.ARM64 -{ - public enum AddrModeSize - { - Int8 = 1, - Int16 = 2, - Int32 = 4, - Int64 = 8, - Int128 = 16 - } - - public struct AddrMode - { - public readonly Register BaseReg; - public readonly Register? IndexReg; - public readonly int Offset; - public readonly byte Scale; - public readonly AddrModeSize Size; - - public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size) - { - BaseReg = baseRegister; - IndexReg = indexRegister; - Offset = offset; - Scale = scale; - Size = size; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/Register.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/Register.cs deleted file mode 100644 index b69177e30af..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/Register.cs +++ /dev/null @@ -1,52 +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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ILCompiler.DependencyAnalysis.ARM64 -{ - public enum Register - { - X0 = 0, - X1 = 1, - X2 = 2, - X3 = 3, - X4 = 4, - X5 = 5, - X6 = 6, - X7 = 7, - X8 = 8, - X9 = 9, - X10 = 10, - X11 = 11, - X12 = 12, - X13 = 13, - X14 = 14, - X15 = 15, - X16 = 16, - X17 = 17, - X18 = 18, - X19 = 19, - X20 = 20, - X21 = 21, - X22 = 22, - X23 = 23, - X24 = 24, - X25 = 25, - X26 = 26, - X27 = 27, - X28 = 28, - X29 = 29, - X30 = 30, - - X31 = 31, - - None = 32, - NoIndex = 128, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/TargetRegisterMap.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/TargetRegisterMap.cs deleted file mode 100644 index dff6e4a837d..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_ARM64/TargetRegisterMap.cs +++ /dev/null @@ -1,39 +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.TypeSystem; - -namespace ILCompiler.DependencyAnalysis.ARM64 -{ - /// - /// Maps logical registers to physical registers on a specified OS. - /// - public struct TargetRegisterMap - { - public readonly Register Arg0; - public readonly Register Arg1; - public readonly Register Arg2; - public readonly Register Arg3; - public readonly Register Arg4; - public readonly Register Arg5; - public readonly Register Arg6; - public readonly Register Arg7; - public readonly Register Result; - - public TargetRegisterMap(TargetOS os) - { - Arg0 = Register.X0; - Arg1 = Register.X1; - Arg2 = Register.X2; - Arg3 = Register.X3; - Arg4 = Register.X4; - Arg5 = Register.X5; - Arg6 = Register.X6; - Arg7 = Register.X7; - Result = Register.X0; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/AddrMode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/AddrMode.cs deleted file mode 100644 index cba245601b5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/AddrMode.cs +++ /dev/null @@ -1,35 +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; - -namespace ILCompiler.DependencyAnalysis.X64 -{ - public enum AddrModeSize - { - Int8 = 1, - Int16 = 2, - Int32 = 4, - Int64 = 8, - Int128 = 16 - } - - public struct AddrMode - { - public readonly Register BaseReg; - public readonly Register? IndexReg; - public readonly int Offset; - public readonly byte Scale; - public readonly AddrModeSize Size; - - public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size) - { - BaseReg = baseRegister; - IndexReg = indexRegister; - Offset = offset; - Scale = scale; - Size = size; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/Register.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/Register.cs deleted file mode 100644 index 1bc2aa00bc0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/Register.cs +++ /dev/null @@ -1,37 +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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ILCompiler.DependencyAnalysis.X64 -{ - public enum Register - { - RAX = 0, - RCX = 1, - RDX = 2, - RBX = 3, - RSP = 4, - RBP = 5, - RSI = 6, - RDI = 7, - R8 = 8, - R9 = 9, - R10 = 10, - R11 = 11, - R12 = 12, - R13 = 13, - R14 = 14, - R15 = 15, - - None = 16, - RegDirect = 24, - - NoIndex = 128, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs deleted file mode 100644 index 808f8ed03c5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs +++ /dev/null @@ -1,48 +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.TypeSystem; - -namespace ILCompiler.DependencyAnalysis.X64 -{ - /// - /// Maps logical registers to physical registers on a specified OS. - /// - public struct TargetRegisterMap - { - public readonly Register Arg0; - public readonly Register Arg1; - public readonly Register Arg2; - public readonly Register Arg3; - public readonly Register Result; - - public TargetRegisterMap(TargetOS os) - { - switch (os) - { - case TargetOS.Windows: - Arg0 = Register.RCX; - Arg1 = Register.RDX; - Arg2 = Register.R8; - Arg3 = Register.R9; - Result = Register.RAX; - break; - - case TargetOS.Linux: - case TargetOS.OSX: - case TargetOS.FreeBSD: - Arg0 = Register.RDI; - Arg1 = Register.RSI; - Arg2 = Register.RDX; - Arg3 = Register.RCX; - Result = Register.RAX; - break; - default: - throw new NotImplementedException(); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs deleted file mode 100644 index 932e5ab96de..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs +++ /dev/null @@ -1,375 +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 System.Diagnostics; - -namespace ILCompiler.DependencyAnalysis.X64 -{ - public struct X64Emitter - { - public X64Emitter(NodeFactory factory, bool relocsOnly) - { - Builder = new ObjectDataBuilder(factory, relocsOnly); - TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem); - } - - public ObjectDataBuilder Builder; - public TargetRegisterMap TargetRegister; - - // Assembly stub creation api. TBD, actually make this general purpose - public void EmitMOV(Register regDst, ref AddrMode memory) - { - EmitIndirInstructionSize(0x8a, regDst, ref memory); - } - - public void EmitMOV(Register regDst, Register regSrc) - { - AddrMode rexAddrMode = new AddrMode(regSrc, null, 0, 0, AddrModeSize.Int64); - EmitRexPrefix(regDst, ref rexAddrMode); - Builder.EmitByte(0x8B); - Builder.EmitByte((byte)(0xC0 | (((int)regDst & 0x07) << 3) | (((int)regSrc & 0x07)))); - } - - public void EmitMOV(Register regDst, int imm32) - { - AddrMode rexAddrMode = new AddrMode(regDst, null, 0, 0, AddrModeSize.Int32); - EmitRexPrefix(regDst, ref rexAddrMode); - Builder.EmitByte((byte)(0xB8 | ((int)regDst & 0x07))); - Builder.EmitInt(imm32); - } - - public void EmitMOV(Register regDst, ISymbolNode node) - { - if (node.RepresentsIndirectionCell) - { - Builder.EmitByte(0x67); - Builder.EmitByte(0x48); - Builder.EmitByte(0x8B); - Builder.EmitByte((byte)(0x00 | ((byte)regDst << 3) | 0x05)); - Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_REL32); - } - else - { - EmitLEAQ(regDst, node, delta: 0); - } - } - - public void EmitLEAQ(Register reg, ISymbolNode symbol, int delta = 0) - { - AddrMode rexAddrMode = new AddrMode(Register.RAX, null, 0, 0, AddrModeSize.Int64); - EmitRexPrefix(reg, ref rexAddrMode); - Builder.EmitByte(0x8D); - Builder.EmitByte((byte)(0x05 | (((int)reg) & 0x07) << 3)); - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32, delta); - } - - public void EmitLEA(Register reg, ref AddrMode addrMode) - { - Debug.Assert(addrMode.Size != AddrModeSize.Int8 && - addrMode.Size != AddrModeSize.Int16); - EmitIndirInstruction(0x8D, reg, ref addrMode); - } - - public void EmitCMP(ref AddrMode addrMode, sbyte immediate) - { - if (addrMode.Size == AddrModeSize.Int16) - Builder.EmitByte(0x66); - EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), 0x7, ref addrMode); - Builder.EmitByte((byte)immediate); - } - - public void EmitADD(ref AddrMode addrMode, sbyte immediate) - { - if (addrMode.Size == AddrModeSize.Int16) - Builder.EmitByte(0x66); - EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), (byte)0, ref addrMode); - Builder.EmitByte((byte)immediate); - } - - public void EmitJMP(ISymbolNode symbol) - { - if (symbol.RepresentsIndirectionCell) - { - Builder.EmitByte(0xff); - Builder.EmitByte(0x25); - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); - } - else - { - Builder.EmitByte(0xE9); - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); - - } - } - - public void EmitJE(ISymbolNode symbol) - { - if (symbol.RepresentsIndirectionCell) - { - throw new NotImplementedException(); - } - else - { - Builder.EmitByte(0x0f); - Builder.EmitByte(0x84); - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); - } - } - - public void EmitINT3() - { - Builder.EmitByte(0xCC); - } - - public void EmitJmpToAddrMode(ref AddrMode addrMode) - { - EmitIndirInstruction(0xFF, 0x4, ref addrMode); - } - - public void EmitPUSH(sbyte imm8) - { - Builder.EmitByte(0x6A); - Builder.EmitByte(unchecked((byte)imm8)); - } - - public void EmitPUSH(ISymbolNode node) - { - if (node.RepresentsIndirectionCell) - { - // push [rip + relative node offset] - Builder.EmitByte(0xFF); - Builder.EmitByte(0x35); - Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_REL32); - } - else - { - // push rax (arbitrary value) - Builder.EmitByte(0x50); - // lea rax, [rip + relative node offset] - Builder.EmitByte(0x48); - Builder.EmitByte(0x8D); - Builder.EmitByte(0x05); - Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_REL32); - // xchg [rsp], rax; this also restores the previous value of rax - Builder.EmitByte(0x48); - Builder.EmitByte(0x87); - Builder.EmitByte(0x04); - Builder.EmitByte(0x24); - } - } - - public void EmitRET() - { - Builder.EmitByte(0xC3); - } - - public void EmitRETIfEqual() - { - // jne @+1 - Builder.EmitByte(0x75); - Builder.EmitByte(0x01); - - // ret - Builder.EmitByte(0xC3); - } - - private bool InSignedByteRange(int i) - { - return i == (int)(sbyte)i; - } - - private void EmitImmediate(int immediate, int size) - { - switch (size) - { - case 0: - break; - case 1: - Builder.EmitByte((byte)immediate); - break; - case 2: - Builder.EmitShort((short)immediate); - break; - case 4: - Builder.EmitInt(immediate); - break; - default: - throw new NotImplementedException(); - } - } - - private void EmitModRM(byte subOpcode, ref AddrMode addrMode) - { - byte modRM = (byte)((subOpcode & 0x07) << 3); - if (addrMode.BaseReg > Register.None) - { - Debug.Assert(addrMode.BaseReg >= Register.RegDirect); - - Register reg = (Register)(addrMode.BaseReg - Register.RegDirect); - Builder.EmitByte((byte)(0xC0 | modRM | ((int)reg & 0x07))); - } - else - { - byte lowOrderBitsOfBaseReg = (byte)((int)addrMode.BaseReg & 0x07); - modRM |= lowOrderBitsOfBaseReg; - int offsetSize = 0; - - if (addrMode.Offset == 0 && (lowOrderBitsOfBaseReg != (byte)Register.RBP)) - { - offsetSize = 0; - } - else if (InSignedByteRange(addrMode.Offset)) - { - offsetSize = 1; - modRM |= 0x40; - } - else - { - offsetSize = 4; - modRM |= 0x80; - } - - bool emitSibByte = false; - Register sibByteBaseRegister = addrMode.BaseReg; - - if (addrMode.BaseReg == Register.None) - { - //# ifdef _TARGET_AMD64_ - // x64 requires SIB to avoid RIP relative address - emitSibByte = true; - //#else - // emitSibByte = (addrMode.m_indexReg != MDIL_REG_NO_INDEX); - //#endif - - modRM &= 0x38; // set Mod bits to 00 and clear out base reg - offsetSize = 4; // this forces 32-bit displacement - - if (emitSibByte) - { - // EBP in SIB byte means no base - // ModRM base register forced to ESP in SIB code below - sibByteBaseRegister = Register.RBP; - } - else - { - // EBP in ModRM means no base - modRM |= (byte)(Register.RBP); - } - } - else if (lowOrderBitsOfBaseReg == (byte)Register.RSP || addrMode.IndexReg.HasValue) - { - emitSibByte = true; - } - - if (!emitSibByte) - { - Builder.EmitByte(modRM); - } - else - { - // MDIL_REG_ESP as the base is the marker that there is a SIB byte - modRM = (byte)((modRM & 0xF8) | (int)Register.RSP); - Builder.EmitByte(modRM); - - int indexRegAsInt = (int)(addrMode.IndexReg.HasValue ? addrMode.IndexReg.Value : Register.RSP); - - Builder.EmitByte((byte)((addrMode.Scale << 6) + ((indexRegAsInt & 0x07) << 3) + ((int)sibByteBaseRegister & 0x07))); - } - EmitImmediate(addrMode.Offset, offsetSize); - } - } - - private void EmitExtendedOpcode(int opcode) - { - if ((opcode >> 16) != 0) - { - if ((opcode >> 24) != 0) - { - Builder.EmitByte((byte)(opcode >> 24)); - } - Builder.EmitByte((byte)(opcode >> 16)); - } - Builder.EmitByte((byte)(opcode >> 8)); - } - - private void EmitRexPrefix(Register reg, ref AddrMode addrMode) - { - byte rexPrefix = 0; - - // Check the situations where a REX prefix is needed - - // Are we accessing a byte register that wasn't byte accessible in x86? - if (addrMode.Size == AddrModeSize.Int8 && reg >= Register.RSP) - { - rexPrefix |= 0x40; // REX - access to new 8-bit registers - } - - // Is this a 64 bit instruction? - if (addrMode.Size == AddrModeSize.Int64) - { - rexPrefix |= 0x48; // REX.W - 64-bit data operand - } - - // Is the destination register one of the new ones? - if (reg >= Register.R8) - { - rexPrefix |= 0x44; // REX.R - extension of the register field - } - - // Is the index register one of the new ones? - if (addrMode.IndexReg.HasValue && addrMode.IndexReg.Value >= Register.R8 && addrMode.IndexReg.Value <= Register.R15) - { - rexPrefix |= 0x42; // REX.X - extension of the SIB index field - } - - // Is the base register one of the new ones? - if (addrMode.BaseReg >= Register.R8 && addrMode.BaseReg <= Register.R15 - || addrMode.BaseReg >= (int)Register.R8 + Register.RegDirect && addrMode.BaseReg <= (int)Register.R15 + Register.RegDirect) - { - rexPrefix |= 0x41; // REX.WB (Wide, extended Base) - } - - // If we have anything so far, emit it. - if (rexPrefix != 0) - { - Builder.EmitByte(rexPrefix); - } - } - - private void EmitIndirInstruction(int opcode, byte subOpcode, ref AddrMode addrMode) - { - EmitRexPrefix(Register.RAX, ref addrMode); - if ((opcode >> 8) != 0) - { - EmitExtendedOpcode(opcode); - } - Builder.EmitByte((byte)opcode); - EmitModRM(subOpcode, ref addrMode); - } - - private void EmitIndirInstruction(int opcode, Register dstReg, ref AddrMode addrMode) - { - EmitRexPrefix(dstReg, ref addrMode); - if ((opcode >> 8) != 0) - { - EmitExtendedOpcode(opcode); - } - Builder.EmitByte((byte)opcode); - EmitModRM((byte)((int)dstReg & 0x07), ref addrMode); - } - - private void EmitIndirInstructionSize(int opcode, Register dstReg, ref AddrMode addrMode) - { - //# ifndef _TARGET_AMD64_ - // assert that ESP, EBP, ESI, EDI are not accessed as bytes in 32-bit mode - // Debug.Assert(!(addrMode.Size == AddrModeSize.Int8 && dstReg > Register.RBX)); - //#endif - Debug.Assert(addrMode.Size != 0); - if (addrMode.Size == AddrModeSize.Int16) - Builder.EmitByte(0x66); - EmitIndirInstruction(opcode + ((addrMode.Size != AddrModeSize.Int8) ? 1 : 0), dstReg, ref addrMode); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs deleted file mode 100644 index 75a5a7edabd..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs +++ /dev/null @@ -1,33 +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; - -namespace ILCompiler.DependencyAnalysis.X86 -{ - public enum AddrModeSize - { - Int8 = 1, - Int16 = 2, - Int32 = 4 - } - - public struct AddrMode - { - public readonly Register BaseReg; - public readonly Register? IndexReg; - public readonly int Offset; - public readonly byte Scale; - public readonly AddrModeSize Size; - - public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size) - { - BaseReg = baseRegister; - IndexReg = indexRegister; - Offset = offset; - Scale = scale; - Size = size; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/Register.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/Register.cs deleted file mode 100644 index ab938c82800..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/Register.cs +++ /dev/null @@ -1,29 +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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ILCompiler.DependencyAnalysis.X86 -{ - public enum Register - { - EAX = 0, - ECX = 1, - EDX = 2, - EBX = 3, - ESP = 4, - EBP = 5, - ESI = 6, - EDI = 7, - - None = 8, - RegDirect = 24, - - NoIndex = 128, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs deleted file mode 100644 index 3b81e43ba02..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs +++ /dev/null @@ -1,35 +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.TypeSystem; - -namespace ILCompiler.DependencyAnalysis.X86 -{ - /// - /// Maps logical registers to physical registers on a specified OS. - /// - public struct TargetRegisterMap - { - public readonly Register Arg0; - public readonly Register Arg1; - public readonly Register Result; - - public TargetRegisterMap(TargetOS os) - { - switch (os) - { - case TargetOS.Windows: - Arg0 = Register.ECX; - Arg1 = Register.EDX; - Result = Register.EAX; - break; - - default: - throw new NotImplementedException(); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs deleted file mode 100644 index a811ab4e678..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs +++ /dev/null @@ -1,220 +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 System.Diagnostics; - -namespace ILCompiler.DependencyAnalysis.X86 -{ - public struct X86Emitter - { - public X86Emitter(NodeFactory factory, bool relocsOnly) - { - Builder = new ObjectDataBuilder(factory, relocsOnly); - TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem); - } - - public ObjectDataBuilder Builder; - public TargetRegisterMap TargetRegister; - - public void EmitADD(ref AddrMode addrMode, sbyte immediate) - { - if (addrMode.Size == AddrModeSize.Int16) - Builder.EmitByte(0x66); - EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), (byte)0, ref addrMode); - Builder.EmitByte((byte)immediate); - } - - public void EmitJMP(ISymbolNode symbol) - { - if (symbol.RepresentsIndirectionCell) - { - Builder.EmitByte(0xff); - Builder.EmitByte(0x25); - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_HIGHLOW); - } - else - { - Builder.EmitByte(0xE9); - Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); - } - } - - public void EmitXOR(Register register1, Register register2) - { - Builder.EmitByte(0x33); - Builder.EmitByte((byte)(0xC0 | ((byte)register1 << 3) | (byte)register2)); - } - - public void EmitPUSH(sbyte imm8) - { - Builder.EmitByte(0x6A); - Builder.EmitByte(unchecked((byte)imm8)); - } - - public void EmitPUSH(ISymbolNode node) - { - if (node.RepresentsIndirectionCell) - { - // push eax (arbitrary value) - Builder.EmitByte(0x50); - // mov eax, [node address] - Builder.EmitByte(0x8B); - Builder.EmitByte(0x00 | ((byte)Register.EAX << 3) | 0x5); - Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_HIGHLOW); - // xchg [esp], eax; this also restores the previous value of eax - Builder.EmitByte(0x87); - Builder.EmitByte(0x04); - Builder.EmitByte(0x24); - } - else - { - // push - Builder.EmitByte(0x68); - Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_HIGHLOW); - } - } - - public void EmitMOV(Register register, ISymbolNode node) - { - if (node.RepresentsIndirectionCell) - { - // mov register, [node address] - Builder.EmitByte(0x8B); - Builder.EmitByte((byte)(0x00 | ((byte)register << 3) | 0x5)); - } - else - { - // mov register, immediate - Builder.EmitByte((byte)(0xB8 + (byte)register)); - } - Builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_HIGHLOW); - } - - public void EmitINT3() - { - Builder.EmitByte(0xCC); - } - - private bool InSignedByteRange(int i) - { - return i == (int)(sbyte)i; - } - - private void EmitImmediate(int immediate, int size) - { - switch (size) - { - case 0: - break; - case 1: - Builder.EmitByte((byte)immediate); - break; - case 2: - Builder.EmitShort((short)immediate); - break; - case 4: - Builder.EmitInt(immediate); - break; - default: - throw new NotImplementedException(); - } - } - - private void EmitModRM(byte subOpcode, ref AddrMode addrMode) - { - byte modRM = (byte)((subOpcode & 0x07) << 3); - if (addrMode.BaseReg > Register.None) - { - Debug.Assert(addrMode.BaseReg >= Register.RegDirect); - - Register reg = (Register)(addrMode.BaseReg - Register.RegDirect); - Builder.EmitByte((byte)(0xC0 | modRM | ((int)reg & 0x07))); - } - else - { - byte lowOrderBitsOfBaseReg = (byte)((int)addrMode.BaseReg & 0x07); - modRM |= lowOrderBitsOfBaseReg; - int offsetSize = 0; - - if (addrMode.Offset == 0 && (lowOrderBitsOfBaseReg != (byte)Register.EBP)) - { - offsetSize = 0; - } - else if (InSignedByteRange(addrMode.Offset)) - { - offsetSize = 1; - modRM |= 0x40; - } - else - { - offsetSize = 4; - modRM |= 0x80; - } - - bool emitSibByte = false; - Register sibByteBaseRegister = addrMode.BaseReg; - - if (addrMode.BaseReg == Register.None) - { - emitSibByte = (addrMode.IndexReg != Register.NoIndex); - modRM &= 0x38; // set Mod bits to 00 and clear out base reg - offsetSize = 4; // this forces 32-bit displacement - - if (emitSibByte) - { - // EBP in SIB byte means no base - // ModRM base register forced to ESP in SIB code below - sibByteBaseRegister = Register.EBP; - } - else - { - // EBP in ModRM means no base - modRM |= (byte)(Register.EBP); - } - } - else if (lowOrderBitsOfBaseReg == (byte)Register.ESP || addrMode.IndexReg.HasValue) - { - emitSibByte = true; - } - - if (!emitSibByte) - { - Builder.EmitByte(modRM); - } - else - { - modRM = (byte)((modRM & 0xF8) | (int)Register.ESP); - Builder.EmitByte(modRM); - int indexRegAsInt = (int)(addrMode.IndexReg.HasValue ? addrMode.IndexReg.Value : Register.ESP); - Builder.EmitByte((byte)((addrMode.Scale << 6) + ((indexRegAsInt & 0x07) << 3) + ((int)sibByteBaseRegister & 0x07))); - } - EmitImmediate(addrMode.Offset, offsetSize); - } - } - - private void EmitExtendedOpcode(int opcode) - { - if ((opcode >> 16) != 0) - { - if ((opcode >> 24) != 0) - { - Builder.EmitByte((byte)(opcode >> 24)); - } - Builder.EmitByte((byte)(opcode >> 16)); - } - Builder.EmitByte((byte)(opcode >> 8)); - } - - private void EmitIndirInstruction(int opcode, byte subOpcode, ref AddrMode addrMode) - { - if ((opcode >> 8) != 0) - { - EmitExtendedOpcode(opcode); - } - Builder.EmitByte((byte)opcode); - EmitModRM(subOpcode, ref addrMode); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyTrackingLevel.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyTrackingLevel.cs deleted file mode 100644 index 9322b9d3026..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DependencyTrackingLevel.cs +++ /dev/null @@ -1,58 +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 System.Collections.Generic; - -using ILCompiler.DependencyAnalysis; -using ILCompiler.DependencyAnalysisFramework; - -namespace ILCompiler -{ - /// - /// Represents the level of dependency tracking within the dependency analysis system. - /// - public enum DependencyTrackingLevel - { - /// - /// Tracking disabled. This is the most performant and memory efficient option. - /// - None, - - /// - /// The graph keeps track of the first dependency. - /// - First, - - /// - /// The graph keeps track of all dependencies. - /// - All - } - - internal static class DependencyTrackingLevelExtensions - { - public static DependencyAnalyzerBase CreateDependencyGraph(this DependencyTrackingLevel trackingLevel, NodeFactory factory, IComparer> comparer = null) - { - // Choose which dependency graph implementation to use based on the amount of logging requested. - switch (trackingLevel) - { - case DependencyTrackingLevel.None: - if (EventSourceLogStrategy.IsEventSourceEnabled) - return new DependencyAnalyzer, NodeFactory>(factory, comparer); - else - return new DependencyAnalyzer, NodeFactory>(factory, comparer); - - case DependencyTrackingLevel.First: - return new DependencyAnalyzer, NodeFactory>(factory, comparer); - - case DependencyTrackingLevel.All: - return new DependencyAnalyzer, NodeFactory>(factory, comparer); - - default: - throw new InvalidOperationException(); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/DevirtualizationManager.cs deleted file mode 100644 index 92467d0176c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/DevirtualizationManager.cs +++ /dev/null @@ -1,101 +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 Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace ILCompiler -{ - /// - /// Manages devirtualization behaviors. Devirtualization is the process of converting - /// virtual calls to direct calls in cases where we can compute the result of a virtual - /// lookup at compile time. - /// - public class DevirtualizationManager - { - /// - /// Returns true if cannot be the base class of any other - /// type. - /// - public virtual bool IsEffectivelySealed(TypeDesc type) - { - switch (type.Category) - { - case TypeFlags.Array: - case TypeFlags.SzArray: - case TypeFlags.ByRef: - case TypeFlags.Pointer: - case TypeFlags.FunctionPointer: - return true; - - default: - Debug.Assert(type.IsDefType); - var metadataType = (MetadataType)type; - return metadataType.IsSealed || metadataType.IsModuleType; - } - } - - /// - /// Returns true if cannot be overriden by any other method. - /// - public virtual bool IsEffectivelySealed(MethodDesc method) - { - return method.IsFinal || IsEffectivelySealed(method.OwningType); - } - - /// - /// Attempts to resolve the virtual method into - /// a method on that implements the declaring method. - /// Returns null if this is not possible. - /// - /// - /// Note that if is a value type, the result of the resolution - /// might have to be treated as an unboxing thunk by the caller. - /// - public MethodDesc ResolveVirtualMethod(MethodDesc declMethod, TypeDesc implType) - { - Debug.Assert(declMethod.IsVirtual); - - // We're operating on virtual methods. This means that if implType is an array, we need - // to get the type that has all the virtual methods provided by the class library. - return ResolveVirtualMethod(declMethod, implType.GetClosestDefType()); - } - - protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType implType) - { - // Quick check: if decl matches impl, we're done. - if (declMethod.OwningType == implType) - return declMethod; - - MethodDesc impl; - - if (declMethod.OwningType.IsInterface) - { - impl = implType.ResolveInterfaceMethodTarget(declMethod); - if (impl != null) - { - impl = implType.FindVirtualFunctionTargetMethodOnObjectType(impl); - } - } - else - { - impl = implType.FindVirtualFunctionTargetMethodOnObjectType(declMethod); - if (impl != null && (impl != declMethod)) - { - MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl); - MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod); - - if (slotDefiningMethodImpl != slotDefiningMethodDecl) - { - // We cannot resolve virtual method in case the impl is a different slot from the declMethod - impl = null; - } - } - } - - return impl; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/HardwareIntrinsicHelpers.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/HardwareIntrinsicHelpers.cs deleted file mode 100644 index 99b3400617c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/HardwareIntrinsicHelpers.cs +++ /dev/null @@ -1,192 +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.TypeSystem; -using Internal.IL; -using Internal.IL.Stubs; -using System.Diagnostics; - -namespace ILCompiler -{ - public static class HardwareIntrinsicHelpers - { - /// - /// Gets a value indicating whether this is a hardware intrinsic on the platform that we're compiling for. - /// - public static bool IsHardwareIntrinsic(MethodDesc method) - { - TypeDesc owningType = method.OwningType; - - if (owningType.IsIntrinsic && owningType is MetadataType mdType) - { - TargetArchitecture targetArch = owningType.Context.Target.Architecture; - - if (targetArch == TargetArchitecture.X64 || targetArch == TargetArchitecture.X86) - { - mdType = (MetadataType)mdType.ContainingType ?? mdType; - if (mdType.Namespace == "System.Runtime.Intrinsics.X86") - return true; - } - else if (targetArch == TargetArchitecture.ARM64) - { - if (mdType.Namespace == "System.Runtime.Intrinsics.Arm.Arm64") - return true; - } - } - - return false; - } - - public static bool IsIsSupportedMethod(MethodDesc method) - { - return method.Name == "get_IsSupported"; - } - - public static MethodIL GetUnsupportedImplementationIL(MethodDesc method) - { - // The implementation of IsSupported for codegen backends that don't support hardware intrinsics - // at all is to return 0. - if (IsIsSupportedMethod(method)) - { - return new ILStubMethodIL(method, - new byte[] { - (byte)ILOpcode.ldc_i4_0, - (byte)ILOpcode.ret - }, - Array.Empty(), null); - } - - // Other methods throw PlatformNotSupportedException - MethodDesc throwPnse = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException"); - - return new ILStubMethodIL(method, - new byte[] { - (byte)ILOpcode.call, 1, 0, 0, 0, - (byte)ILOpcode.br_s, unchecked((byte)-7), - }, - Array.Empty(), - new object[] { throwPnse }); - } - - /// - /// Generates IL for the IsSupported property that reads this information from a field initialized by the runtime - /// at startup. Returns null for hardware intrinsics whose support level is known at compile time - /// (i.e. they're known to be always supported or always unsupported). - /// - public static MethodIL EmitIsSupportedIL(MethodDesc method, FieldDesc isSupportedField) - { - Debug.Assert(IsIsSupportedMethod(method)); - Debug.Assert(isSupportedField.IsStatic && isSupportedField.FieldType.IsWellKnownType(WellKnownType.Int32)); - - TargetDetails target = method.Context.Target; - MetadataType owningType = (MetadataType)method.OwningType; - - // Check for case of nested "X64" types - if (owningType.Name == "X64") - { - if (target.Architecture != TargetArchitecture.X64) - return null; - - // Un-nest the type so that we can do a name match - owningType = (MetadataType)owningType.ContainingType; - } - - int flag; - if ((target.Architecture == TargetArchitecture.X64 || target.Architecture == TargetArchitecture.X86) - && owningType.Namespace == "System.Runtime.Intrinsics.X86") - { - switch (owningType.Name) - { - case "Aes": - flag = XArchIntrinsicConstants.Aes; - break; - case "Pclmulqdq": - flag = XArchIntrinsicConstants.Pclmulqdq; - break; - case "Sse3": - flag = XArchIntrinsicConstants.Sse3; - break; - case "Ssse3": - flag = XArchIntrinsicConstants.Ssse3; - break; - case "Lzcnt": - flag = XArchIntrinsicConstants.Lzcnt; - break; - // NOTE: this switch is complemented by IsKnownSupportedIntrinsicAtCompileTime - // in the method below. - default: - return null; - } - } - else - { - return null; - } - - var emit = new ILEmitter(); - ILCodeStream codeStream = emit.NewCodeStream(); - - codeStream.Emit(ILOpcode.ldsfld, emit.NewToken(isSupportedField)); - codeStream.EmitLdc(flag); - codeStream.Emit(ILOpcode.and); - codeStream.EmitLdc(0); - codeStream.Emit(ILOpcode.cgt_un); - codeStream.Emit(ILOpcode.ret); - - return emit.Link(method); - } - - /// - /// Gets a value indicating whether the support for a given intrinsic is known at compile time. - /// - public static bool IsKnownSupportedIntrinsicAtCompileTime(MethodDesc method) - { - TargetDetails target = method.Context.Target; - - if (target.Architecture == TargetArchitecture.X64 - || target.Architecture == TargetArchitecture.X86) - { - var owningType = (MetadataType)method.OwningType; - if (owningType.Name == "X64") - { - if (target.Architecture != TargetArchitecture.X64) - return true; - owningType = (MetadataType)owningType.ContainingType; - } - - if (owningType.Namespace != "System.Runtime.Intrinsics.X86") - return true; - - // Sse and Sse2 are baseline required intrinsics. - // RyuJIT also uses Sse41/Sse42 with the general purpose Vector APIs. - // RyuJIT only respects Popcnt if Sse41/Sse42 is also enabled. - // Avx/Avx2/Bmi1/Bmi2 require VEX encoding and RyuJIT currently can't enable them - // without enabling VEX encoding everywhere. We don't support them. - // This list complements EmitIsSupportedIL above. - return owningType.Name == "Sse" || owningType.Name == "Sse2" - || owningType.Name == "Sse41" || owningType.Name == "Sse42" - || owningType.Name == "Popcnt" - || owningType.Name == "Bmi1" || owningType.Name == "Bmi2" - || owningType.Name == "Avx" || owningType.Name == "Avx2"; - } - - return false; - } - - // Keep this enumeration in sync with startup.cpp in the native runtime. - private static class XArchIntrinsicConstants - { - public const int Aes = 0x0001; - public const int Pclmulqdq = 0x0002; - public const int Sse3 = 0x0004; - public const int Ssse3 = 0x0008; - public const int Sse41 = 0x0010; - public const int Sse42 = 0x0020; - public const int Popcnt = 0x0040; - public const int Lzcnt = 0x0080; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/ICompilationRootProvider.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/ICompilationRootProvider.cs deleted file mode 100644 index 8434ad8a8ac..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/ICompilationRootProvider.cs +++ /dev/null @@ -1,18 +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. - -namespace ILCompiler -{ - /// - /// Provides a set of seeds from which compilation will start. - /// - public interface ICompilationRootProvider - { - /// - /// When implemented in a class, uses to add compilation - /// roots to the compilation. - /// - void AddCompilationRoots(IRootingServiceProvider rootProvider); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/InternalCompilerErrorException.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/InternalCompilerErrorException.cs deleted file mode 100644 index 06d0cf3e5df..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/InternalCompilerErrorException.cs +++ /dev/null @@ -1,21 +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; - -namespace ILCompiler -{ - public class InternalCompilerErrorException : Exception - { - public InternalCompilerErrorException(string message) - : this(message, innerException: null) - { - } - - public InternalCompilerErrorException(string message, Exception innerException) - : base(message, innerException) - { - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/Logger.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/Logger.cs deleted file mode 100644 index 5fa09a1c420..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/Logger.cs +++ /dev/null @@ -1,25 +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.IO; - -namespace ILCompiler -{ - // Poor man's logger. We can do better than this. - - public class Logger - { - public static Logger Null = new Logger(TextWriter.Null, false); - - public TextWriter Writer { get; } - - public bool IsVerbose { get; } - - public Logger(TextWriter writer, bool isVerbose) - { - Writer = TextWriter.Synchronized(writer); - IsVerbose = isVerbose; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/NameMangler.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/NameMangler.cs deleted file mode 100644 index 3bd959748e2..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/NameMangler.cs +++ /dev/null @@ -1,39 +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 Internal.Text; -using Internal.TypeSystem; - -namespace ILCompiler -{ - // - // NameMangler is responsible for giving extern C/C++ names to managed types, methods and fields - // - // The key invariant is that the mangled names are independent on the compilation order. - // - public abstract class NameMangler - { -#if !READYTORUN - public NameMangler(NodeMangler nodeMangler) - { - nodeMangler.NameMangler = this; - NodeMangler = nodeMangler; - } - - public NodeMangler NodeMangler { get; private set; } -#endif - - public abstract string CompilationUnitPrefix { get; set; } - - public abstract string SanitizeName(string s, bool typeName = false); - - public abstract string GetMangledTypeName(TypeDesc type); - - public abstract Utf8String GetMangledMethodName(MethodDesc method); - - public abstract Utf8String GetMangledFieldName(FieldDesc field); - - public abstract string GetMangledStringName(string literal); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/ReadyToRun.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/ReadyToRun.cs deleted file mode 100644 index 034136734d1..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/ReadyToRun.cs +++ /dev/null @@ -1,195 +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. - -// -// Keep in sync with https://github.com/dotnet/coreclr/blob/master/src/inc/readytorun.h -// - -namespace ILCompiler -{ - // - // Intrinsics and helpers - // - - public enum ReadyToRunHelper - { - Invalid = 0x00, - - // Not a real helper - handle to current module passed to delay load helpers. - Module = 0x01, - GSCookie = 0x02, - - // - // Delay load helpers - // - - // All delay load helpers use custom calling convention: - // - scratch register - address of indirection cell. 0 = address is inferred from callsite. - // - stack - section index, module handle - DelayLoad_MethodCall = 0x08, - - DelayLoad_Helper = 0x10, - DelayLoad_Helper_Obj = 0x11, - DelayLoad_Helper_ObjObj = 0x12, - - // Exception handling helpers - Throw = 0x20, - Rethrow = 0x21, - Overflow = 0x22, - RngChkFail = 0x23, - FailFast = 0x24, - ThrowNullRef = 0x25, - ThrowDivZero = 0x26, - - // Write barriers - WriteBarrier = 0x30, - CheckedWriteBarrier = 0x31, - ByRefWriteBarrier = 0x32, - - // Array helpers - Stelem_Ref = 0x38, - Ldelema_Ref = 0x39, - - MemSet = 0x40, - MemCpy = 0x41, - - // P/Invoke support - PInvokeBegin = 0x42, - PInvokeEnd = 0x43, - - // Get string handle lazily - GetString = 0x50, - - // Used by /Tuning for Profile optimizations - LogMethodEnter = 0x51, - - // Reflection helpers - GetRuntimeTypeHandle = 0x54, - GetRuntimeMethodHandle = 0x55, - GetRuntimeFieldHandle = 0x56, - - Box = 0x58, - Box_Nullable = 0x59, - Unbox = 0x5A, - Unbox_Nullable = 0x5B, - NewMultiDimArr = 0x5C, - NewMultiDimArr_NonVarArg = 0x5D, - - // Helpers used with generic handle lookup cases - NewObject = 0x60, - NewArray = 0x61, - CheckCastAny = 0x62, - CheckInstanceAny = 0x63, - GenericGcStaticBase = 0x64, - GenericNonGcStaticBase = 0x65, - GenericGcTlsBase = 0x66, - GenericNonGcTlsBase = 0x67, - VirtualFuncPtr = 0x68, - - // Long mul/div/shift ops - LMul = 0xC0, - LMulOfv = 0xC1, - ULMulOvf = 0xC2, - LDiv = 0xC3, - LMod = 0xC4, - ULDiv = 0xC5, - ULMod = 0xC6, - LLsh = 0xC7, - LRsh = 0xC8, - LRsz = 0xC9, - Lng2Dbl = 0xCA, - ULng2Dbl = 0xCB, - - // 32-bit division helpers - Div = 0xCC, - Mod = 0xCD, - UDiv = 0xCE, - UMod = 0xCF, - - // Floating point conversions - Dbl2Int = 0xD0, - Dbl2IntOvf = 0xD1, - Dbl2Lng = 0xD2, - Dbl2LngOvf = 0xD3, - Dbl2UInt = 0xD4, - Dbl2UIntOvf = 0xD5, - Dbl2ULng = 0xD6, - Dbl2ULngOvf = 0xD7, - - // Floating point ops - DblRem = 0xE0, - FltRem = 0xE1, - DblRound = 0xE2, - FltRound = 0xE3, - - // Personality rountines - PersonalityRoutine = 0xF0, - PersonalityRoutineFilterFunclet = 0xF1, - - // Synchronized methods - MonitorEnter = 0xF8, - MonitorExit = 0xF9, - - // JIT32 x86-specific write barriers - WriteBarrier_EAX = 0x100, - WriteBarrier_EBX = 0x101, - WriteBarrier_ECX = 0x102, - WriteBarrier_ESI = 0x103, - WriteBarrier_EDI = 0x104, - WriteBarrier_EBP = 0x105, - CheckedWriteBarrier_EAX = 0x106, - CheckedWriteBarrier_EBX = 0x107, - CheckedWriteBarrier_ECX = 0x108, - CheckedWriteBarrier_ESI = 0x109, - CheckedWriteBarrier_EDI = 0x10A, - CheckedWriteBarrier_EBP = 0x10B, - - // JIT32 x86-specific exception handling - EndCatch = 0x110, - - StackProbe = 0x111, - - // ********************************************************************************************** - // - // These are not actually part of the R2R file format. We have them here because it's convenient. - // - // ********************************************************************************************** - - // Marker to be used in asserts. - FirstFakeHelper, - - ThrowArgumentOutOfRange, - ThrowArgument, - ThrowPlatformNotSupported, - ThrowNotImplemented, - - DebugBreak, - - GetRuntimeType, - - AreTypesEquivalent, - - CheckCastClass, - CheckInstanceClass, - CheckCastArray, - CheckInstanceArray, - CheckCastInterface, - CheckInstanceInterface, - - // P/Invoke support - ReversePInvokeEnter, - ReversePInvokeExit, - - MonitorEnterStatic, - MonitorExitStatic, - - // GVM lookup helper - GVMLookupForSlot, - - // TypedReference - TypeHandleToRuntimeType, - GetRefAny, - TypeHandleToRuntimeTypeHandle, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/SingleMethodRootProvider.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/SingleMethodRootProvider.cs deleted file mode 100644 index c1d9f484e0b..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/SingleMethodRootProvider.cs +++ /dev/null @@ -1,26 +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 Internal.TypeSystem; - -namespace ILCompiler -{ - /// - /// Compilation root that is a single method. - /// - public class SingleMethodRootProvider : ICompilationRootProvider - { - private MethodDesc _method; - - public SingleMethodRootProvider(MethodDesc method) - { - _method = method; - } - - public void AddCompilationRoots(IRootingServiceProvider rootProvider) - { - rootProvider.AddCompilationRoot(_method, "Single method root"); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/TypeExtensions.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/TypeExtensions.cs deleted file mode 100644 index 0514b24488c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/TypeExtensions.cs +++ /dev/null @@ -1,506 +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.IL; -using Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace ILCompiler -{ - public static class TypeExtensions - { - public static bool IsSealed(this TypeDesc type) - { - var metadataType = type as MetadataType; - if (metadataType != null) - { - return metadataType.IsSealed || metadataType.IsModuleType; - } - - Debug.Assert(type.IsArray, "IsSealed on a type with no virtual methods?"); - return true; - } - - /// - /// Gets the type that defines virtual method slots for the specified type. - /// - public static DefType GetClosestDefType(this TypeDesc type) - { - if (type.IsArray) - { - if (!type.IsArrayTypeWithoutGenericInterfaces()) - { - MetadataType arrayShadowType = type.Context.SystemModule.GetType("System", "Array`1", throwIfNotFound: false); - if (arrayShadowType != null) - { - return arrayShadowType.MakeInstantiatedType(((ArrayType)type).ElementType); - } - } - - return type.Context.GetWellKnownType(WellKnownType.Array); - } - - Debug.Assert(type is DefType); - return (DefType)type; - } - - /// - /// Gets a value indicating whether the method requires a hidden instantiation argument in addition - /// to the formal arguments defined in the method signature. - /// - public static bool RequiresInstArg(this MethodDesc method) - { - return method.IsSharedByGenericInstantiations && - (method.HasInstantiation || method.Signature.IsStatic || method.ImplementationType.IsValueType || (method.ImplementationType.IsInterface && !method.IsAbstract)); - } - - /// - /// Gets a value indicating whether the method acquires the generic context from a hidden - /// instantiation argument that points to the method's generic dictionary. - /// - public static bool RequiresInstMethodDescArg(this MethodDesc method) - { - return method.HasInstantiation && method.IsSharedByGenericInstantiations; - } - - /// - /// Gets a value indicating whether the method acquires the generic context from a hidden - /// instantiation argument that points to the generic dictionary of the method's owning type. - /// - public static bool RequiresInstMethodTableArg(this MethodDesc method) - { - return (method.Signature.IsStatic || method.ImplementationType.IsValueType || (method.ImplementationType.IsInterface && !method.IsAbstract)) && - method.IsSharedByGenericInstantiations && - !method.HasInstantiation; - } - - /// - /// Gets a value indicating whether the method acquires the generic context from the this pointer. - /// - public static bool AcquiresInstMethodTableFromThis(this MethodDesc method) - { - return method.IsSharedByGenericInstantiations && - !method.HasInstantiation && - !method.Signature.IsStatic && - !method.ImplementationType.IsValueType && - !(method.ImplementationType.IsInterface && !method.IsAbstract); - } - - /// - /// Returns true if '' is the "Address" method on multidimensional array types. - /// - public static bool IsArrayAddressMethod(this MethodDesc method) - { - var arrayMethod = method as ArrayMethod; - return arrayMethod != null && arrayMethod.Kind == ArrayMethodKind.Address; - } - - /// - /// Gets a value indicating whether this type has any generic virtual methods. - /// - public static bool HasGenericVirtualMethods(this TypeDesc type) - { - foreach (var method in type.GetAllMethods()) - { - if (method.IsVirtual && method.HasInstantiation) - return true; - } - - return false; - } - - /// - /// Wrapper helper function around the IsCanonicalDefinitionType API on the TypeSystemContext - /// - public static bool IsCanonicalDefinitionType(this TypeDesc type, CanonicalFormKind kind) - { - return type.Context.IsCanonicalDefinitionType(type, kind); - } - - /// - /// Gets the value of the field ordinal. Ordinals are computed by also including static fields, but excluding - /// literal fields and fields with RVAs. - /// - public static int GetFieldOrdinal(this FieldDesc inputField) - { - // Make sure we are asking the question for a valid instance or static field - Debug.Assert(!inputField.HasRva && !inputField.IsLiteral); - - int fieldOrdinal = 0; - foreach (FieldDesc field in inputField.OwningType.GetFields()) - { - // If this field does not contribute to layout, skip - if (field.HasRva || field.IsLiteral) - continue; - - if (field == inputField) - return fieldOrdinal; - - fieldOrdinal++; - } - - Debug.Assert(false); - return -1; - } - - /// - /// What is the maximum number of steps that need to be taken from this type to its most contained generic type. - /// i.e. - /// System.Int32 => 0 - /// List<System.Int32> => 1 - /// Dictionary<System.Int32,System.Int32> => 1 - /// Dictionary<List<System.Int32>,<System.Int32> => 2 - /// - public static int GetGenericDepth(this TypeDesc type) - { - if (type.HasInstantiation) - { - int maxGenericDepthInInstantiation = 0; - foreach (TypeDesc instantiationType in type.Instantiation) - { - maxGenericDepthInInstantiation = Math.Max(instantiationType.GetGenericDepth(), maxGenericDepthInInstantiation); - } - - return maxGenericDepthInInstantiation + 1; - } - - return 0; - } - - /// - /// Determine if a type has a generic depth greater than a given value - /// - public static bool IsGenericDepthGreaterThan(this TypeDesc type, int depth) - { - if (depth < 0) - return true; - - foreach (TypeDesc instantiationType in type.Instantiation) - { - if (instantiationType.IsGenericDepthGreaterThan(depth - 1)) - return true; - } - - return false; - } - - /// - /// Determines whether an array type does implements the generic collection interfaces. This is the case - /// for multi-dimensional arrays, and arrays of pointers. - /// - public static bool IsArrayTypeWithoutGenericInterfaces(this TypeDesc type) - { - if (!type.IsArray) - return false; - - var arrayType = (ArrayType)type; - TypeDesc elementType = arrayType.ElementType; - return type.IsMdArray || elementType.IsPointer || elementType.IsFunctionPointer; - } - - /// - /// Determines whether an object of type '' requires 8-byte alignment on - /// 32bit ARM architectures. - /// - public static bool RequiresAlign8(this TypeDesc type) - { - if (type.Context.Target.Architecture != TargetArchitecture.ARM) - { - return false; - } - - if (type.IsArray) - { - var elementType = ((ArrayType)type).ElementType; - if ((elementType.IsValueType) && ((DefType)elementType).InstanceByteAlignment.AsInt > 4) - { - return true; - } - } - else if (type.IsDefType && ((DefType)type).InstanceByteAlignment.AsInt > 4) - { - return true; - } - - return false; - } - - public static TypeDesc MergeTypesToCommonParent(TypeDesc ta, TypeDesc tb) - { - if (ta == tb) - { - return ta; - } - - // Handle the array case - if (ta.IsArray) - { - if (tb.IsArray) - { - return MergeArrayTypesToCommonParent((ArrayType)ta, (ArrayType)tb); - } - else if (tb.IsInterface) - { - // Check to see if we can merge the array to a common interface (such as Derived[] and IList) - if (ta.CanCastTo(tb)) - { - return tb; - } - } - // keep merging from here - ta = ta.Context.GetWellKnownType(WellKnownType.Array); - } - else if (tb.IsArray) - { - if (ta.IsInterface && tb.CanCastTo(ta)) - { - return ta; - } - - tb = tb.Context.GetWellKnownType(WellKnownType.Array); - } - - Debug.Assert(ta.IsDefType); - Debug.Assert(tb.IsDefType); - - if (tb.IsInterface) - { - if (ta.IsInterface) - { - // - // Both classes are interfaces. Check that if one - // interface extends the other. - // - // Does tb extend ta ? - // - if (tb.ImplementsEquivalentInterface(ta)) - { - return ta; - } - - // - // Does tb extend ta ? - // - if (ta.ImplementsEquivalentInterface(tb)) - { - return tb; - } - - // No compatible merge found - using Object - return ta.Context.GetWellKnownType(WellKnownType.Object); - } - else - { - return MergeClassWithInterface(ta, tb); - } - } - else if (ta.IsInterface) - { - return MergeClassWithInterface(tb, ta); - } - - int aDepth = 0; - int bDepth = 0; - - // find the depth in the class hierarchy for each class - for (TypeDesc searchType = ta; searchType != null; searchType = searchType.BaseType) - { - aDepth++; - } - - for (TypeDesc searchType = tb; searchType != null; searchType = searchType.BaseType) - { - bDepth++; - } - - // for whichever class is lower down in the hierarchy, walk up the superclass chain - // to the same level as the other class - while (aDepth > bDepth) - { - ta = ta.BaseType; - aDepth--; - } - - while (bDepth > aDepth) - { - tb = tb.BaseType; - bDepth--; - } - - while (ta != tb) - { - ta = ta.BaseType; - tb = tb.BaseType; - } - - // If no compatible merge is found, we end up using Object - - Debug.Assert(ta != null); - - return ta; - } - - private static TypeDesc MergeArrayTypesToCommonParent(ArrayType ta, ArrayType tb) - { - Debug.Assert(ta.IsArray && tb.IsArray && ta != tb); - - // if no match on the rank the common ancestor is System.Array - if (ta.IsSzArray != tb.IsSzArray || ta.Rank != tb.Rank) - { - return ta.Context.GetWellKnownType(WellKnownType.Array); - } - - TypeDesc taElem = ta.ElementType; - TypeDesc tbElem = tb.ElementType; - Debug.Assert(taElem != tbElem); - - TypeDesc mergeElem; - if (taElem.IsArray && tbElem.IsArray) - { - mergeElem = MergeArrayTypesToCommonParent((ArrayType)taElem, (ArrayType)tbElem); - } - else if (taElem.IsGCPointer && tbElem.IsGCPointer) - { - // Find the common ancestor of the element types. - mergeElem = MergeTypesToCommonParent(taElem, tbElem); - } - else - { - // The element types have nothing in common. - return ta.Context.GetWellKnownType(WellKnownType.Array); - } - - if (mergeElem == taElem) - { - return ta; - } - - if (mergeElem == tbElem) - { - return tb; - } - - if (taElem.IsMdArray) - { - return mergeElem.MakeArrayType(ta.Rank); - } - - return mergeElem.MakeArrayType(); - } - - private static bool ImplementsEquivalentInterface(this TypeDesc type, TypeDesc interfaceType) - { - foreach (DefType implementedInterface in type.RuntimeInterfaces) - { - if (implementedInterface == interfaceType) - { - return true; - } - } - - return false; - } - - private static TypeDesc MergeClassWithInterface(TypeDesc type, TypeDesc interfaceType) - { - // Check if the class implements the interface - if (type.ImplementsEquivalentInterface(interfaceType)) - { - return interfaceType; - } - - // Check if the class and the interface implement a common interface - foreach (var potentialCommonInterface in interfaceType.RuntimeInterfaces) - { - if (type.ImplementsEquivalentInterface(potentialCommonInterface)) - { - // Found a common interface. If there are multiple common interfaces, then - // the problem is ambiguous so we'll just take the first one--it's the best - // we can do. - return potentialCommonInterface; - } - } - - // No compatible merge found - using Object - return type.Context.GetWellKnownType(WellKnownType.Object); - } - - /// - /// Normalizes canonical instantiations (converts Foo<object, __Canon> to - /// Foo<__Canon, __Canon>). Returns identity for non-canonical types. - /// - public static TypeDesc NormalizeInstantiation(this TypeDesc thisType) - { - if (thisType.IsCanonicalSubtype(CanonicalFormKind.Any)) - return thisType.ConvertToCanonForm(CanonicalFormKind.Specific); - - return thisType; - } - - public static Instantiation GetInstantiationThatMeetsConstraints(Instantiation inst, bool allowCanon) - { - TypeDesc[] resultArray = new TypeDesc[inst.Length]; - for (int i = 0; i < inst.Length; i++) - { - TypeDesc instArg = GetTypeThatMeetsConstraints((GenericParameterDesc)inst[i], allowCanon); - if (instArg == null) - return default(Instantiation); - resultArray[i] = instArg; - } - - return new Instantiation(resultArray); - } - - private static TypeDesc GetTypeThatMeetsConstraints(GenericParameterDesc genericParam, bool allowCanon) - { - TypeSystemContext context = genericParam.Context; - - // Universal canon is the best option if it's supported - if (allowCanon && context.SupportsUniversalCanon) - return context.UniversalCanonType; - - // Not nullable type is the only thing where we can't substitute reference types - GenericConstraints constraints = genericParam.Constraints; - if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) - return null; - - // If canon is allowed, we can use that - if (allowCanon && context.SupportsCanon) - { - foreach (var c in genericParam.TypeConstraints) - { - // Could be e.g. "where T : U" - // We could try to dig into the U and solve it, but that just opens us up to - // recursion and it's just not worth it. - if (c.IsSignatureVariable) - return null; - - if (!c.IsGCPointer) - return null; - } - - return genericParam.Context.CanonType; - } - - // If canon is not allowed, we're limited in our choices. - TypeDesc constrainedType = null; - foreach (var c in genericParam.TypeConstraints) - { - // Can't do multiple constraints - if (constrainedType != null) - return null; - - // Could be e.g. "where T : IFoo" or "where T : U" - if (c.ContainsSignatureVariables()) - return null; - - constrainedType = c; - } - - return constrainedType ?? genericParam.Context.GetWellKnownType(WellKnownType.Object); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Compiler/VectorFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/Compiler/VectorFieldLayoutAlgorithm.cs deleted file mode 100644 index f52f18cf842..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Compiler/VectorFieldLayoutAlgorithm.cs +++ /dev/null @@ -1,115 +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 Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace ILCompiler -{ - /// - /// Represents an algorithm that computes field layout for intrinsic vector types (Vector64/Vector128/Vector256). - /// - public class VectorFieldLayoutAlgorithm : FieldLayoutAlgorithm - { - private readonly FieldLayoutAlgorithm _fallbackAlgorithm; - - public VectorFieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm) - { - _fallbackAlgorithm = fallbackAlgorithm; - } - - public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind) - { - Debug.Assert(IsVectorType(defType)); - - LayoutInt alignment; - - string name = defType.Name; - if (name == "Vector64`1") - { - alignment = new LayoutInt(8); - } - else if (name == "Vector128`1") - { - if (defType.Context.Target.Architecture == TargetArchitecture.ARM) - { - // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128 - alignment = new LayoutInt(8); - } - else - { - alignment = new LayoutInt(16); - } - } - else - { - Debug.Assert(name == "Vector256`1"); - - if (defType.Context.Target.Architecture == TargetArchitecture.ARM) - { - // No such type exists for the Procedure Call Standard for ARM. We will default - // to the same alignment as __m128, which is supported by the ABI. - alignment = new LayoutInt(8); - } - else if (defType.Context.Target.Architecture == TargetArchitecture.ARM64) - { - // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to - // 16-byte alignment for __m256. - alignment = new LayoutInt(16); - } - else - { - alignment = new LayoutInt(32); - } - } - - ComputedInstanceFieldLayout layoutFromMetadata = _fallbackAlgorithm.ComputeInstanceLayout(defType, layoutKind); - - return new ComputedInstanceFieldLayout - { - ByteCountUnaligned = layoutFromMetadata.ByteCountUnaligned, - ByteCountAlignment = layoutFromMetadata.ByteCountAlignment, - FieldAlignment = alignment, - FieldSize = layoutFromMetadata.FieldSize, - Offsets = layoutFromMetadata.Offsets, - }; - } - - public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind) - { - return _fallbackAlgorithm.ComputeStaticFieldLayout(defType, layoutKind); - } - - public override bool ComputeContainsGCPointers(DefType type) - { - Debug.Assert(!_fallbackAlgorithm.ComputeContainsGCPointers(type)); - return false; - } - - public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) - { - return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type); - } - - public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) - { - return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type); - } - - public static bool IsVectorType(DefType type) - { - return type.IsIntrinsic && - type.Namespace == "System.Runtime.Intrinsics" && - (type.Name == "Vector64`1" || - type.Name == "Vector128`1" || - type.Name == "Vector256`1"); - } - - public static bool IsVectorOfTType(DefType type) - { - return type.IsIntrinsic && type.Namespace == "System.Numerics" && type.Name == "Vector`1"; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormat.cs b/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormat.cs deleted file mode 100644 index 3c8539adcfe..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormat.cs +++ /dev/null @@ -1,232 +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; - -// -// Native Format -// -// NativeFormat is a binary metadata format. It primarily designed for storing layout decisions done by static code -// generator that the dynamic code generator needs to be aware of. However, it can be also used for storing general -// managed code metadata in future. The key properties of the format are: -// -// - Extensible: It should be possible to attach new data to existing records without breaking existing consumers that -// do not understand the new data yet. -// -// - Naturally compressed: Integers are stored using variable length encoding. Offsets are stored as relative offsets. -// -// - Random access: Random access to selected information should be fast. It is achieved by using tokens as offsets. -// -// - Locality: Access to related information should be accessing data that are close to each other. -// -// The format is essentially a collection of variable size records that can reference each other. -// - -namespace Internal.NativeFormat -{ - // - // Bag is the key record type for extensibility. It is a list pairs. Data is integer that - // is interpretted according to the id. It is typically relative offset of another record. - // -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum BagElementKind : uint - { - End = 0x00, - BaseType = 0x01, - ImplementedInterfaces = 0x02, - - DictionaryLayout = 0x40, - TypeFlags = 0x41, - NonGcStaticData = 0x42, - GcStaticData = 0x43, - NonGcStaticDataSize = 0x44, - GcStaticDataSize = 0x45, - GcStaticDesc = 0x46, - ThreadStaticDataSize = 0x47, - ThreadStaticDesc = 0x48, - ThreadStaticIndex = 0x49, - ThreadStaticOffset = 0x4a, - FieldLayout = 0x4b, - VTableMethodSignatures = 0x4c, - SealedVTableEntries = 0x4d, - ClassConstructorPointer = 0x4e, - BaseTypeSize = 0x4f, - GenericVarianceInfo = 0x50, - DelegateInvokeSignature = 0x51, - GcStaticEEType = 0x52, - - // Add new custom bag elements that don't match to something you'd find in the ECMA metadata here. - } - - // - // FixupSignature signature describes indirection. It starts with integer describing the kind of data stored in the indirection, - // followed by kind-specific signature. - // -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum FixupSignatureKind : uint - { - Null = 0x00, - TypeHandle = 0x01, - InterfaceCall = 0x02, - // unused = 0x03, - MethodDictionary = 0x04, - StaticData = 0x05, - UnwrapNullableType = 0x06, - FieldLdToken = 0x07, - MethodLdToken = 0x08, - AllocateObject = 0x09, - DefaultConstructor = 0x0a, - TlsIndex = 0x0b, - TlsOffset = 0x0c, - Method = 0x0d, - IsInst = 0x0e, - CastClass = 0x0f, - AllocateArray = 0x10, - CheckArrayElementType = 0x11, - TypeSize = 0x12, - FieldOffset = 0x13, - CallingConventionConverter = 0x14, - VTableOffset = 0x15, - NonGenericConstrainedMethod = 0x16, - GenericConstrainedMethod = 0x17, - NonGenericDirectConstrainedMethod = 0x18, - PointerToOtherSlot = 0x19, - IntValue = 0x20, - - NotYetSupported = 0xee, - } - - // - // TypeSignature describes type. The low 4 bits of the integer that is starts with describe the kind. Upper 28 bits are kind - // specific data. The argument signatures immediately follow for nested types. - // -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum TypeSignatureKind : uint - { - Null = 0x0, - Lookback = 0x1, // Go back in the stream for signature continuation (data - number of bytes to go back) - Modifier = 0x2, // Type modifier (data - TypeModifierKind) - Instantiation = 0x3, // Generic instantiation (data - number of instantiation args) - Variable = 0x4, // Generic variable (data - 2 * varnum + method) - BuiltIn = 0x5, // Built-in type (data - BuildInTypeKind) - External = 0x6, // External type reference (data - external type id) - - MultiDimArray = 0xA, // Multi-dimensional array (data - dimension) - FunctionPointer = 0xB, // Function pointer (data - calling convention, arg count, args) - }; - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum TypeModifierKind : uint - { - Array = 0x1, - ByRef = 0x2, - Pointer = 0x3, - }; - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum StaticDataKind : uint - { - Gc = 0x1, - NonGc = 0x2, - }; - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum GenericContextKind : uint - { - FromThis = 0x00, - FromHiddenArg = 0x01, - FromMethodHiddenArg = 0x02, - - HasDeclaringType = 0x04, - - NeedsUSGContext = 0x08, - }; - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum CallingConventionConverterKind : uint - { - NoInstantiatingParam = 0x00, // The calling convention interpreter can assume that the calling convention of the target method has no instantiating parameter - HasInstantiatingParam = 0x01, // The calling convention interpreter can assume that the calling convention of the target method has an instantiating parameter - MaybeInstantiatingParam = 0x02, // The calling convention interpreter can assume that the calling convention of the target method may be a fat function pointer - } - - [Flags] -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum TypeFlags : uint - { - HasClassConstructor = 0x1, - HasInstantiationDeterminedSize = 0x2, - }; - - [Flags] -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum MethodFlags : uint - { - HasInstantiation = 0x1, - IsUnboxingStub = 0x2, - HasFunctionPointer = 0x4, - FunctionPointerIsUSG = 0x8, - }; - - [Flags] -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum MethodCallingConvention : uint - { - Generic = 0x1, - Static = 0x2, - }; - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - enum FieldStorage : uint - { - Instance = 0x0, - NonGCStatic = 0x1, - GCStatic = 0x2, - TLSStatic = 0x3, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormatWriter.Primitives.cs b/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormatWriter.Primitives.cs deleted file mode 100644 index 52a917c9a9c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormatWriter.Primitives.cs +++ /dev/null @@ -1,198 +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 System.IO; -using System.Diagnostics; - -namespace Internal.NativeFormat -{ - internal struct NativePrimitiveEncoder - { - private byte[] _buffer; - private int _size; - - public void Init() - { - _buffer = new byte[128]; - _size = 0; - } - - public int Size { get { return _size; } } - public void Clear() { _size = 0; } - public void RollbackTo(int offset) { _size = offset; } - - public void WriteByte(byte b) - { - if (_buffer.Length == _size) - Array.Resize(ref _buffer, 2 * _buffer.Length); - _buffer[_size++] = b; - } - - public void WriteUInt8(byte value) - { - WriteByte(value); - } - - public void WriteUInt16(ushort value) - { - WriteByte((byte)value); - WriteByte((byte)(value >> 8)); - } - - public void WriteUInt32(uint value) - { - WriteByte((byte)value); - WriteByte((byte)(value >> 8)); - WriteByte((byte)(value >> 16)); - WriteByte((byte)(value >> 24)); - } - - public void WriteUInt64(ulong value) - { - WriteUInt32((uint)value); - WriteUInt32((uint)(value >> 32)); - } - - public unsafe void WriteFloat(float value) - { - WriteUInt32(*((uint*)&value)); - } - - public unsafe void WriteDouble(double value) - { - WriteUInt64(*((ulong*)&value)); - } - - // - // Same encoding as what's used by CTL - // - public void WriteUnsigned(uint d) - { - if (d < 128) - { - WriteByte((byte)(d * 2 + 0)); - } - else if (d < 128 * 128) - { - WriteByte((byte)(d * 4 + 1)); - WriteByte((byte)(d >> 6)); - } - else if (d < 128 * 128 * 128) - { - WriteByte((byte)(d * 8 + 3)); - WriteByte((byte)(d >> 5)); - WriteByte((byte)(d >> 13)); - } - else if (d < 128 * 128 * 128 * 128) - { - WriteByte((byte)(d * 16 + 7)); - WriteByte((byte)(d >> 4)); - WriteByte((byte)(d >> 12)); - WriteByte((byte)(d >> 20)); - } - else - { - WriteByte((byte)15); - WriteUInt32(d); - } - } - - public static int GetUnsignedEncodingSize(uint d) - { - if (d < 128) return 1; - if (d < 128 * 128) return 2; - if (d < 128 * 128 * 128) return 3; - if (d < 128 * 128 * 128 * 128) return 4; - return 5; - } - - public void WriteSigned(int i) - { - uint d = (uint)i; - if (d + 64 < 128) - { - WriteByte((byte)(d * 2 + 0)); - } - else if (d + 64 * 128 < 128 * 128) - { - WriteByte((byte)(d * 4 + 1)); - WriteByte((byte)(d >> 6)); - } - else if (d + 64 * 128 * 128 < 128 * 128 * 128) - { - WriteByte((byte)(d * 8 + 3)); - WriteByte((byte)(d >> 5)); - WriteByte((byte)(d >> 13)); - } - else if (d + 64 * 128 * 128 * 128 < 128 * 128 * 128 * 128) - { - WriteByte((byte)(d * 16 + 7)); - WriteByte((byte)(d >> 4)); - WriteByte((byte)(d >> 12)); - WriteByte((byte)(d >> 20)); - } - else - { - WriteByte((byte)15); - WriteUInt32(d); - } - } - - public void WriteUnsignedLong(ulong i) - { - if ((uint)i == i) - { - WriteUnsigned((uint)i); - return; - } - - WriteByte((byte)31); - WriteUInt64(i); - } - - public void WriteSignedLong(long i) - { - if ((int)i == i) - { - WriteSigned((int)i); - return; - } - - WriteByte((byte)31); - WriteUInt64((ulong)i); - } - - public void PatchByteAt(int offset, byte value) - { - Debug.Assert(offset < _size); - _buffer[offset] = value; - } - - public void Save(Stream stream) - { - stream.Write(_buffer, 0, _size); - } - - public unsafe bool Save(byte* stream, int streamLength) - { - if (streamLength < _size) - { - Debug.Assert(false); - return false; - } - for (int i = 0; i < _size; i++) - stream[i] = _buffer[i]; - return true; - } - - public byte[] GetBytes() - { - byte[] retBuffer = new byte[_size]; - for (int i = 0; i < _size; i++) - retBuffer[i] = _buffer[i]; - return retBuffer; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormatWriter.cs b/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormatWriter.cs deleted file mode 100644 index c170e3707f8..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Internal/NativeFormat/NativeFormatWriter.cs +++ /dev/null @@ -1,2147 +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 System.IO; -using System.Diagnostics; -using System.Collections.Generic; -using System.Text; - -// Managed mirror of NativeFormatWriter.h/.cpp -namespace Internal.NativeFormat -{ -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - abstract class Vertex - { - internal int _offset = NotPlaced; - internal int _iteration = -1; // Iteration that the offset is valid for - - internal const int NotPlaced = -1; - internal const int Placed = -2; - internal const int Unified = -3; - - public Vertex() - { - } - - internal abstract void Save(NativeWriter writer); - - public int VertexOffset - { - get - { - Debug.Assert(_offset >= 0); - return _offset; - } - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class Section - { - internal List _items = new List(); - internal Dictionary _placedMap = new Dictionary(); - - public Section() - { - } - - public Vertex Place(Vertex vertex) - { - if (vertex._offset == Vertex.Unified) - { - Vertex placedVertex; - if (_placedMap.TryGetValue(vertex, out placedVertex)) - return placedVertex; - - placedVertex = new PlacedVertex(vertex); - _placedMap.Add(vertex, placedVertex); - vertex = placedVertex; - } - - Debug.Assert(vertex._offset == Vertex.NotPlaced); - vertex._offset = Vertex.Placed; - _items.Add(vertex); - - return vertex; - } - - public Vertex Pop() - { - Vertex vertex = _items[_items.Count - 1]; - _items.RemoveAt(_items.Count - 1); - Debug.Assert(vertex._offset == Vertex.Placed); - vertex._offset = Vertex.NotPlaced; - return vertex; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class NativeWriter - { - List
_sections = new List
(); - - enum SavePhase - { - Initial, - Shrinking, - Growing - } - - - int _iteration = 0; - SavePhase _phase; // Current save phase - int _offsetAdjustment; // Cumulative offset adjustment compared to previous iteration - int _paddingSize; // How much padding was used - - Dictionary _unifier = new Dictionary(); - - NativePrimitiveEncoder _encoder = new NativePrimitiveEncoder(); - -#if NATIVEFORMAT_COMPRESSION - struct Tentative - { - internal Vertex Vertex; - internal int PreviousOffset; - } - - // State used by compression - List _tentativelyWritten = new List(); // Tentatively written Vertices. - int _compressionDepth = 0; -#endif - - public NativeWriter() - { - _encoder.Init(); - } - - public Section NewSection() - { - Section section = new Section(); - _sections.Add(section); - return section; - } - - public void WriteByte(byte b) { _encoder.WriteByte(b); } - public void WriteUInt8(byte value) { _encoder.WriteUInt8(value); } - public void WriteUInt16(ushort value) { _encoder.WriteUInt16(value); } - public void WriteUInt32(uint value) { _encoder.WriteUInt32(value); } - public void WriteUInt64(ulong value) { _encoder.WriteUInt64(value); } - public void WriteUnsigned(uint d) { _encoder.WriteUnsigned(d); } - public void WriteSigned(int i) { _encoder.WriteSigned(i); } - public void WriteUnsignedLong(ulong i) { _encoder.WriteUnsignedLong(i); } - public void WriteSignedLong(long i) { _encoder.WriteSignedLong(i); } - public void WriteFloat(float value) { _encoder.WriteFloat(value); } - public void WriteDouble(double value) { _encoder.WriteDouble(value); } - - public void WritePad(int size) - { - while (size > 0) - { - _encoder.WriteByte(0); - size--; - } - } - - public bool IsGrowing() - { - return _phase == SavePhase.Growing; - } - - public void UpdateOffsetAdjustment(int offsetDelta) - { - switch (_phase) - { - case SavePhase.Shrinking: - _offsetAdjustment = Math.Min(_offsetAdjustment, offsetDelta); - break; - case SavePhase.Growing: - _offsetAdjustment = Math.Max(_offsetAdjustment, offsetDelta); - break; - default: - break; - } - } - - public void RollbackTo(int offset) - { - _encoder.RollbackTo(offset); - } - - public void RollbackTo(int offset, int offsetAdjustment) - { - _offsetAdjustment = offsetAdjustment; - RollbackTo(offset); - } - - public void PatchByteAt(int offset, byte value) - { - _encoder.PatchByteAt(offset, value); - } - - // Swallow exceptions if invalid encoding is detected. - // This is the price we have to pay for using UTF8. Thing like High Surrogate Start Char - '\ud800' - // can be expressed in UTF-16 (which is the format used to store ECMA metadata), but don't have - // a representation in UTF-8. - private static Encoding _stringEncoding = new UTF8Encoding(false, false); - - public void WriteString(string s) - { - // The actual bytes are only necessary for the final version during the growing plase - if (IsGrowing()) - { - byte[] bytes = _stringEncoding.GetBytes(s); - - _encoder.WriteUnsigned((uint)bytes.Length); - for (int i = 0; i < bytes.Length; i++) - _encoder.WriteByte(bytes[i]); - } - else - { - int byteCount = _stringEncoding.GetByteCount(s); - _encoder.WriteUnsigned((uint)byteCount); - WritePad(byteCount); - } - } - - public void WriteRelativeOffset(Vertex val) - { - if (val._iteration == -1) - { - // If the offsets are not determined yet, use the maximum possible encoding - _encoder.WriteSigned(0x7FFFFFFF); - return; - } - - int offset = val._offset; - - // If the offset was not update in this iteration yet, adjust it by delta we have accumulated in this iteration so far. - // This adjustment allows the offsets to converge faster. - if (val._iteration < _iteration) - offset += _offsetAdjustment; - - _encoder.WriteSigned(offset - GetCurrentOffset()); - } - - public int GetExpectedOffset(Vertex val) - { - Debug.Assert(val._offset != Vertex.NotPlaced); - - if (val._iteration == -1) - { - // If the offsets are not determined yet, use the maximum possible encoding - return 0x7FFFFFFF; - } - - int offset = val._offset; - - // If the offset was not update in this iteration yet, adjust it by delta we have accumulated in this iteration so far. - // This adjustment allows the offsets to converge faster. - if (val._iteration < _iteration) - offset += _offsetAdjustment; - - return offset; - } - - public int GetCurrentOffset(Vertex val) - { - if (val._iteration != _iteration) - return -1; - - return val._offset; - } - - public int GetCurrentOffset() - { - return _encoder.Size; - } - - public int GetNumberOfIterations() - { - return _iteration; - } - - public int GetPaddingSize() - { - return _paddingSize; - } - - public void Save(Stream stream) - { - _encoder.Clear(); - - _phase = SavePhase.Initial; - foreach (var section in _sections) foreach (var vertex in section._items) - { - vertex._offset = GetCurrentOffset(); - vertex._iteration = _iteration; - vertex.Save(this); - -#if NATIVEFORMAT_COMPRESSION - // Ensure that the compressor state is fully flushed - Debug.Assert(_TentativelyWritten.Count == 0); - Debug.Assert(_compressionDepth == 0); -#endif - } - - // Aggressive phase that only allows offsets to shrink. - _phase = SavePhase.Shrinking; - for (; ; ) - { - _iteration++; - _encoder.Clear(); - - _offsetAdjustment = 0; - - foreach (var section in _sections) foreach (var vertex in section._items) - { - int currentOffset = GetCurrentOffset(); - - // Only allow the offsets to shrink. - _offsetAdjustment = Math.Min(_offsetAdjustment, currentOffset - vertex._offset); - - vertex._offset += _offsetAdjustment; - - if (vertex._offset < currentOffset) - { - // It is possible for the encoding of relative offsets to grow during some iterations. - // Ignore this growth because of it should disappear during next iteration. - RollbackTo(vertex._offset); - } - Debug.Assert(vertex._offset == GetCurrentOffset()); - - vertex._iteration = _iteration; - - vertex.Save(this); - -#if NATIVEFORMAT_COMPRESSION - // Ensure that the compressor state is fully flushed - Debug.Assert(_tentativelyWritten.Count == 0); - Debug.Assert(_compressionDepth == 0); -#endif - } - - // We are not able to shrink anymore. We cannot just return here. It is possible that we have rolledback - // above because of we shrinked too much. - if (_offsetAdjustment == 0) - break; - - // Limit number of shrinking interations. This limit is meant to be hit in corner cases only. - if (_iteration > 10) - break; - } - - // Conservative phase that only allows the offsets to grow. It is guaranteed to converge. - _phase = SavePhase.Growing; - for (; ; ) - { - _iteration++; - _encoder.Clear(); - - _offsetAdjustment = 0; - _paddingSize = 0; - - foreach (var section in _sections) foreach (var vertex in section._items) - { - int currentOffset = GetCurrentOffset(); - - // Only allow the offsets to grow. - _offsetAdjustment = Math.Max(_offsetAdjustment, currentOffset - vertex._offset); - - vertex._offset += _offsetAdjustment; - - if (vertex._offset > currentOffset) - { - // Padding - int padding = vertex._offset - currentOffset; - _paddingSize += padding; - WritePad(padding); - } - Debug.Assert(vertex._offset == GetCurrentOffset()); - - vertex._iteration = _iteration; - - vertex.Save(this); - -#if NATIVEFORMAT_COMPRESSION - // Ensure that the compressor state is fully flushed - Debug.Assert(_tentativelyWritten.Count == 0); - Debug.Assert(_compressionDepth == 0); -#endif - } - - if (_offsetAdjustment == 0) - { - _encoder.Save(stream); - return; - } - } - } - -#if NATIVEFORMAT_COMPRESSION - // TODO: -#else - internal struct TypeSignatureCompressor - { - internal TypeSignatureCompressor(NativeWriter pWriter) { } - internal void Pack(Vertex vertex) { } - } -#endif - - T Unify(T vertex) where T : Vertex - { - Vertex existing; - if (_unifier.TryGetValue(vertex, out existing)) - return (T)existing; - - Debug.Assert(vertex._offset == Vertex.NotPlaced); - vertex._offset = Vertex.Unified; - _unifier.Add(vertex, vertex); - - return vertex; - } - - public Vertex GetUnsignedConstant(uint value) - { - UnsignedConstant vertex = new UnsignedConstant(value); - return Unify(vertex); - } - - public Vertex GetTuple(Vertex item1, Vertex item2) - { - Tuple vertex = new Tuple(item1, item2); - return Unify(vertex); - } - - public Vertex GetTuple(Vertex item1, Vertex item2, Vertex item3) - { - Tuple vertex = new Tuple(item1, item2, item3); - return Unify(vertex); - } - - public Vertex GetMethodNameAndSigSignature(string name, Vertex signature) - { - MethodNameAndSigSignature sig = new MethodNameAndSigSignature( - GetStringConstant(name), - GetRelativeOffsetSignature(signature)); - return Unify(sig); - } - - public Vertex GetStringConstant(string value) - { - StringConstant vertex = new StringConstant(value); - return Unify(vertex); - } - - public Vertex GetRelativeOffsetSignature(Vertex item) - { - RelativeOffsetSignature sig = new RelativeOffsetSignature(item); - return Unify(sig); - } - - public Vertex GetOffsetSignature(Vertex item) - { - OffsetSignature sig = new OffsetSignature(item); - return Unify(sig); - } - - public Vertex GetExternalTypeSignature(uint externalTypeId) - { - ExternalTypeSignature sig = new ExternalTypeSignature(externalTypeId); - return Unify(sig); - } - - public Vertex GetMethodSignature(uint flags, uint fptrReferenceId, Vertex containingType, Vertex methodNameAndSig, Vertex[] args) - { - MethodSignature sig = new MethodSignature(flags, fptrReferenceId, containingType, methodNameAndSig, args); - return Unify(sig); - } - - public Vertex GetFieldSignature(Vertex containingType, string name) - { - FieldSignature sig = new FieldSignature(containingType, name); - return Unify(sig); - } - - public Vertex GetFixupSignature(FixupSignatureKind kind, Vertex signature) - { - FixupSignature sig = new FixupSignature(kind, signature); - return Unify(sig); - } - - public Vertex GetStaticDataSignature(Vertex type, StaticDataKind staticDataKind) - { - StaticDataSignature sig = new StaticDataSignature(type, staticDataKind); - return Unify(sig); - } - - public Vertex GetMethodSlotSignature(Vertex type, uint slot) - { - MethodSlotSignature sig = new MethodSlotSignature(type, slot); - return Unify(sig); - } - - public Vertex GetMethodSigSignature(uint callingConvention, uint genericArgCount, Vertex returnType, Vertex[] parameters) - { - MethodSigSignature sig = new MethodSigSignature(callingConvention, genericArgCount, returnType, parameters); - return Unify(sig); - } - - public Vertex GetModifierTypeSignature(TypeModifierKind modifier, Vertex param) - { - ModifierTypeSignature sig = new ModifierTypeSignature(modifier, param); - return Unify(sig); - } - - public Vertex GetVariableTypeSignature(uint index, bool method) - { - VariableTypeSignature sig = new VariableTypeSignature(index, method); - return Unify(sig); - } - - public Vertex GetInstantiationTypeSignature(Vertex typeDef, Vertex[] arguments) - { - InstantiationTypeSignature sig = new InstantiationTypeSignature(typeDef, arguments); - return Unify(sig); - } - - public Vertex GetMDArrayTypeSignature(Vertex elementType, uint rank, uint[] bounds, uint[] lowerBounds) - { - MDArrayTypeSignature sig = new MDArrayTypeSignature(elementType, rank, bounds, lowerBounds); - return Unify(sig); - } - - public Vertex GetCallingConventionConverterSignature(uint flags, Vertex signature) - { - CallingConventionConverterSignature sig = new CallingConventionConverterSignature(flags, GetRelativeOffsetSignature(signature)); - return Unify(sig); - } - } - - class PlacedVertex : Vertex - { - Vertex _unified; - - public PlacedVertex(Vertex unified) - { - _unified = unified; - } - - internal override void Save(NativeWriter writer) - { - _unified.Save(writer); - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class UnsignedConstant : Vertex - { - uint _value; - - public UnsignedConstant(uint value) - { - _value = value; - } - - internal override void Save(NativeWriter writer) - { - writer.WriteUnsigned(_value); - } - - public override int GetHashCode() - { - return 6659 + ((int)_value) * 19; - } - public override bool Equals(object other) - { - if (!(other is UnsignedConstant)) - return false; - - UnsignedConstant p = (UnsignedConstant)other; - if (_value != p._value) return false; - return true; - } - } - - class Tuple : Vertex - { - private Vertex _item1; - private Vertex _item2; - private Vertex _item3; - - public Tuple(Vertex item1, Vertex item2, Vertex item3 = null) - { - _item1 = item1; - _item2 = item2; - _item3 = item3; - } - - internal override void Save(NativeWriter writer) - { - _item1.Save(writer); - _item2.Save(writer); - if (_item3 != null) - _item3.Save(writer); - } - - public override int GetHashCode() - { - int hash = _item1.GetHashCode() * 93481 + _item2.GetHashCode() + 3492; - if (_item3 != null) - hash += (hash << 7) + _item3.GetHashCode() * 34987 + 213; - return hash; - } - - public override bool Equals(object obj) - { - Tuple other = obj as Tuple; - if (other == null) - return false; - - return Object.Equals(_item1, other._item1) && - Object.Equals(_item2, other._item2) && - Object.Equals(_item3, other._item3); - } - } - - // - // Bag of pairs. Good for extensible information (e.g. type info) - // - // Data can be either relative offset of another vertex, or arbitrary integer. - // -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class VertexBag : Vertex - { - enum EntryType { Vertex, Unsigned, Signed } - - struct Entry - { - internal BagElementKind _id; - internal EntryType _type; - internal object _value; - - internal Entry(BagElementKind id, Vertex value) - { - _id = id; - _type = EntryType.Vertex; - _value = value; - } - - internal Entry(BagElementKind id, uint value) - { - _id = id; - _type = EntryType.Unsigned; - _value = value; - } - - internal Entry(BagElementKind id, int value) - { - _id = id; - _type = EntryType.Signed; - _value = value; - } - } - - private List _elements; - - public VertexBag() - { - _elements = new List(); - } - - public void Append(BagElementKind id, Vertex value) - { - _elements.Add(new Entry(id, value)); - } - - public void AppendUnsigned(BagElementKind id, uint value) - { - _elements.Add(new Entry(id, value)); - } - - public void AppendSigned(BagElementKind id, int value) - { - _elements.Add(new Entry(id, value)); - } - - internal override void Save(NativeWriter writer) - { - foreach (var elem in _elements) - { - writer.WriteUnsigned((uint)elem._id); - - switch (elem._type) - { - case EntryType.Vertex: - writer.WriteRelativeOffset((Vertex)elem._value); - break; - - case EntryType.Unsigned: - writer.WriteUnsigned((uint)elem._value); - break; - - case EntryType.Signed: - writer.WriteSigned((int)elem._value); - break; - - } - } - writer.WriteUnsigned((uint)BagElementKind.End); - } - - public int ElementsCount => _elements.Count; - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class VertexSequence : Vertex - { - private List _elements; - - public VertexSequence() - { - _elements = new List(); - } - - public void Append(Vertex vertex) - { - _elements.Add(vertex); - } - - internal override void Save(NativeWriter writer) - { - writer.WriteUnsigned((uint)_elements.Count); - foreach (var elem in _elements) - elem.Save(writer); - } - - public override bool Equals(object obj) - { - var other = obj as VertexSequence; - if (other == null || other._elements.Count != _elements.Count) - return false; - - for (int i = 0; i < _elements.Count; i++) - if (!Object.Equals(_elements[i], other._elements[i])) - return false; - - return true; - } - - public override int GetHashCode() - { - int hashCode = 13; - foreach (var element in _elements) - { - int value = (element != null ? element.GetHashCode() : 0) * 0x5498341 + 0x832424; - hashCode = hashCode * 31 + value; - } - - return hashCode; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class MethodNameAndSigSignature : Vertex - { - private Vertex _methodName; - private Vertex _signature; - - public MethodNameAndSigSignature(Vertex methodName, Vertex signature) - { - _methodName = methodName; - _signature = signature; - } - - internal override void Save(NativeWriter writer) - { - _methodName.Save(writer); - _signature.Save(writer); - } - - public override int GetHashCode() - { - return 509 * 197 + _methodName.GetHashCode() + 647 * _signature.GetHashCode(); - } - - public override bool Equals(object obj) - { - MethodNameAndSigSignature other = obj as MethodNameAndSigSignature; - if (other == null) - return false; - - return Object.Equals(_methodName, other._methodName) && Object.Equals(_signature, other._signature); - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class StringConstant : Vertex - { - private string _value; - - public StringConstant(string value) - { - _value = value; - } - - internal override void Save(NativeWriter writer) - { - writer.WriteString(_value); - } - - public override int GetHashCode() - { - return _value.GetHashCode(); - } - - public override bool Equals(object obj) - { - StringConstant other = obj as StringConstant; - if (other == null) - return false; - - return _value == other._value; - } - } - - // - // Performs indirection to an existing native layout signature by writing out the - // relative offset. - // -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class RelativeOffsetSignature : Vertex - { - private Vertex _item; - - public RelativeOffsetSignature(Vertex item) - { - _item = item; - } - - internal override void Save(NativeWriter writer) - { - writer.WriteRelativeOffset(_item); - } - - public override int GetHashCode() - { - return _item.GetHashCode() >> 3; - } - - public override bool Equals(object obj) - { - RelativeOffsetSignature other = obj as RelativeOffsetSignature; - if (other == null) - return false; - - return Object.Equals(_item, other._item); - } - } - - // - // Performs indirection to an existing native layout signature using offset from the - // beginning of the native format. This allows cross-native layout references. You must - // ensure that the native layout writer of the pointee is saved before that of the pointer - // so the offsets are locked down. - // -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class OffsetSignature : Vertex - { - private Vertex _item; - - public OffsetSignature(Vertex item) - { - _item = item; - } - - internal override void Save(NativeWriter writer) - { - writer.WriteUnsigned((uint)_item.VertexOffset); - } - - public override int GetHashCode() - { - return _item.GetHashCode(); - } - - public override bool Equals(object obj) - { - OffsetSignature other = obj as OffsetSignature; - if (other == null) - return false; - - return Object.Equals(_item, other._item); - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class ExternalTypeSignature : Vertex - { - private uint _externalTypeId; - - public ExternalTypeSignature(uint externalTypeId) - { - _externalTypeId = externalTypeId; - } - - internal override void Save(NativeWriter writer) - { - NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); - - writer.WriteUnsigned((uint)TypeSignatureKind.External | (_externalTypeId << 4)); - - compressor.Pack(this); - } - - public override int GetHashCode() - { - return 32439 + 11 * (int)_externalTypeId; - } - - public override bool Equals(object obj) - { - ExternalTypeSignature other = obj as ExternalTypeSignature; - if (other == null) - return false; - - return _externalTypeId == other._externalTypeId; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class MethodSignature : Vertex - { - private uint _flags; - private uint _fptrReferenceId; - private Vertex _containingType; - private Vertex _methodNameAndSig; - private Vertex[] _args; - - public MethodSignature(uint flags, uint fptrReferenceId, Vertex containingType, Vertex methodNameAndSig, Vertex[] args) - { - _flags = flags; - _fptrReferenceId = fptrReferenceId; - _containingType = containingType; - _methodNameAndSig = methodNameAndSig; - _args = args; - - if ((flags & (uint)MethodFlags.HasInstantiation) != 0) - Debug.Assert(args != null && args.Length > 0); - if ((flags & (uint)MethodFlags.HasFunctionPointer) == 0) - Debug.Assert(fptrReferenceId == 0); - } - - internal override void Save(NativeWriter writer) - { - writer.WriteUnsigned(_flags); - if ((_flags & (uint)MethodFlags.HasFunctionPointer) != 0) - writer.WriteUnsigned(_fptrReferenceId); - _containingType.Save(writer); - _methodNameAndSig.Save(writer); - if ((_flags & (uint)MethodFlags.HasInstantiation) != 0) - { - writer.WriteUnsigned((uint)_args.Length); - for (uint iArg = 0; _args != null && iArg < _args.Length; iArg++) - _args[iArg].Save(writer); - } - } - - public override int GetHashCode() - { - int hash = _args != null ? _args.Length : 0; - hash += (hash << 5) + (int)_flags * 23; - hash += (hash << 5) + (int)_fptrReferenceId * 119; - hash += (hash << 5) + _containingType.GetHashCode(); - for (uint iArg = 0; _args != null && iArg < _args.Length; iArg++) - hash += (hash << 5) + _args[iArg].GetHashCode(); - hash += (hash << 5) + _methodNameAndSig.GetHashCode(); - return hash; - } - - public override bool Equals(object obj) - { - MethodSignature other = obj as MethodSignature; - if (other == null) - return false; - - if (!( - _flags == other._flags && - _fptrReferenceId == other._fptrReferenceId && - Object.Equals(_containingType, other._containingType) && - Object.Equals(_methodNameAndSig, other._methodNameAndSig))) - { - return false; - } - - if (_args != null) - { - if (other._args == null) return false; - if (other._args.Length != _args.Length) return false; - for (uint iArg = 0; _args != null && iArg < _args.Length; iArg++) - if (!Object.Equals(_args[iArg], other._args[iArg])) - return false; - } - else if (other._args != null) - return false; - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class FieldSignature : Vertex - { - private Vertex _containingType; - private string _name; - - public FieldSignature(Vertex containingType, string name) - { - _containingType = containingType; - _name = name; - } - - internal override void Save(NativeWriter writer) - { - _containingType.Save(writer); - writer.WriteString(_name); - } - - public override int GetHashCode() - { - int hash = 113 + 97 * _containingType.GetHashCode(); - foreach (char c in _name) - hash += (hash << 5) + c * 19; - - return hash; - } - - public override bool Equals(object obj) - { - var other = obj as FieldSignature; - if (other == null) - return false; - - if (!Object.Equals(other._containingType, _containingType)) - return false; - - if (!Object.Equals(other._name, _name)) - return false; - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class FixupSignature : Vertex - { - private FixupSignatureKind _kind; - private Vertex _signature; - - public FixupSignature(FixupSignatureKind kind, Vertex signature) - { - _kind = kind; - _signature = signature; - } - - internal override void Save(NativeWriter writer) - { - writer.WriteUnsigned((uint)_kind); - if (_signature != null) - _signature.Save(writer); - } - - public override int GetHashCode() - { - return 53345 + 97 * (int)_kind + ((_signature != null) ? _signature.GetHashCode() : 0); - } - - public override bool Equals(object obj) - { - var other = obj as FixupSignature; - if (other == null) - return false; - - if (other._kind != _kind) - return false; - - if (!Object.Equals(other._signature, _signature)) - return false; - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class StaticDataSignature : Vertex - { - private Vertex _type; - private StaticDataKind _staticDataKind; - - public StaticDataSignature(Vertex type, StaticDataKind staticDataKind) - { - _type = type; - _staticDataKind = staticDataKind; - } - - internal override void Save(NativeWriter writer) - { - _type.Save(writer); - writer.WriteUnsigned((uint)_staticDataKind); - } - - public override int GetHashCode() - { - return 456789 + 101 * (int)_staticDataKind + _type.GetHashCode(); - } - - public override bool Equals(object obj) - { - var other = obj as StaticDataSignature; - if (other == null) - return false; - - if (!Object.Equals(other._type, _type)) - return false; - - if (other._staticDataKind != _staticDataKind) - return false; - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class MethodSlotSignature : Vertex - { - private Vertex _type; - private uint _slot; - - public MethodSlotSignature(Vertex type, uint slot) - { - _type = type; - _slot = slot; - } - - internal override void Save(NativeWriter writer) - { - _type.Save(writer); - writer.WriteUnsigned(_slot); - } - - public override int GetHashCode() - { - return 124121 + 47 * (int)_slot + _type.GetHashCode(); - } - - public override bool Equals(object obj) - { - var other = obj as MethodSlotSignature; - if (other == null) - return false; - - if (!Object.Equals(other._type, _type)) - return false; - - if (other._slot != _slot) - return false; - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class MethodSigSignature : Vertex - { - private uint _callingConvention; - private uint _genericArgCount; - private Vertex _returnType; - private Vertex[] _parameters; - - public MethodSigSignature(uint callingConvention, uint genericArgCount, Vertex returnType, Vertex[] parameters) - { - _callingConvention = callingConvention; - _returnType = returnType; - _genericArgCount = genericArgCount; - _parameters = parameters; - } - - internal override void Save(NativeWriter writer) - { - writer.WriteUnsigned(_callingConvention); - - // Signatures omit the generic type parameter count for non-generic methods - if (_genericArgCount > 0) - writer.WriteUnsigned(_genericArgCount); - - writer.WriteUnsigned((uint)_parameters.Length); - - _returnType.Save(writer); - - foreach (var p in _parameters) - p.Save(writer); - } - - public override int GetHashCode() - { - int hash = 317 + 709 * (int)_callingConvention + 953 * (int)_genericArgCount + 31 * _returnType.GetHashCode(); - foreach (var p in _parameters) - hash += (hash << 5) + p.GetHashCode(); - return hash; - } - - public override bool Equals(object obj) - { - MethodSigSignature other = obj as MethodSigSignature; - if (other == null) - return false; - - if (!( - _callingConvention == other._callingConvention && - _genericArgCount == other._genericArgCount && - _parameters.Length == other._parameters.Length && - Object.Equals(_returnType, other._returnType))) - { - return false; - } - - for (int i = 0; i < _parameters.Length; i++) - if (!Object.Equals(_parameters[i], other._parameters[i])) - return false; - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class ModifierTypeSignature : Vertex - { - private TypeModifierKind _modifier; - private Vertex _param; - - public ModifierTypeSignature(TypeModifierKind modifier, Vertex param) - { - _modifier = modifier; - _param = param; - } - - internal override void Save(NativeWriter writer) - { - NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); - - writer.WriteUnsigned((uint)TypeSignatureKind.Modifier | ((uint)_modifier << 4)); - _param.Save(writer); - - compressor.Pack(this); - } - - public override int GetHashCode() - { - return 432981 + 37 * (int)_modifier + _param.GetHashCode(); - } - - public override bool Equals(object obj) - { - ModifierTypeSignature other = obj as ModifierTypeSignature; - if (other == null) - return false; - - return _modifier == other._modifier && Object.Equals(_param, other._param); - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class VariableTypeSignature : Vertex - { - private uint _variableId; - - public VariableTypeSignature(uint index, bool method) - { - _variableId = (index << 1) | (method ? (uint)1 : 0); - } - - internal override void Save(NativeWriter writer) - { - NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); - - writer.WriteUnsigned((uint)TypeSignatureKind.Variable | (_variableId << 4)); - - compressor.Pack(this); - } - - public override int GetHashCode() - { - return 6093 + 7 * (int)_variableId; - } - - public override bool Equals(object obj) - { - VariableTypeSignature other = obj as VariableTypeSignature; - if (other == null) - return false; - - return _variableId == other._variableId; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class InstantiationTypeSignature : Vertex - { - private Vertex _typeDef; - private Vertex[] _args; - - public InstantiationTypeSignature(Vertex typeDef, Vertex[] args) - { - _typeDef = typeDef; - _args = args; - } - - internal override void Save(NativeWriter writer) - { - NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); - - writer.WriteUnsigned((uint)TypeSignatureKind.Instantiation | ((uint)_args.Length << 4)); - _typeDef.Save(writer); - for (int iArg = 0; iArg < _args.Length; iArg++) - _args[iArg].Save(writer); - - compressor.Pack(this); - } - - public override int GetHashCode() - { - int hash = _args.Length; - - hash += (hash << 5) + _typeDef.GetHashCode(); - for (int iArg = 0; iArg < _args.Length; iArg++) - hash += (hash << 5) + _args[iArg].GetHashCode(); - return hash; - } - - public override bool Equals(object obj) - { - InstantiationTypeSignature other = obj as InstantiationTypeSignature; - if (other == null) - return false; - - if (_args.Length != other._args.Length || !Object.Equals(_typeDef, other._typeDef)) - return false; - - for (uint iArg = 0; iArg < _args.Length; iArg++) - if (!Object.Equals(_args[iArg], other._args[iArg])) - return false; - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class MDArrayTypeSignature : Vertex - { - private Vertex _arrayElementType; - private uint _rank; - private uint[] _bounds; - private uint[] _lowerBounds; - - public MDArrayTypeSignature(Vertex arrayElementType, uint rank, uint[] bounds, uint[] lowerBounds) - { - Debug.Assert(bounds != null && lowerBounds != null); - - _arrayElementType = arrayElementType; - _rank = rank; - _bounds = bounds; - _lowerBounds = lowerBounds; - } - - internal override void Save(NativeWriter writer) - { - NativeWriter.TypeSignatureCompressor compressor = new NativeWriter.TypeSignatureCompressor(writer); - - writer.WriteUnsigned((uint)TypeSignatureKind.MultiDimArray | ((uint)_rank << 4)); - _arrayElementType.Save(writer); - - writer.WriteUnsigned((uint)_bounds.Length); - foreach (uint b in _bounds) - writer.WriteUnsigned(b); - - writer.WriteUnsigned((uint)_lowerBounds.Length); - foreach (uint b in _lowerBounds) - writer.WriteUnsigned(b); - - compressor.Pack(this); - } - - public override int GetHashCode() - { - int hash = 79 + 971 * (int)_rank + 83 * _arrayElementType.GetHashCode(); - - foreach (uint b in _bounds) - hash += (hash << 5) + (int)b * 19; - - foreach (uint b in _lowerBounds) - hash += (hash << 5) + (int)b * 19; - - return hash; - } - - public override bool Equals(object obj) - { - MDArrayTypeSignature other = obj as MDArrayTypeSignature; - if (other == null) - return false; - - if (!Object.Equals(_arrayElementType, other._arrayElementType) || - _rank != other._rank || - _bounds.Length != other._bounds.Length || - _lowerBounds.Length != other._lowerBounds.Length) - { - return false; - } - for (int i = 0; i < _bounds.Length; i++) - { - if (_bounds[i] != other._bounds[i]) - return false; - } - for (int i = 0; i < _lowerBounds.Length; i++) - { - if (_lowerBounds[i] != other._lowerBounds[i]) - return false; - } - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class CallingConventionConverterSignature : Vertex - { - private uint _flags; - private Vertex _signature; - - public CallingConventionConverterSignature(uint flags, Vertex signature) - { - _flags = flags; - _signature = signature; - } - - internal override void Save(NativeWriter writer) - { - writer.WriteUnsigned(_flags); - _signature.Save(writer); - } - - public override int GetHashCode() - { - return 509 * 197 + ((int)_flags) * 23 + 647 * _signature.GetHashCode(); - } - - public override bool Equals(object obj) - { - CallingConventionConverterSignature other = obj as CallingConventionConverterSignature; - if (other == null) - return false; - - if (_flags != other._flags) - return false; - - if (!_signature.Equals(other._signature)) - return false; - - return true; - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class BlobVertex : Vertex - { - private byte[] _data; - - public BlobVertex(byte[] data) - { - _data = data; - } - - public int GetSize() - { - return _data.Length; - } - - internal override void Save(NativeWriter writer) - { - foreach (byte b in _data) - { - writer.WriteByte(b); - } - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class EntryPointVertex : Vertex - { - private uint _methodIndex; - - private BlobVertex _fixups; - - public EntryPointVertex(uint methodIndex, BlobVertex fixups) - { - _methodIndex = methodIndex; - _fixups = fixups; - } - - internal override void Save(NativeWriter writer) - { - if (_fixups != null) - { - int existingOffset = _fixups._offset; - if (existingOffset != -1) - { - writer.WriteUnsigned((_methodIndex << 2) | 3); - writer.WriteUnsigned((uint)(writer.GetCurrentOffset() - existingOffset)); - } - else - { - writer.WriteUnsigned((_methodIndex << 2) | 1); - _fixups.Save(writer); - } - } - else - { - writer.WriteUnsigned(_methodIndex << 1); - } - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class EntryPointWithBlobVertex : EntryPointVertex - { - private BlobVertex _blob; - - public EntryPointWithBlobVertex(uint methodIndex, BlobVertex fixups, BlobVertex blob) - : base(methodIndex, fixups) - { - _blob = blob; - } - - internal override void Save(NativeWriter writer) - { - _blob.Save(writer); - base.Save(writer); - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class DebugInfoVertex : Vertex - { - private BlobVertex _debugInfo; - - public DebugInfoVertex(BlobVertex debugInfo) - { - _debugInfo = debugInfo; - } - - internal override void Save(NativeWriter writer) - { - int existingOffset = writer.GetCurrentOffset(_debugInfo); - if (existingOffset != -1) - { - Debug.Assert(writer.GetCurrentOffset() > existingOffset); - writer.WriteUnsigned((uint)(writer.GetCurrentOffset() - existingOffset)); - } - else - { - writer.WriteUnsigned(0); - _debugInfo._iteration = writer.GetNumberOfIterations(); - _debugInfo._offset = writer.GetCurrentOffset(); - _debugInfo.Save(writer); - } - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class VertexArray : Vertex - { - private const int BlockSize = 16; - - private Section _section; - - private List _entries; - - private List _blocks; - - /// - /// Current size of index entry: 0 - uint8, 1 - uint16, 2 - uint32 - /// - private uint _entryIndexSize; - - class VertexLeaf : Vertex - { - private Vertex _vertex; - private int _leafIndex; - - public VertexLeaf(Vertex vertex, int leafIndex) - { - _vertex = vertex; - _leafIndex = leafIndex; - } - - internal override void Save(NativeWriter writer) - { - writer.WriteUnsigned((uint)_leafIndex << 2); - - if (_vertex != null) - { - _vertex.Save(writer); - } - } - } - - class VertexTree : Vertex - { - private Vertex _first; - private Vertex _second; - - public VertexTree() - { - _first = null; - _second = null; - } - - public VertexTree(Vertex first, Vertex second) - { - _first = first; - _second = second; - } - - public void Update(Vertex first, Vertex second) - { - _first = first; - _second = second; - } - - internal override void Save(NativeWriter writer) - { - uint value = (_first != null ? 1u : 0u); - - if (_second != null) - { - value |= 2; - - int delta = writer.GetExpectedOffset(_second) - writer.GetCurrentOffset(); - Debug.Assert(delta >= 0); - value |= ((uint)delta << 2); - } - - writer.WriteUnsigned(value); - - if (_first != null) - _first.Save(writer); - } - } - - public VertexArray(Section section) - { - _section = section; - _entries = new List(); - _blocks = new List(); - _entryIndexSize = 0; - } - - private Vertex ExpandBlock(int index, int depth, bool place, out bool isLeaf) - { - if (depth == 1) - { - Vertex first = (index < _entries.Count ? _entries[index] : null); - Vertex second = (index + 1 < _entries.Count ? _entries[index + 1] : null); - - if (first == null && second == null) - { - isLeaf = true; - return null; - } - - if (first == null || second == null) - { - VertexLeaf leaf = new VertexLeaf( - first == null ? second : first, - (first == null ? index + 1 : index) & (BlockSize - 1)); - - if (place) - { - _section.Place(leaf); - } - - isLeaf = true; - return leaf; - } - - VertexTree tree = new VertexTree(first, second); - if (place) - _section.Place(tree); - - _section.Place(second); - - isLeaf = false; - return tree; - } - else - { - VertexTree tree = new VertexTree(); - if (place) - _section.Place(tree); - - bool firstIsLeaf; - Vertex first = ExpandBlock(index, depth - 1, false, out firstIsLeaf); - - bool secondIsLeaf; - Vertex second = ExpandBlock(index + (1 << (depth - 1)), depth - 1, true, out secondIsLeaf); - - if (first == null && second == null) - { - if (place) - { - Vertex pop = _section.Pop(); - Debug.Assert(pop == tree); - } - isLeaf = true; - return null; - } - - if (first == null && secondIsLeaf) - { - Vertex pop = _section.Pop(); - Debug.Assert(pop == second); - if (place) - { - pop = _section.Pop(); - Debug.Assert(pop == tree); - _section.Place(second); - } - - isLeaf = true; - return second; - } - - if (second == null && firstIsLeaf) - { - if (place) - { - Vertex pop = _section.Pop(); - Debug.Assert(pop == tree); - _section.Place(first); - } - - isLeaf = true; - return first; - } - - tree.Update(first, second); - isLeaf = false; - return tree; - } - } - - public void Set(int index, Vertex element) - { - while (index >= _entries.Count) - _entries.Add(null); - - _entries[index] = element; - } - - public void ExpandLayout() - { - VertexLeaf nullBlock = null; - for (int i = 0; i < _entries.Count; i += BlockSize) - { - bool isLeaf; - Vertex block = ExpandBlock(i, 4, true, out isLeaf); - - if (block == null) - { - if (nullBlock == null) - { - nullBlock = new VertexLeaf(vertex: null, leafIndex: BlockSize); - _section.Place(nullBlock); - } - block = nullBlock; - } - - _blocks.Add(block); - } - - // Start with maximum size entries - _entryIndexSize = 2; - } - - internal override void Save(NativeWriter writer) - { - // Lowest two bits are entry index size, the rest is number of elements - writer.WriteUnsigned(((uint)_entries.Count << 2) | _entryIndexSize); - - int blocksOffset = writer.GetCurrentOffset(); - int maxOffset = 0; - - foreach (Vertex block in _blocks) - { - int offset = writer.GetExpectedOffset(block) - blocksOffset; - Debug.Assert(offset >= 0); - - maxOffset = Math.Max(offset, maxOffset); - - if (_entryIndexSize == 0) - { - writer.WriteByte((byte)offset); - } - else - if (_entryIndexSize == 1) - { - writer.WriteUInt16((ushort)offset); - } - else - { - writer.WriteUInt32((uint)offset); - } - } - - uint newEntryIndexSize = 0; - if (maxOffset > 0xFF) - { - newEntryIndexSize++; - if (maxOffset > 0xFFFF) - newEntryIndexSize++; - } - - if (writer.IsGrowing()) - { - if (newEntryIndexSize > _entryIndexSize) - { - // Ensure that the table will be redone with new entry index size - writer.UpdateOffsetAdjustment(1); - - _entryIndexSize = newEntryIndexSize; - } - } - else - { - if (newEntryIndexSize < _entryIndexSize) - { - // Ensure that the table will be redone with new entry index size - writer.UpdateOffsetAdjustment(-1); - - _entryIndexSize = newEntryIndexSize; - } - } - } - } - -#if NATIVEFORMAT_PUBLICWRITER - public -#else - internal -#endif - class VertexHashtable : Vertex - { - struct Entry - { - public Entry(uint hashcode, Vertex vertex) - { - Offset = 0; - Hashcode = hashcode; - Vertex = vertex; - } - - public int Offset; - - public uint Hashcode; - public Vertex Vertex; - - public static int Comparison(Entry a, Entry b) - { - return (int)(a.Hashcode /*& mask*/) - (int)(b.Hashcode /*& mask*/); - } - } - - private List _Entries; - - // How many entries to target per bucket. Higher fill factor means smaller size, but worse runtime perf. - private int _nFillFactor; - - // Number of buckets choosen for the table. Must be power of two. 0 means that the table is still open for mutation. - private uint _nBuckets; - - // Current size of index entry - private int _entryIndexSize; // 0 - uint8, 1 - uint16, 2 - uint32 - - public const int DefaultFillFactor = 13; - - public VertexHashtable(int fillFactor = DefaultFillFactor) - { - _Entries = new List(); - _nFillFactor = fillFactor; - _nBuckets = 0; - _entryIndexSize = 0; - } - - public void Append(uint hashcode, Vertex element) - { - // The table needs to be open for mutation - Debug.Assert(_nBuckets == 0); - - _Entries.Add(new Entry(hashcode, element)); - } - - // Returns 1 + log2(x) rounded up, 0 iff x == 0 - static int HighestBit(uint x) - { - int ret = 0; - while (x != 0) - { - x >>= 1; - ret++; - } - return ret; - } - - // Helper method to back patch entry index in the bucket table - static void PatchEntryIndex(NativeWriter writer, int patchOffset, int entryIndexSize, int entryIndex) - { - if (entryIndexSize == 0) - { - writer.PatchByteAt(patchOffset, (byte)entryIndex); - } - else if (entryIndexSize == 1) - { - writer.PatchByteAt(patchOffset, (byte)entryIndex); - writer.PatchByteAt(patchOffset + 1, (byte)(entryIndex >> 8)); - } - else - { - writer.PatchByteAt(patchOffset, (byte)entryIndex); - writer.PatchByteAt(patchOffset + 1, (byte)(entryIndex >> 8)); - writer.PatchByteAt(patchOffset + 2, (byte)(entryIndex >> 16)); - writer.PatchByteAt(patchOffset + 3, (byte)(entryIndex >> 24)); - } - } - - void ComputeLayout() - { - uint bucketsEstimate = (uint)(_Entries.Count / _nFillFactor); - - // Round number of buckets up to the power of two - _nBuckets = (uint)(1 << HighestBit(bucketsEstimate)); - - // Lowest byte of the hashcode is used for lookup within the bucket. Keep it sorted too so that - // we can use the ordering to terminate the lookup prematurely. - uint mask = ((_nBuckets - 1) << 8) | 0xFF; - - // sort it by hashcode - _Entries.Sort( - (a, b) => - { - return (int)(a.Hashcode & mask) - (int)(b.Hashcode & mask); - } - ); - - // Start with maximum size entries - _entryIndexSize = 2; - } - - internal override void Save(NativeWriter writer) - { - // Compute the layout of the table if we have not done it yet - if (_nBuckets == 0) - ComputeLayout(); - - int nEntries = _Entries.Count; - int startOffset = writer.GetCurrentOffset(); - uint bucketMask = (_nBuckets - 1); - - // Lowest two bits are entry index size, the rest is log2 number of buckets - int numberOfBucketsShift = HighestBit(_nBuckets) - 1; - writer.WriteByte((byte)((numberOfBucketsShift << 2) | _entryIndexSize)); - - int bucketsOffset = writer.GetCurrentOffset(); - - writer.WritePad((int)((_nBuckets + 1) << _entryIndexSize)); - - // For faster lookup at runtime, we store the first entry index even though it is redundant (the - // value can be inferred from number of buckets) - PatchEntryIndex(writer, bucketsOffset, _entryIndexSize, writer.GetCurrentOffset() - bucketsOffset); - - int iEntry = 0; - - for (int iBucket = 0; iBucket < _nBuckets; iBucket++) - { - while (iEntry < nEntries) - { - if (((_Entries[iEntry].Hashcode >> 8) & bucketMask) != iBucket) - break; - - Entry curEntry = _Entries[iEntry]; - - int currentOffset = writer.GetCurrentOffset(); - writer.UpdateOffsetAdjustment(currentOffset - curEntry.Offset); - curEntry.Offset = currentOffset; - _Entries[iEntry] = curEntry; - - writer.WriteByte((byte)curEntry.Hashcode); - writer.WriteRelativeOffset(curEntry.Vertex); - - iEntry++; - } - - int patchOffset = bucketsOffset + ((iBucket + 1) << _entryIndexSize); - - PatchEntryIndex(writer, patchOffset, _entryIndexSize, writer.GetCurrentOffset() - bucketsOffset); - } - Debug.Assert(iEntry == nEntries); - - int maxIndexEntry = (writer.GetCurrentOffset() - bucketsOffset); - int newEntryIndexSize = 0; - if (maxIndexEntry > 0xFF) - { - newEntryIndexSize++; - if (maxIndexEntry > 0xFFFF) - newEntryIndexSize++; - } - - if (writer.IsGrowing()) - { - if (newEntryIndexSize > _entryIndexSize) - { - // Ensure that the table will be redone with new entry index size - writer.UpdateOffsetAdjustment(1); - - _entryIndexSize = newEntryIndexSize; - } - } - else - { - if (newEntryIndexSize < _entryIndexSize) - { - // Ensure that the table will be redone with new entry index size - writer.UpdateOffsetAdjustment(-1); - - _entryIndexSize = newEntryIndexSize; - } - } - } - - public override bool Equals(object obj) - { - throw new NotImplementedException(); - } - - public override int GetHashCode() - { - throw new NotImplementedException(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/src/tools/crossgen2/Common/Internal/Runtime/ModuleHeaders.cs deleted file mode 100644 index 5c374310df9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Internal/Runtime/ModuleHeaders.cs +++ /dev/null @@ -1,102 +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; - -namespace Internal.Runtime -{ - // - // Please keep the data structures in this file in sync with the native version at - // src/Native/Runtime/inc/ModuleHeaders.h - // - - internal struct ReadyToRunHeaderConstants - { - public const uint Signature = 0x00525452; // 'RTR' - - public const ushort CurrentMajorVersion = 4; - public const ushort CurrentMinorVersion = 0; - } - -#pragma warning disable 0169 - internal struct ReadyToRunHeader - { - private uint Signature; // ReadyToRunHeaderConstants.Signature - private ushort MajorVersion; - private ushort MinorVersion; - - private uint Flags; - - private ushort NumberOfSections; - private byte EntrySize; - private byte EntryType; - - // Array of sections follows. - }; -#pragma warning restore 0169 - - enum ReadyToRunFlag - { - READYTORUN_FLAG_PLATFORM_NEUTRAL_SOURCE = 0x00000001, // Set if the original IL assembly was platform-neutral - READYTORUN_FLAG_SKIP_TYPE_VALIDATION = 0x00000002, // Set of methods with native code was determined using profile data - READYTORUN_FLAG_PARTIAL = 0x00000004, - READYTORUN_FLAG_NONSHARED_PINVOKE_STUBS = 0x00000008 // PInvoke stubs compiled into image are non-shareable (no secret parameter) - }; - - // - // ReadyToRunSectionType IDs are used by the runtime to look up specific global data sections - // from each module linked into the final binary. New sections should be added at the bottom - // of the enum and deprecated sections should not be removed to preserve ID stability. - // - // This list should be kept in sync with the runtime version at - // https://github.com/dotnet/coreclr/blob/master/src/inc/readytorun.h - // - public enum ReadyToRunSectionType - { - // - // CoreCLR ReadyToRun sections - // - CompilerIdentifier = 100, - ImportSections = 101, - RuntimeFunctions = 102, - MethodDefEntryPoints = 103, - ExceptionInfo = 104, - DebugInfo = 105, - DelayLoadMethodCallThunks = 106, - // 107 is deprecated - it was used by an older format of AvailableTypes - AvailableTypes = 108, - InstanceMethodEntryPoints = 109, - InliningInfo = 110, // Added in v2.1 - ProfileDataInfo = 111, // Added in v2.2 - ManifestMetadata = 112, // Added in v2.3 - AttributePresence = 113, // Added in V3.1 - - // - // CoreRT ReadyToRun sections - // - StringTable = 200, // Unused - GCStaticRegion = 201, - ThreadStaticRegion = 202, - InterfaceDispatchTable = 203, - TypeManagerIndirection = 204, - EagerCctor = 205, - FrozenObjectRegion = 206, - GCStaticDesc = 207, - ThreadStaticOffsetRegion = 208, - ThreadStaticGCDescRegion = 209, - ThreadStaticIndex = 210, - LoopHijackFlag = 211, - ImportAddressTables = 212, - - // Sections 300 - 399 are reserved for RhFindBlob backwards compatibility - ReadonlyBlobRegionStart = 300, - ReadonlyBlobRegionEnd = 399, - } - - [Flags] - internal enum ModuleInfoFlags : int - { - HasEndPointer = 0x1, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Internal/Text/Utf8String.cs b/src/coreclr/src/tools/crossgen2/Common/Internal/Text/Utf8String.cs deleted file mode 100644 index 47e70135076..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Internal/Text/Utf8String.cs +++ /dev/null @@ -1,151 +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 System.Runtime.CompilerServices; -using System.Text; - -namespace Internal.Text -{ - public struct Utf8String : IEquatable, IComparable - { - private byte[] _value; - - public Utf8String(byte[] underlyingArray) - { - _value = underlyingArray; - } - - public Utf8String(string s) - { - _value = Encoding.UTF8.GetBytes(s); - } - - // TODO: This should return ReadOnlySpan instead once available - public byte[] UnderlyingArray => _value; - public int Length => _value.Length; - - // For now, define implicit conversions between string and Utf8String to aid the transition - // These conversions will be removed eventually - public static implicit operator Utf8String(string s) - { - return new Utf8String(s); - } - - public override string ToString() - { - return Encoding.UTF8.GetString(_value); - } - - public override bool Equals(object obj) - { - return (obj is Utf8String) && Equals((Utf8String)obj); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int _rotl(int value, int shift) - { - // This is expected to be optimized into a single rotl instruction - return (int)(((uint)value << shift) | ((uint)value >> (32 - shift))); - } - - public unsafe override int GetHashCode() - { - int length = _value.Length; - int hash = length; - fixed (byte* ap = _value) - { - byte* a = ap; - - while (length >= 4) - { - hash = (hash + _rotl(hash, 5)) ^ *(int*)a; - a += 4; length -= 4; - } - if (length >= 2) - { - hash = (hash + _rotl(hash, 5)) ^ *(short*)a; - a += 2; length -= 2; - } - if (length > 0) - { - hash = (hash + _rotl(hash, 5)) ^ *a; - } - hash += _rotl(hash, 7); - hash += _rotl(hash, 15); - return hash; - } - } - - public bool Equals(Utf8String other) - { - int length = _value.Length; - if (length != other.Length) - return false; - - if (_value == other._value) - return true; - - unsafe - { - fixed (byte* ap = _value) fixed (byte* bp = other._value) - { - byte* a = ap; - byte* b = bp; - - while (length >= 4) - { - if (*(int*)a != *(int*)b) return false; - a += 4; b += 4; length -= 4; - } - if (length >= 2) - { - if (*(short*)a != *(short*)b) return false; - a += 2; b += 2; length -= 2; - } - if (length > 0) - { - if (*a != *b) return false; - } - return true; - } - } - } - - private static int Compare(Utf8String strA, Utf8String strB) - { - int length = Math.Min(strA.Length, strB.Length); - - unsafe - { - fixed (byte* ap = strA._value) - fixed (byte* bp = strB._value) - { - byte* a = ap; - byte* b = bp; - - while (length > 0) - { - if (*a != *b) - return *a - *b; - a += 1; - b += 1; - length -= 1; - } - - // At this point, we have compared all the characters in at least one string. - // The longer string will be larger. - // We could optimize and compare lengths before iterating strings, but we want - // Foo and Foo1 to be sorted adjacent to eachother. - return strA.Length - strB.Length; - } - } - } - - public int CompareTo(Utf8String other) - { - return Compare(this, other); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/Internal/Text/Utf8StringBuilder.cs b/src/coreclr/src/tools/crossgen2/Common/Internal/Text/Utf8StringBuilder.cs deleted file mode 100644 index 0cdd95abcd4..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/Internal/Text/Utf8StringBuilder.cs +++ /dev/null @@ -1,152 +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 System.Text; -using System.Diagnostics; - -namespace Internal.Text -{ - public class Utf8StringBuilder - { - private byte[] _buffer = Array.Empty(); - private int _length = 0; - - public Utf8StringBuilder() - { - } - - // TODO: This should return ReadOnlySpan instead once available - public byte[] UnderlyingArray => _buffer; - public int Length => _length; - - public Utf8StringBuilder Clear() - { - _length = 0; - return this; - } - - public Utf8StringBuilder Truncate(int newLength) - { - Debug.Assert(newLength <= _length); - _length = newLength; - return this; - } - - public Utf8StringBuilder Append(Utf8String value) - { - return Append(value.UnderlyingArray); - } - - public Utf8StringBuilder Append(byte[] value) - { - Ensure(value.Length); - Buffer.BlockCopy(value, 0, _buffer, _length, value.Length); - _length += value.Length; - return this; - } - - public Utf8StringBuilder Append(char value) - { - Ensure(1); - if (value > 0x7F) - return Append(Encoding.UTF8.GetBytes(new char[] { value })); - _buffer[_length++] = (byte)value; - return this; - } - - public Utf8StringBuilder Append(string value) - { - Ensure(value.Length); - - byte[] buffer = _buffer; - for (int i = 0; i < value.Length; i++) - { - char c = value[i]; - if (c > 0x7F) - return Append(Encoding.UTF8.GetBytes(value)); - buffer[_length+i] = (byte)c; - } - _length += value.Length; - - return this; - } - - public override string ToString() - { - return Encoding.UTF8.GetString(_buffer, 0, _length); - } - - public string ToString(int start) - { - return Encoding.UTF8.GetString(_buffer, start, _length - start); - } - - public Utf8String ToUtf8String() - { - var ret = new byte[_length]; - Buffer.BlockCopy(_buffer, 0, ret, 0, _length); - return new Utf8String(ret); - } - - private void Ensure(int extraSpace) - { - if ((uint)(_length + extraSpace) > (uint)_buffer.Length) - Grow(extraSpace); - } - - private void Grow(int extraSpace) - { - int newSize = Math.Max(2 * _buffer.Length, _length + extraSpace); - byte[] newBuffer = new byte[newSize]; - Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _length); - _buffer = newBuffer; - } - - // Find the boundary of the last character prior to a position - // If pos points to the last byte of a char, then return pos; Otherwise, - // return the position of the last byte of the preceding char. - public int LastCharBoundary(int pos) - { - Debug.Assert(pos < _length); - - if (_buffer[pos] < 128 /*10000000*/) - { - // This is a single byte character - return pos; - } - - int origPos = pos; - - // Skip following bytes of a multi-byte character until the first byte is seen - while (_buffer[pos] < 192 /*11000000*/) - { - pos--; - } - - if (pos == origPos - 3) - { - // We just skipped a four-byte character - Debug.Assert(_buffer[pos] >= 240 /*11110000*/); - return origPos; - } - - if (pos == origPos - 2 && _buffer[pos] < 240 && _buffer[pos] >= 224 /*11100000*/) - { - // We just skipped a three-byte character - return origPos; - } - - if (pos == origPos - 1 && _buffer[pos] < 224) - { - // We just skipped a two-byte character - Debug.Assert(_buffer[pos] >= 192 /*11000000*/); - return origPos; - } - - // We were in the middle of a multi-byte character - return pos - 1; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoBase.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoBase.cs deleted file mode 100644 index 1aa42f323d6..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoBase.cs +++ /dev/null @@ -1,3382 +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. - -// DO NOT EDIT THIS FILE! It IS AUTOGENERATED -using System; -using System.Runtime.InteropServices; - -namespace Internal.JitInterface -{ - unsafe partial class CorInfoImpl - { - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getMethodAttribs(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __setMethodAttribs(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getMethodSig(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __getMethodInfo(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoInline __canInline(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint pRestrictions); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __reportInliningDecision(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __canTailCall(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, [MarshalAs(UnmanagedType.I1)]bool fIsTailPrefix); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __reportTailCallDecision(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, [MarshalAs(UnmanagedType.I1)]bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getEHinfo(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getMethodClass(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_MODULE_STRUCT_* __getMethodModule(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getMethodVTableOffset(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, [MarshalAs(UnmanagedType.U1)] ref bool isRelative); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_METHOD_STRUCT_* __resolveVirtualMethod(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* virtualMethod, CORINFO_CLASS_STRUCT_* implementingClass, CORINFO_CONTEXT_STRUCT* ownerType); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_METHOD_STRUCT_* __getUnboxedEntry(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte* requiresInstMethodTableArg); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getDefaultEqualityComparerClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* elemType); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __expandRawHandleIntrinsic(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoIntrinsics __getIntrinsicID(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, byte* pMustExpand); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __isIntrinsicType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* classHnd); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoUnmanagedCallConv __getUnmanagedCallConv(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __pInvokeMarshalingRequired(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __satisfiesMethodConstraints(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [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(default(CallingConvention))] - delegate CorInfoInstantiationVerification __isInstantiationOfVerifiedGeneric(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __initConstraintsForVerification(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularClassConstraints, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularMethodConstraint); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoCanSkipVerificationResult __canSkipMethodVerification(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHandle); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __methodMustBeLoadedBeforeCodeIsRun(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_METHOD_STRUCT_* __mapMethodDeclToMethodImpl(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getGSCookie(IntPtr _this, IntPtr* ppException, IntPtr* pCookieVal, IntPtr** ppCookieVal); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __resolveToken(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __tryResolveToken(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __findSig(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __findCallSiteSig(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getTokenTypeAsHandle(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoCanSkipVerificationResult __canSkipVerification(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isValidToken(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint metaTOK); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isValidStringRef(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint metaTOK); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __shouldEnforceCallvirtRestriction(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* scope); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoType __asCorInfoType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __getClassName(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __getClassNameFromMetadata(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte** namespaceName); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getTypeInstantiationArgument(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, uint index); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate int __appendClassName(IntPtr _this, IntPtr* ppException, short** ppBuf, ref int pnBufLen, CORINFO_CLASS_STRUCT_* cls, [MarshalAs(UnmanagedType.Bool)]bool fNamespace, [MarshalAs(UnmanagedType.Bool)]bool fFullInst, [MarshalAs(UnmanagedType.Bool)]bool fAssembly); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isValueClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoInlineTypeCheck __canInlineTypeCheck(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CorInfoInlineTypeCheckSource source); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __canInlineTypeCheckWithObjectVTable(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getClassAttribs(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isStructRequiringStackAllocRetBuf(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_MODULE_STRUCT_* __getClassModule(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_ASSEMBLY_STRUCT_* __getModuleAssembly(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* mod); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __getAssemblyName(IntPtr _this, IntPtr* ppException, CORINFO_ASSEMBLY_STRUCT_* assem); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __LongLifetimeMalloc(IntPtr _this, IntPtr* ppException, UIntPtr sz); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __LongLifetimeFree(IntPtr _this, IntPtr* ppException, void* obj); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __getClassModuleIdForStatics(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getClassSize(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getHeapClassSize(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __canAllocateOnStack(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getClassAlignmentRequirement(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, [MarshalAs(UnmanagedType.Bool)]bool fDoubleAlignHint); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getClassGClayout(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getClassNumInstanceFields(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_FIELD_STRUCT_* __getFieldInClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, int num); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __checkMethodModifier(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, [MarshalAs(UnmanagedType.Bool)]bool fOptional); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoHelpFunc __getNewHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, byte* pHasSideEffects); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoHelpFunc __getNewArrHelper(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* arrayCls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoHelpFunc __getCastingHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool fThrowing); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoHelpFunc __getSharedCCtorHelper(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoHelpFunc __getSecurityPrologHelper(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getTypeForBox(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoHelpFunc __getBoxHelper(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoHelpFunc __getUnBoxHelper(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __getReadyToRunHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getReadyToRunDelegateCtorHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pTargetMethod, CORINFO_CLASS_STRUCT_* delegateType, ref CORINFO_LOOKUP pLookup); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __getHelperName(IntPtr _this, IntPtr* ppException, CorInfoHelpFunc helpFunc); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoInitClassResult __initClass(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context, [MarshalAs(UnmanagedType.Bool)]bool speculative); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __classMustBeLoadedBeforeCodeIsRun(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getBuiltinClass(IntPtr _this, IntPtr* ppException, CorInfoClassId classId); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoType __getTypeForPrimitiveValueClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoType __getTypeForPrimitiveNumericClass(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __canCast(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __areTypesEquivalent(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate TypeCompareState __compareTypesForCast(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate TypeCompareState __compareTypesForEquality(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __mergeClasses(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isMoreSpecificType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getParentType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoType __getChildType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __satisfiesClassConstraints(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isSDArray(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getArrayRank(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getArrayInitializationData(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, uint size); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoIsAccessAllowedResult __canAccessClass(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __getFieldName(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* ftn, byte** moduleName); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getFieldClass(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoType __getFieldType(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getFieldOffset(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __isWriteBarrierHelperRequired(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getFieldInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __isFieldStatic(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getBoundaries(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implictBoundaries); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __setBoundaries(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getVars(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, [MarshalAs(UnmanagedType.U1)] ref bool extendOthers); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __setVars(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __allocateArray(IntPtr _this, IntPtr* ppException, uint cBytes); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __freeArray(IntPtr _this, IntPtr* ppException, void* array); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_ARG_LIST_STRUCT_* __getArgNext(IntPtr _this, IntPtr* ppException, CORINFO_ARG_LIST_STRUCT_* args); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoTypeWithMod __getArgType(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getArgClass(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoType __getHFAType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* hClass); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate HRESULT __GetErrorHRESULT(IntPtr _this, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __GetErrorMessage(IntPtr _this, IntPtr* ppException, short* buffer, uint bufferLength); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate int __FilterException(IntPtr _this, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __HandleException(IntPtr _this, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __ThrowExceptionForJitResult(IntPtr _this, IntPtr* ppException, HRESULT result); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __ThrowExceptionForHelper(IntPtr _this, IntPtr* ppException, ref CORINFO_HELPER_DESC throwHelper); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __runWithErrorTrap(IntPtr _this, IntPtr* ppException, void* function, void* parameter); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getEEInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_EE_INFO pEEInfoOut); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.LPWStr)]delegate string __getJitTimeLogFilename(IntPtr _this, IntPtr* ppException); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate mdToken __getMethodDefFromMethod(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hMethod); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __getMethodName(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte** moduleName); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __getMethodNameFromMetadata(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassName); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getMethodHash(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate byte* __findNameOfToken(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* moduleHandle, mdToken token, byte* szFQName, UIntPtr FQNameCapacity); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __getSystemVAmd64PassStructInRegisterDescriptor(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getThreadTLSIndex(IntPtr _this, IntPtr* ppException, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getInlinedCallFrameVptr(IntPtr _this, IntPtr* ppException, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate int* __getAddrOfCaptureThreadGlobal(IntPtr _this, IntPtr* ppException, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getHelperFtn(IntPtr _this, IntPtr* ppException, CorInfoHelpFunc ftnNum, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getFunctionEntryPoint(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getFunctionFixedEntryPoint(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getMethodSync(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CorInfoHelpFunc __getLazyStringLiteralHelper(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* handle); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_MODULE_STRUCT_* __embedModuleHandle(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __embedClassHandle(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_METHOD_STRUCT_* __embedMethodHandle(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_FIELD_STRUCT_* __embedFieldHandle(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __embedGenericHandle(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.Bool)]bool fEmbedParent, ref CORINFO_GENERICHANDLE_RESULT pResult); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getLocationOfThisType(IntPtr _this, IntPtr* ppException, out CORINFO_LOOKUP_KIND _return, CORINFO_METHOD_STRUCT_* context); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getPInvokeUnmanagedTarget(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getAddressOfPInvokeFixup(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getAddressOfPInvokeTarget(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __GetCookieForPInvokeCalliSig(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __canGetCookieForPInvokeCalliSig(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_JUST_MY_CODE_HANDLE_* __getJustMyCodeHandle(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __GetProfilingHandle(IntPtr _this, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)] ref bool pbHookFunction, ref void* pProfilerHandle, [MarshalAs(UnmanagedType.Bool)] ref bool pbIndirectedHandles); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getCallInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __canAccessFamily(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hCaller, CORINFO_CLASS_STRUCT_* hInstanceType); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isRIDClassDomainID(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getClassDomainID(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getFieldAddress(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, void** ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_CLASS_STRUCT_* __getStaticFieldCurrentClass(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate IntPtr __getVarArgsHandle(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* pSig, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __canGetVarArgsHandle(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* pSig); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate InfoAccessType __constructStringLiteral(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate InfoAccessType __emptyStringLiteral(IntPtr _this, IntPtr* ppException, ref void* ppValue); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getFieldThreadLocalStoreID(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __setOverride(IntPtr _this, IntPtr* ppException, IntPtr pOverride, CORINFO_METHOD_STRUCT_* currentMethod); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __addActiveDependency(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* moduleFrom, CORINFO_MODULE_STRUCT_* moduleTo); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate CORINFO_METHOD_STRUCT_* __GetDelegateCtor(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __MethodCompileComplete(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getTailCallCopyArgsThunk(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.I1)]delegate bool __convertPInvokeCalliToCall(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool mustConvert); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getMemoryManager(IntPtr _this, IntPtr* ppException); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __allocMem(IntPtr _this, IntPtr* ppException, uint hotCodeSize, uint coldCodeSize, uint roDataSize, uint xcptnsCount, CorJitAllocMemFlag flag, ref void* hotCodeBlock, ref void* coldCodeBlock, ref void* roDataBlock); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __reserveUnwindInfo(IntPtr _this, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)]bool isFunclet, [MarshalAs(UnmanagedType.Bool)]bool isColdCode, uint unwindSize); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __allocUnwindInfo(IntPtr _this, IntPtr* ppException, byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __allocGCInfo(IntPtr _this, IntPtr* ppException, UIntPtr size); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __yieldExecution(IntPtr _this, IntPtr* ppException); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __setEHcount(IntPtr _this, IntPtr* ppException, uint cEH); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __setEHinfo(IntPtr _this, IntPtr* ppException, uint EHnumber, ref CORINFO_EH_CLAUSE clause); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __logMsg(IntPtr _this, IntPtr* ppException, uint level, byte* fmt, IntPtr args); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate int __doAssert(IntPtr _this, IntPtr* ppException, byte* szFile, int iLine, byte* szExpr); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __reportFatalError(IntPtr _this, IntPtr* ppException, CorJitResult result); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate HRESULT __allocMethodBlockCounts(IntPtr _this, IntPtr* ppException, uint count, ref BlockCounts* pBlockCounts); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate HRESULT __getMethodBlockCounts(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHnd, ref uint pCount, ref BlockCounts* pBlockCounts, ref uint pNumRuns); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __recordCallSite(IntPtr _this, IntPtr* ppException, uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __recordRelocation(IntPtr _this, IntPtr* ppException, void* location, void* target, ushort fRelocType, ushort slotNum, int addlDelta); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate ushort __getRelocTypeHint(IntPtr _this, IntPtr* ppException, void* target); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void __getModuleNativeEntryPointRange(IntPtr _this, IntPtr* ppException, ref void* pStart, ref void* pEnd); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getExpectedTargetArchitecture(IntPtr _this, IntPtr* ppException); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate uint __getJitFlags(IntPtr _this, IntPtr* ppException, ref CORJIT_FLAGS flags, uint sizeInBytes); - - static uint _getMethodAttribs(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodAttribs(ftn); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static void _setMethodAttribs(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) - { - var _this = GetThis(thisHandle); - try - { - _this.setMethodAttribs(ftn, attribs); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _getMethodSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) - { - var _this = GetThis(thisHandle); - try - { - _this.getMethodSig(ftn, sig, memberParent); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _getMethodInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodInfo(ftn, info); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static CorInfoInline _canInline(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint pRestrictions) - { - var _this = GetThis(thisHandle); - try - { - return _this.canInline(callerHnd, calleeHnd, ref pRestrictions); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoInline); - } - } - - static void _reportInliningDecision(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) - { - var _this = GetThis(thisHandle); - try - { - _this.reportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _canTailCall(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, [MarshalAs(UnmanagedType.I1)]bool fIsTailPrefix) - { - var _this = GetThis(thisHandle); - try - { - return _this.canTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static void _reportTailCallDecision(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, [MarshalAs(UnmanagedType.I1)]bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason) - { - var _this = GetThis(thisHandle); - try - { - _this.reportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _getEHinfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) - { - var _this = GetThis(thisHandle); - try - { - _this.getEHinfo(ftn, EHnumber, ref clause); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static CORINFO_CLASS_STRUCT_* _getMethodClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodClass(method); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static CORINFO_MODULE_STRUCT_* _getMethodModule(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodModule(method); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_MODULE_STRUCT_*); - } - } - - static void _getMethodVTableOffset(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, [MarshalAs(UnmanagedType.U1)] ref bool isRelative) - { - var _this = GetThis(thisHandle); - try - { - _this.getMethodVTableOffset(method, ref offsetOfIndirection, ref offsetAfterIndirection, ref isRelative); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static CORINFO_METHOD_STRUCT_* _resolveVirtualMethod(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* virtualMethod, CORINFO_CLASS_STRUCT_* implementingClass, CORINFO_CONTEXT_STRUCT* ownerType) - { - var _this = GetThis(thisHandle); - try - { - return _this.resolveVirtualMethod(virtualMethod, implementingClass, ownerType); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_METHOD_STRUCT_*); - } - } - - static CORINFO_METHOD_STRUCT_* _getUnboxedEntry(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte* requiresInstMethodTableArg) - { - var _this = GetThis(thisHandle); - try - { - return _this.getUnboxedEntry(ftn, requiresInstMethodTableArg); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_METHOD_STRUCT_*); - } - } - - static CORINFO_CLASS_STRUCT_* _getDefaultEqualityComparerClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* elemType) - { - var _this = GetThis(thisHandle); - try - { - return _this.getDefaultEqualityComparerClass(elemType); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - 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, byte* pMustExpand) - { - var _this = GetThis(thisHandle); - try - { - return _this.getIntrinsicID(method, pMustExpand); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoIntrinsics); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _isIntrinsicType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* classHnd) - { - var _this = GetThis(thisHandle); - try - { - return _this.isIntrinsicType(classHnd); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static CorInfoUnmanagedCallConv _getUnmanagedCallConv(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) - { - var _this = GetThis(thisHandle); - try - { - return _this.getUnmanagedCallConv(method); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoUnmanagedCallConv); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _pInvokeMarshalingRequired(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) - { - var _this = GetThis(thisHandle); - try - { - return _this.pInvokeMarshalingRequired(method, callSiteSig); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _satisfiesMethodConstraints(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) - { - var _this = GetThis(thisHandle); - try - { - return _this.satisfiesMethodConstraints(parent, method); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _isCompatibleDelegate(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* objCls, CORINFO_CLASS_STRUCT_* methodParentCls, CORINFO_METHOD_STRUCT_* method, CORINFO_CLASS_STRUCT_* delegateCls, [MarshalAs(UnmanagedType.Bool)] ref bool pfIsOpenDelegate) - { - var _this = GetThis(thisHandle); - try - { - return _this.isCompatibleDelegate(objCls, methodParentCls, method, delegateCls, ref pfIsOpenDelegate); - } - 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); - try - { - return _this.isInstantiationOfVerifiedGeneric(method); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoInstantiationVerification); - } - } - - static void _initConstraintsForVerification(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularClassConstraints, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularMethodConstraint) - { - var _this = GetThis(thisHandle); - try - { - _this.initConstraintsForVerification(method, ref pfHasCircularClassConstraints, ref pfHasCircularMethodConstraint); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static CorInfoCanSkipVerificationResult _canSkipMethodVerification(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHandle) - { - var _this = GetThis(thisHandle); - try - { - return _this.canSkipMethodVerification(ftnHandle); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoCanSkipVerificationResult); - } - } - - static void _methodMustBeLoadedBeforeCodeIsRun(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) - { - var _this = GetThis(thisHandle); - try - { - _this.methodMustBeLoadedBeforeCodeIsRun(method); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static CORINFO_METHOD_STRUCT_* _mapMethodDeclToMethodImpl(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) - { - var _this = GetThis(thisHandle); - try - { - return _this.mapMethodDeclToMethodImpl(method); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_METHOD_STRUCT_*); - } - } - - static void _getGSCookie(IntPtr thisHandle, IntPtr* ppException, IntPtr* pCookieVal, IntPtr** ppCookieVal) - { - var _this = GetThis(thisHandle); - try - { - _this.getGSCookie(pCookieVal, ppCookieVal); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _resolveToken(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken) - { - var _this = GetThis(thisHandle); - try - { - _this.resolveToken(ref pResolvedToken); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _tryResolveToken(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken) - { - var _this = GetThis(thisHandle); - try - { - _this.tryResolveToken(ref pResolvedToken); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _findSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) - { - var _this = GetThis(thisHandle); - try - { - _this.findSig(module, sigTOK, context, sig); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _findCallSiteSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) - { - var _this = GetThis(thisHandle); - try - { - _this.findCallSiteSig(module, methTOK, context, sig); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static CORINFO_CLASS_STRUCT_* _getTokenTypeAsHandle(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken) - { - var _this = GetThis(thisHandle); - try - { - return _this.getTokenTypeAsHandle(ref pResolvedToken); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static CorInfoCanSkipVerificationResult _canSkipVerification(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module) - { - var _this = GetThis(thisHandle); - try - { - return _this.canSkipVerification(module); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoCanSkipVerificationResult); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _isValidToken(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint metaTOK) - { - var _this = GetThis(thisHandle); - try - { - return _this.isValidToken(module, metaTOK); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _isValidStringRef(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, uint metaTOK) - { - var _this = GetThis(thisHandle); - try - { - return _this.isValidStringRef(module, metaTOK); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _shouldEnforceCallvirtRestriction(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* scope) - { - var _this = GetThis(thisHandle); - try - { - return _this.shouldEnforceCallvirtRestriction(scope); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static CorInfoType _asCorInfoType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.asCorInfoType(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoType); - } - } - - static byte* _getClassName(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassName(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - static byte* _getClassNameFromMetadata(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassNameFromMetadata(cls, namespaceName); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - static CORINFO_CLASS_STRUCT_* _getTypeInstantiationArgument(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, uint index) - { - var _this = GetThis(thisHandle); - try - { - return _this.getTypeInstantiationArgument(cls, index); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static int _appendClassName(IntPtr thisHandle, IntPtr* ppException, short** ppBuf, ref int pnBufLen, CORINFO_CLASS_STRUCT_* cls, [MarshalAs(UnmanagedType.Bool)]bool fNamespace, [MarshalAs(UnmanagedType.Bool)]bool fFullInst, [MarshalAs(UnmanagedType.Bool)]bool fAssembly) - { - var _this = GetThis(thisHandle); - try - { - return _this.appendClassName(ppBuf, ref pnBufLen, cls, fNamespace, fFullInst, fAssembly); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(int); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _isValueClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.isValueClass(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static CorInfoInlineTypeCheck _canInlineTypeCheck(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CorInfoInlineTypeCheckSource source) - { - var _this = GetThis(thisHandle); - try - { - return _this.canInlineTypeCheck(cls, source); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoInlineTypeCheck); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _canInlineTypeCheckWithObjectVTable(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.canInlineTypeCheckWithObjectVTable(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static uint _getClassAttribs(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassAttribs(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _isStructRequiringStackAllocRetBuf(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.isStructRequiringStackAllocRetBuf(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static CORINFO_MODULE_STRUCT_* _getClassModule(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassModule(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_MODULE_STRUCT_*); - } - } - - static CORINFO_ASSEMBLY_STRUCT_* _getModuleAssembly(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* mod) - { - var _this = GetThis(thisHandle); - try - { - return _this.getModuleAssembly(mod); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_ASSEMBLY_STRUCT_*); - } - } - - static byte* _getAssemblyName(IntPtr thisHandle, IntPtr* ppException, CORINFO_ASSEMBLY_STRUCT_* assem) - { - var _this = GetThis(thisHandle); - try - { - return _this.getAssemblyName(assem); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - static void* _LongLifetimeMalloc(IntPtr thisHandle, IntPtr* ppException, UIntPtr sz) - { - var _this = GetThis(thisHandle); - try - { - return _this.LongLifetimeMalloc(sz); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static void _LongLifetimeFree(IntPtr thisHandle, IntPtr* ppException, void* obj) - { - var _this = GetThis(thisHandle); - try - { - _this.LongLifetimeFree(obj); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static byte* _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassModuleIdForStatics(cls, pModule, ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - static uint _getClassSize(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassSize(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static uint _getHeapClassSize(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getHeapClassSize(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _canAllocateOnStack(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.canAllocateOnStack(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static uint _getClassAlignmentRequirement(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, [MarshalAs(UnmanagedType.Bool)]bool fDoubleAlignHint) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassAlignmentRequirement(cls, fDoubleAlignHint); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static uint _getClassGClayout(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassGClayout(cls, gcPtrs); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static uint _getClassNumInstanceFields(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassNumInstanceFields(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static CORINFO_FIELD_STRUCT_* _getFieldInClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, int num) - { - var _this = GetThis(thisHandle); - try - { - return _this.getFieldInClass(clsHnd, num); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_FIELD_STRUCT_*); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _checkMethodModifier(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, [MarshalAs(UnmanagedType.Bool)]bool fOptional) - { - var _this = GetThis(thisHandle); - try - { - return _this.checkMethodModifier(hMethod, modifier, fOptional); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static CorInfoHelpFunc _getNewHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, byte* pHasSideEffects) - { - var _this = GetThis(thisHandle); - try - { - return _this.getNewHelper(ref pResolvedToken, callerHandle, pHasSideEffects); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoHelpFunc); - } - } - - static CorInfoHelpFunc _getNewArrHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* arrayCls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getNewArrHelper(arrayCls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoHelpFunc); - } - } - - static CorInfoHelpFunc _getCastingHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool fThrowing) - { - var _this = GetThis(thisHandle); - try - { - return _this.getCastingHelper(ref pResolvedToken, fThrowing); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoHelpFunc); - } - } - - static CorInfoHelpFunc _getSharedCCtorHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd) - { - var _this = GetThis(thisHandle); - try - { - return _this.getSharedCCtorHelper(clsHnd); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoHelpFunc); - } - } - - static CorInfoHelpFunc _getSecurityPrologHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn) - { - var _this = GetThis(thisHandle); - try - { - return _this.getSecurityPrologHelper(ftn); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoHelpFunc); - } - } - - static CORINFO_CLASS_STRUCT_* _getTypeForBox(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getTypeForBox(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static CorInfoHelpFunc _getBoxHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getBoxHelper(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoHelpFunc); - } - } - - static CorInfoHelpFunc _getUnBoxHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getUnBoxHelper(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoHelpFunc); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _getReadyToRunHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup) - { - var _this = GetThis(thisHandle); - try - { - return _this.getReadyToRunHelper(ref pResolvedToken, ref pGenericLookupKind, id, ref pLookup); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static void _getReadyToRunDelegateCtorHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pTargetMethod, CORINFO_CLASS_STRUCT_* delegateType, ref CORINFO_LOOKUP pLookup) - { - var _this = GetThis(thisHandle); - try - { - _this.getReadyToRunDelegateCtorHelper(ref pTargetMethod, delegateType, ref pLookup); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static byte* _getHelperName(IntPtr thisHandle, IntPtr* ppException, CorInfoHelpFunc helpFunc) - { - var _this = GetThis(thisHandle); - try - { - return _this.getHelperName(helpFunc); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - static CorInfoInitClassResult _initClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context, [MarshalAs(UnmanagedType.Bool)]bool speculative) - { - var _this = GetThis(thisHandle); - try - { - return _this.initClass(field, method, context, speculative); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoInitClassResult); - } - } - - static void _classMustBeLoadedBeforeCodeIsRun(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - _this.classMustBeLoadedBeforeCodeIsRun(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static CORINFO_CLASS_STRUCT_* _getBuiltinClass(IntPtr thisHandle, IntPtr* ppException, CorInfoClassId classId) - { - var _this = GetThis(thisHandle); - try - { - return _this.getBuiltinClass(classId); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static CorInfoType _getTypeForPrimitiveValueClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getTypeForPrimitiveValueClass(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoType); - } - } - - static CorInfoType _getTypeForPrimitiveNumericClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getTypeForPrimitiveNumericClass(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoType); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _canCast(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) - { - var _this = GetThis(thisHandle); - try - { - return _this.canCast(child, parent); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _areTypesEquivalent(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { - var _this = GetThis(thisHandle); - try - { - return _this.areTypesEquivalent(cls1, cls2); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static TypeCompareState _compareTypesForCast(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) - { - var _this = GetThis(thisHandle); - try - { - return _this.compareTypesForCast(fromClass, toClass); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(TypeCompareState); - } - } - - static TypeCompareState _compareTypesForEquality(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { - var _this = GetThis(thisHandle); - try - { - return _this.compareTypesForEquality(cls1, cls2); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(TypeCompareState); - } - } - - static CORINFO_CLASS_STRUCT_* _mergeClasses(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { - var _this = GetThis(thisHandle); - try - { - return _this.mergeClasses(cls1, cls2); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _isMoreSpecificType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { - var _this = GetThis(thisHandle); - try - { - return _this.isMoreSpecificType(cls1, cls2); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static CORINFO_CLASS_STRUCT_* _getParentType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getParentType(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static CorInfoType _getChildType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) - { - var _this = GetThis(thisHandle); - try - { - return _this.getChildType(clsHnd, clsRet); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoType); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _satisfiesClassConstraints(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.satisfiesClassConstraints(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _isSDArray(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.isSDArray(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static uint _getArrayRank(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.getArrayRank(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static void* _getArrayInitializationData(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, uint size) - { - var _this = GetThis(thisHandle); - try - { - return _this.getArrayInitializationData(field, size); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static CorInfoIsAccessAllowedResult _canAccessClass(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) - { - var _this = GetThis(thisHandle); - try - { - return _this.canAccessClass(ref pResolvedToken, callerHandle, ref pAccessHelper); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoIsAccessAllowedResult); - } - } - - static byte* _getFieldName(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* ftn, byte** moduleName) - { - var _this = GetThis(thisHandle); - try - { - return _this.getFieldName(ftn, moduleName); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - static CORINFO_CLASS_STRUCT_* _getFieldClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field) - { - var _this = GetThis(thisHandle); - try - { - return _this.getFieldClass(field); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static CorInfoType _getFieldType(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent) - { - var _this = GetThis(thisHandle); - try - { - return _this.getFieldType(field, structType, memberParent); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoType); - } - } - - static uint _getFieldOffset(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field) - { - var _this = GetThis(thisHandle); - try - { - return _this.getFieldOffset(field); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _isWriteBarrierHelperRequired(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field) - { - var _this = GetThis(thisHandle); - try - { - return _this.isWriteBarrierHelperRequired(field); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static void _getFieldInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) - { - var _this = GetThis(thisHandle); - try - { - _this.getFieldInfo(ref pResolvedToken, callerHandle, flags, pResult); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _isFieldStatic(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd) - { - var _this = GetThis(thisHandle); - try - { - return _this.isFieldStatic(fldHnd); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static void _getBoundaries(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implictBoundaries) - { - var _this = GetThis(thisHandle); - try - { - _this.getBoundaries(ftn, ref cILOffsets, ref pILOffsets, implictBoundaries); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _setBoundaries(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) - { - var _this = GetThis(thisHandle); - try - { - _this.setBoundaries(ftn, cMap, pMap); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _getVars(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, [MarshalAs(UnmanagedType.U1)] ref bool extendOthers) - { - var _this = GetThis(thisHandle); - try - { - _this.getVars(ftn, ref cVars, vars, ref extendOthers); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _setVars(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) - { - var _this = GetThis(thisHandle); - try - { - _this.setVars(ftn, cVars, vars); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void* _allocateArray(IntPtr thisHandle, IntPtr* ppException, uint cBytes) - { - var _this = GetThis(thisHandle); - try - { - return _this.allocateArray(cBytes); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static void _freeArray(IntPtr thisHandle, IntPtr* ppException, void* array) - { - var _this = GetThis(thisHandle); - try - { - _this.freeArray(array); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static CORINFO_ARG_LIST_STRUCT_* _getArgNext(IntPtr thisHandle, IntPtr* ppException, CORINFO_ARG_LIST_STRUCT_* args) - { - var _this = GetThis(thisHandle); - try - { - return _this.getArgNext(args); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_ARG_LIST_STRUCT_*); - } - } - - static CorInfoTypeWithMod _getArgType(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet) - { - var _this = GetThis(thisHandle); - try - { - return _this.getArgType(sig, args, vcTypeRet); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoTypeWithMod); - } - } - - static CORINFO_CLASS_STRUCT_* _getArgClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) - { - var _this = GetThis(thisHandle); - try - { - return _this.getArgClass(sig, args); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static CorInfoType _getHFAType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* hClass) - { - var _this = GetThis(thisHandle); - try - { - return _this.getHFAType(hClass); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoType); - } - } - - static HRESULT _GetErrorHRESULT(IntPtr thisHandle, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers) - { - var _this = GetThis(thisHandle); - try - { - return _this.GetErrorHRESULT(pExceptionPointers); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(HRESULT); - } - } - - static uint _GetErrorMessage(IntPtr thisHandle, IntPtr* ppException, short* buffer, uint bufferLength) - { - var _this = GetThis(thisHandle); - try - { - return _this.GetErrorMessage(buffer, bufferLength); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static int _FilterException(IntPtr thisHandle, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers) - { - var _this = GetThis(thisHandle); - try - { - return _this.FilterException(pExceptionPointers); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(int); - } - } - - static void _HandleException(IntPtr thisHandle, IntPtr* ppException, _EXCEPTION_POINTERS* pExceptionPointers) - { - var _this = GetThis(thisHandle); - try - { - _this.HandleException(pExceptionPointers); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _ThrowExceptionForJitResult(IntPtr thisHandle, IntPtr* ppException, HRESULT result) - { - var _this = GetThis(thisHandle); - try - { - _this.ThrowExceptionForJitResult(result); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _ThrowExceptionForHelper(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_HELPER_DESC throwHelper) - { - var _this = GetThis(thisHandle); - try - { - _this.ThrowExceptionForHelper(ref throwHelper); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _runWithErrorTrap(IntPtr thisHandle, IntPtr* ppException, void* function, void* parameter) - { - var _this = GetThis(thisHandle); - try - { - return _this.runWithErrorTrap(function, parameter); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static void _getEEInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_EE_INFO pEEInfoOut) - { - var _this = GetThis(thisHandle); - try - { - _this.getEEInfo(ref pEEInfoOut); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - [return: MarshalAs(UnmanagedType.LPWStr)]static string _getJitTimeLogFilename(IntPtr thisHandle, IntPtr* ppException) - { - var _this = GetThis(thisHandle); - try - { - return _this.getJitTimeLogFilename(); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(string); - } - } - - static mdToken _getMethodDefFromMethod(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hMethod) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodDefFromMethod(hMethod); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(mdToken); - } - } - - static byte* _getMethodName(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte** moduleName) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodName(ftn, moduleName); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - static byte* _getMethodNameFromMetadata(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassName) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassName); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - static uint _getMethodHash(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodHash(ftn); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static byte* _findNameOfToken(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* moduleHandle, mdToken token, byte* szFQName, UIntPtr FQNameCapacity) - { - var _this = GetThis(thisHandle); - try - { - return _this.findNameOfToken(moduleHandle, token, szFQName, FQNameCapacity); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(byte*); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _getSystemVAmd64PassStructInRegisterDescriptor(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) - { - var _this = GetThis(thisHandle); - try - { - return _this.getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static uint _getThreadTLSIndex(IntPtr thisHandle, IntPtr* ppException, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getThreadTLSIndex(ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static void* _getInlinedCallFrameVptr(IntPtr thisHandle, IntPtr* ppException, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getInlinedCallFrameVptr(ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static int* _getAddrOfCaptureThreadGlobal(IntPtr thisHandle, IntPtr* ppException, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getAddrOfCaptureThreadGlobal(ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(int*); - } - } - - static void* _getHelperFtn(IntPtr thisHandle, IntPtr* ppException, CorInfoHelpFunc ftnNum, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getHelperFtn(ftnNum, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static void _getFunctionEntryPoint(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) - { - var _this = GetThis(thisHandle); - try - { - _this.getFunctionEntryPoint(ftn, ref pResult, accessFlags); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _getFunctionFixedEntryPoint(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult) - { - var _this = GetThis(thisHandle); - try - { - _this.getFunctionFixedEntryPoint(ftn, ref pResult); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void* _getMethodSync(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodSync(ftn, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static CorInfoHelpFunc _getLazyStringLiteralHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* handle) - { - var _this = GetThis(thisHandle); - try - { - return _this.getLazyStringLiteralHelper(handle); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CorInfoHelpFunc); - } - } - - static CORINFO_MODULE_STRUCT_* _embedModuleHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.embedModuleHandle(handle, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_MODULE_STRUCT_*); - } - } - - static CORINFO_CLASS_STRUCT_* _embedClassHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.embedClassHandle(handle, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static CORINFO_METHOD_STRUCT_* _embedMethodHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.embedMethodHandle(handle, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_METHOD_STRUCT_*); - } - } - - static CORINFO_FIELD_STRUCT_* _embedFieldHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.embedFieldHandle(handle, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_FIELD_STRUCT_*); - } - } - - static void _embedGenericHandle(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.Bool)]bool fEmbedParent, ref CORINFO_GENERICHANDLE_RESULT pResult) - { - var _this = GetThis(thisHandle); - try - { - _this.embedGenericHandle(ref pResolvedToken, fEmbedParent, ref pResult); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _getLocationOfThisType(IntPtr thisHandle, IntPtr* ppException, out CORINFO_LOOKUP_KIND _return, CORINFO_METHOD_STRUCT_* context) - { - var _this = GetThis(thisHandle); - try - { - _this.getLocationOfThisType(out _return, context); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - _return = default(CORINFO_LOOKUP_KIND); - } - } - - static void* _getPInvokeUnmanagedTarget(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getPInvokeUnmanagedTarget(method, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static void* _getAddressOfPInvokeFixup(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getAddressOfPInvokeFixup(method, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static void _getAddressOfPInvokeTarget(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) - { - var _this = GetThis(thisHandle); - try - { - _this.getAddressOfPInvokeTarget(method, ref pLookup); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void* _GetCookieForPInvokeCalliSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.GetCookieForPInvokeCalliSig(szMetaSig, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _canGetCookieForPInvokeCalliSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig) - { - var _this = GetThis(thisHandle); - try - { - return _this.canGetCookieForPInvokeCalliSig(szMetaSig); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static CORINFO_JUST_MY_CODE_HANDLE_* _getJustMyCodeHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getJustMyCodeHandle(method, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_JUST_MY_CODE_HANDLE_*); - } - } - - static void _GetProfilingHandle(IntPtr thisHandle, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)] ref bool pbHookFunction, ref void* pProfilerHandle, [MarshalAs(UnmanagedType.Bool)] ref bool pbIndirectedHandles) - { - var _this = GetThis(thisHandle); - try - { - _this.GetProfilingHandle(ref pbHookFunction, ref pProfilerHandle, ref pbIndirectedHandles); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _getCallInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) - { - var _this = GetThis(thisHandle); - try - { - _this.getCallInfo(ref pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _canAccessFamily(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hCaller, CORINFO_CLASS_STRUCT_* hInstanceType) - { - var _this = GetThis(thisHandle); - try - { - return _this.canAccessFamily(hCaller, hInstanceType); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _isRIDClassDomainID(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) - { - var _this = GetThis(thisHandle); - try - { - return _this.isRIDClassDomainID(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassDomainID(cls, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static void* _getFieldAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, void** ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getFieldAddress(field, ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static CORINFO_CLASS_STRUCT_* _getStaticFieldCurrentClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) - { - var _this = GetThis(thisHandle); - try - { - return _this.getStaticFieldCurrentClass(field, pIsSpeculative); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_CLASS_STRUCT_*); - } - } - - static IntPtr _getVarArgsHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* pSig, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getVarArgsHandle(pSig, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(IntPtr); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _canGetVarArgsHandle(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* pSig) - { - var _this = GetThis(thisHandle); - try - { - return _this.canGetVarArgsHandle(pSig); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static InfoAccessType _constructStringLiteral(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue) - { - var _this = GetThis(thisHandle); - try - { - return _this.constructStringLiteral(module, metaTok, ref ppValue); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(InfoAccessType); - } - } - - static InfoAccessType _emptyStringLiteral(IntPtr thisHandle, IntPtr* ppException, ref void* ppValue) - { - var _this = GetThis(thisHandle); - try - { - return _this.emptyStringLiteral(ref ppValue); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(InfoAccessType); - } - } - - static uint _getFieldThreadLocalStoreID(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getFieldThreadLocalStoreID(field, ref ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static void _setOverride(IntPtr thisHandle, IntPtr* ppException, IntPtr pOverride, CORINFO_METHOD_STRUCT_* currentMethod) - { - var _this = GetThis(thisHandle); - try - { - _this.setOverride(pOverride, currentMethod); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _addActiveDependency(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* moduleFrom, CORINFO_MODULE_STRUCT_* moduleTo) - { - var _this = GetThis(thisHandle); - try - { - _this.addActiveDependency(moduleFrom, moduleTo); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static CORINFO_METHOD_STRUCT_* _GetDelegateCtor(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) - { - var _this = GetThis(thisHandle); - try - { - return _this.GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, ref pCtorData); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(CORINFO_METHOD_STRUCT_*); - } - } - - static void _MethodCompileComplete(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd) - { - var _this = GetThis(thisHandle); - try - { - _this.MethodCompileComplete(methHnd); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void* _getTailCallCopyArgsThunk(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) - { - var _this = GetThis(thisHandle); - try - { - return _this.getTailCallCopyArgsThunk(pSig, flags); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - [return: MarshalAs(UnmanagedType.I1)]static bool _convertPInvokeCalliToCall(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool mustConvert) - { - var _this = GetThis(thisHandle); - try - { - return _this.convertPInvokeCalliToCall(ref pResolvedToken, mustConvert); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static void* _getMemoryManager(IntPtr thisHandle, IntPtr* ppException) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMemoryManager(); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static void _allocMem(IntPtr thisHandle, IntPtr* ppException, uint hotCodeSize, uint coldCodeSize, uint roDataSize, uint xcptnsCount, CorJitAllocMemFlag flag, ref void* hotCodeBlock, ref void* coldCodeBlock, ref void* roDataBlock) - { - var _this = GetThis(thisHandle); - try - { - _this.allocMem(hotCodeSize, coldCodeSize, roDataSize, xcptnsCount, flag, ref hotCodeBlock, ref coldCodeBlock, ref roDataBlock); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _reserveUnwindInfo(IntPtr thisHandle, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)]bool isFunclet, [MarshalAs(UnmanagedType.Bool)]bool isColdCode, uint unwindSize) - { - var _this = GetThis(thisHandle); - try - { - _this.reserveUnwindInfo(isFunclet, isColdCode, unwindSize); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _allocUnwindInfo(IntPtr thisHandle, IntPtr* ppException, byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) - { - var _this = GetThis(thisHandle); - try - { - _this.allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void* _allocGCInfo(IntPtr thisHandle, IntPtr* ppException, UIntPtr size) - { - var _this = GetThis(thisHandle); - try - { - return _this.allocGCInfo(size); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - - static void _yieldExecution(IntPtr thisHandle, IntPtr* ppException) - { - var _this = GetThis(thisHandle); - try - { - _this.yieldExecution(); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _setEHcount(IntPtr thisHandle, IntPtr* ppException, uint cEH) - { - var _this = GetThis(thisHandle); - try - { - _this.setEHcount(cEH); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _setEHinfo(IntPtr thisHandle, IntPtr* ppException, uint EHnumber, ref CORINFO_EH_CLAUSE clause) - { - var _this = GetThis(thisHandle); - try - { - _this.setEHinfo(EHnumber, ref clause); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - [return: MarshalAs(UnmanagedType.Bool)]static bool _logMsg(IntPtr thisHandle, IntPtr* ppException, uint level, byte* fmt, IntPtr args) - { - var _this = GetThis(thisHandle); - try - { - return _this.logMsg(level, fmt, args); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - - static int _doAssert(IntPtr thisHandle, IntPtr* ppException, byte* szFile, int iLine, byte* szExpr) - { - var _this = GetThis(thisHandle); - try - { - return _this.doAssert(szFile, iLine, szExpr); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(int); - } - } - - static void _reportFatalError(IntPtr thisHandle, IntPtr* ppException, CorJitResult result) - { - var _this = GetThis(thisHandle); - try - { - _this.reportFatalError(result); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static HRESULT _allocMethodBlockCounts(IntPtr thisHandle, IntPtr* ppException, uint count, ref BlockCounts* pBlockCounts) - { - var _this = GetThis(thisHandle); - try - { - return _this.allocMethodBlockCounts(count, ref pBlockCounts); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(HRESULT); - } - } - - static HRESULT _getMethodBlockCounts(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHnd, ref uint pCount, ref BlockCounts* pBlockCounts, ref uint pNumRuns) - { - var _this = GetThis(thisHandle); - try - { - return _this.getMethodBlockCounts(ftnHnd, ref pCount, ref pBlockCounts, ref pNumRuns); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(HRESULT); - } - } - - static void _recordCallSite(IntPtr thisHandle, IntPtr* ppException, uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) - { - var _this = GetThis(thisHandle); - try - { - _this.recordCallSite(instrOffset, callSig, methodHandle); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static void _recordRelocation(IntPtr thisHandle, IntPtr* ppException, void* location, void* target, ushort fRelocType, ushort slotNum, int addlDelta) - { - var _this = GetThis(thisHandle); - try - { - _this.recordRelocation(location, target, fRelocType, slotNum, addlDelta); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static ushort _getRelocTypeHint(IntPtr thisHandle, IntPtr* ppException, void* target) - { - var _this = GetThis(thisHandle); - try - { - return _this.getRelocTypeHint(target); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(ushort); - } - } - - static void _getModuleNativeEntryPointRange(IntPtr thisHandle, IntPtr* ppException, ref void* pStart, ref void* pEnd) - { - var _this = GetThis(thisHandle); - try - { - _this.getModuleNativeEntryPointRange(ref pStart, ref pEnd); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - } - } - - static uint _getExpectedTargetArchitecture(IntPtr thisHandle, IntPtr* ppException) - { - var _this = GetThis(thisHandle); - try - { - return _this.getExpectedTargetArchitecture(); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, ref CORJIT_FLAGS flags, uint sizeInBytes) - { - var _this = GetThis(thisHandle); - try - { - return _this.getJitFlags(ref flags, sizeInBytes); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(uint); - } - } - - - static IntPtr GetUnmanagedCallbacks(out Object keepAlive) - { - IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 179); - Object[] delegates = new Object[179]; - - var d0 = new __getMethodAttribs(_getMethodAttribs); - callbacks[0] = Marshal.GetFunctionPointerForDelegate(d0); - delegates[0] = d0; - var d1 = new __setMethodAttribs(_setMethodAttribs); - callbacks[1] = Marshal.GetFunctionPointerForDelegate(d1); - delegates[1] = d1; - var d2 = new __getMethodSig(_getMethodSig); - callbacks[2] = Marshal.GetFunctionPointerForDelegate(d2); - delegates[2] = d2; - var d3 = new __getMethodInfo(_getMethodInfo); - callbacks[3] = Marshal.GetFunctionPointerForDelegate(d3); - delegates[3] = d3; - var d4 = new __canInline(_canInline); - callbacks[4] = Marshal.GetFunctionPointerForDelegate(d4); - delegates[4] = d4; - var d5 = new __reportInliningDecision(_reportInliningDecision); - callbacks[5] = Marshal.GetFunctionPointerForDelegate(d5); - delegates[5] = d5; - var d6 = new __canTailCall(_canTailCall); - callbacks[6] = Marshal.GetFunctionPointerForDelegate(d6); - delegates[6] = d6; - var d7 = new __reportTailCallDecision(_reportTailCallDecision); - callbacks[7] = Marshal.GetFunctionPointerForDelegate(d7); - delegates[7] = d7; - var d8 = new __getEHinfo(_getEHinfo); - callbacks[8] = Marshal.GetFunctionPointerForDelegate(d8); - delegates[8] = d8; - var d9 = new __getMethodClass(_getMethodClass); - callbacks[9] = Marshal.GetFunctionPointerForDelegate(d9); - delegates[9] = d9; - var d10 = new __getMethodModule(_getMethodModule); - callbacks[10] = Marshal.GetFunctionPointerForDelegate(d10); - delegates[10] = d10; - var d11 = new __getMethodVTableOffset(_getMethodVTableOffset); - callbacks[11] = Marshal.GetFunctionPointerForDelegate(d11); - delegates[11] = d11; - var d12 = new __resolveVirtualMethod(_resolveVirtualMethod); - callbacks[12] = Marshal.GetFunctionPointerForDelegate(d12); - delegates[12] = d12; - var d13 = new __getUnboxedEntry(_getUnboxedEntry); - callbacks[13] = Marshal.GetFunctionPointerForDelegate(d13); - delegates[13] = d13; - var d14 = new __getDefaultEqualityComparerClass(_getDefaultEqualityComparerClass); - callbacks[14] = Marshal.GetFunctionPointerForDelegate(d14); - delegates[14] = d14; - var d15 = new __expandRawHandleIntrinsic(_expandRawHandleIntrinsic); - callbacks[15] = Marshal.GetFunctionPointerForDelegate(d15); - delegates[15] = d15; - var d16 = new __getIntrinsicID(_getIntrinsicID); - callbacks[16] = Marshal.GetFunctionPointerForDelegate(d16); - delegates[16] = d16; - var d17 = new __isIntrinsicType(_isIntrinsicType); - callbacks[17] = Marshal.GetFunctionPointerForDelegate(d17); - delegates[17] = d17; - var d18 = new __getUnmanagedCallConv(_getUnmanagedCallConv); - callbacks[18] = Marshal.GetFunctionPointerForDelegate(d18); - delegates[18] = d18; - var d19 = new __pInvokeMarshalingRequired(_pInvokeMarshalingRequired); - callbacks[19] = Marshal.GetFunctionPointerForDelegate(d19); - delegates[19] = d19; - var d20 = new __satisfiesMethodConstraints(_satisfiesMethodConstraints); - callbacks[20] = Marshal.GetFunctionPointerForDelegate(d20); - delegates[20] = d20; - var d21 = new __isCompatibleDelegate(_isCompatibleDelegate); - callbacks[21] = Marshal.GetFunctionPointerForDelegate(d21); - delegates[21] = d21; - var d22 = new __isInstantiationOfVerifiedGeneric(_isInstantiationOfVerifiedGeneric); - callbacks[22] = Marshal.GetFunctionPointerForDelegate(d22); - delegates[22] = d22; - var d23 = new __initConstraintsForVerification(_initConstraintsForVerification); - callbacks[23] = Marshal.GetFunctionPointerForDelegate(d23); - delegates[23] = d23; - var d24 = new __canSkipMethodVerification(_canSkipMethodVerification); - callbacks[24] = Marshal.GetFunctionPointerForDelegate(d24); - delegates[24] = d24; - var d25 = new __methodMustBeLoadedBeforeCodeIsRun(_methodMustBeLoadedBeforeCodeIsRun); - callbacks[25] = Marshal.GetFunctionPointerForDelegate(d25); - delegates[25] = d25; - var d26 = new __mapMethodDeclToMethodImpl(_mapMethodDeclToMethodImpl); - callbacks[26] = Marshal.GetFunctionPointerForDelegate(d26); - delegates[26] = d26; - var d27 = new __getGSCookie(_getGSCookie); - callbacks[27] = Marshal.GetFunctionPointerForDelegate(d27); - delegates[27] = d27; - var d28 = new __resolveToken(_resolveToken); - callbacks[28] = Marshal.GetFunctionPointerForDelegate(d28); - delegates[28] = d28; - var d29 = new __tryResolveToken(_tryResolveToken); - callbacks[29] = Marshal.GetFunctionPointerForDelegate(d29); - delegates[29] = d29; - var d30 = new __findSig(_findSig); - callbacks[30] = Marshal.GetFunctionPointerForDelegate(d30); - delegates[30] = d30; - var d31 = new __findCallSiteSig(_findCallSiteSig); - callbacks[31] = Marshal.GetFunctionPointerForDelegate(d31); - delegates[31] = d31; - var d32 = new __getTokenTypeAsHandle(_getTokenTypeAsHandle); - callbacks[32] = Marshal.GetFunctionPointerForDelegate(d32); - delegates[32] = d32; - var d33 = new __canSkipVerification(_canSkipVerification); - callbacks[33] = Marshal.GetFunctionPointerForDelegate(d33); - delegates[33] = d33; - var d34 = new __isValidToken(_isValidToken); - callbacks[34] = Marshal.GetFunctionPointerForDelegate(d34); - delegates[34] = d34; - var d35 = new __isValidStringRef(_isValidStringRef); - callbacks[35] = Marshal.GetFunctionPointerForDelegate(d35); - delegates[35] = d35; - var d36 = new __shouldEnforceCallvirtRestriction(_shouldEnforceCallvirtRestriction); - callbacks[36] = Marshal.GetFunctionPointerForDelegate(d36); - delegates[36] = d36; - var d37 = new __asCorInfoType(_asCorInfoType); - callbacks[37] = Marshal.GetFunctionPointerForDelegate(d37); - delegates[37] = d37; - var d38 = new __getClassName(_getClassName); - callbacks[38] = Marshal.GetFunctionPointerForDelegate(d38); - delegates[38] = d38; - var d39 = new __getClassNameFromMetadata(_getClassNameFromMetadata); - callbacks[39] = Marshal.GetFunctionPointerForDelegate(d39); - delegates[39] = d39; - var d40 = new __getTypeInstantiationArgument(_getTypeInstantiationArgument); - callbacks[40] = Marshal.GetFunctionPointerForDelegate(d40); - delegates[40] = d40; - var d41 = new __appendClassName(_appendClassName); - callbacks[41] = Marshal.GetFunctionPointerForDelegate(d41); - delegates[41] = d41; - var d42 = new __isValueClass(_isValueClass); - callbacks[42] = Marshal.GetFunctionPointerForDelegate(d42); - delegates[42] = d42; - var d43 = new __canInlineTypeCheck(_canInlineTypeCheck); - callbacks[43] = Marshal.GetFunctionPointerForDelegate(d43); - delegates[43] = d43; - var d44 = new __canInlineTypeCheckWithObjectVTable(_canInlineTypeCheckWithObjectVTable); - callbacks[44] = Marshal.GetFunctionPointerForDelegate(d44); - delegates[44] = d44; - var d45 = new __getClassAttribs(_getClassAttribs); - callbacks[45] = Marshal.GetFunctionPointerForDelegate(d45); - delegates[45] = d45; - var d46 = new __isStructRequiringStackAllocRetBuf(_isStructRequiringStackAllocRetBuf); - callbacks[46] = Marshal.GetFunctionPointerForDelegate(d46); - delegates[46] = d46; - var d47 = new __getClassModule(_getClassModule); - callbacks[47] = Marshal.GetFunctionPointerForDelegate(d47); - delegates[47] = d47; - var d48 = new __getModuleAssembly(_getModuleAssembly); - callbacks[48] = Marshal.GetFunctionPointerForDelegate(d48); - delegates[48] = d48; - var d49 = new __getAssemblyName(_getAssemblyName); - callbacks[49] = Marshal.GetFunctionPointerForDelegate(d49); - delegates[49] = d49; - var d50 = new __LongLifetimeMalloc(_LongLifetimeMalloc); - callbacks[50] = Marshal.GetFunctionPointerForDelegate(d50); - delegates[50] = d50; - var d51 = new __LongLifetimeFree(_LongLifetimeFree); - callbacks[51] = Marshal.GetFunctionPointerForDelegate(d51); - delegates[51] = d51; - var d52 = new __getClassModuleIdForStatics(_getClassModuleIdForStatics); - callbacks[52] = Marshal.GetFunctionPointerForDelegate(d52); - delegates[52] = d52; - var d53 = new __getClassSize(_getClassSize); - callbacks[53] = Marshal.GetFunctionPointerForDelegate(d53); - delegates[53] = d53; - var d54 = new __getHeapClassSize(_getHeapClassSize); - callbacks[54] = Marshal.GetFunctionPointerForDelegate(d54); - delegates[54] = d54; - var d55 = new __canAllocateOnStack(_canAllocateOnStack); - callbacks[55] = Marshal.GetFunctionPointerForDelegate(d55); - delegates[55] = d55; - var d56 = new __getClassAlignmentRequirement(_getClassAlignmentRequirement); - callbacks[56] = Marshal.GetFunctionPointerForDelegate(d56); - delegates[56] = d56; - var d57 = new __getClassGClayout(_getClassGClayout); - callbacks[57] = Marshal.GetFunctionPointerForDelegate(d57); - delegates[57] = d57; - var d58 = new __getClassNumInstanceFields(_getClassNumInstanceFields); - callbacks[58] = Marshal.GetFunctionPointerForDelegate(d58); - delegates[58] = d58; - var d59 = new __getFieldInClass(_getFieldInClass); - callbacks[59] = Marshal.GetFunctionPointerForDelegate(d59); - delegates[59] = d59; - var d60 = new __checkMethodModifier(_checkMethodModifier); - callbacks[60] = Marshal.GetFunctionPointerForDelegate(d60); - delegates[60] = d60; - var d61 = new __getNewHelper(_getNewHelper); - callbacks[61] = Marshal.GetFunctionPointerForDelegate(d61); - delegates[61] = d61; - var d62 = new __getNewArrHelper(_getNewArrHelper); - callbacks[62] = Marshal.GetFunctionPointerForDelegate(d62); - delegates[62] = d62; - var d63 = new __getCastingHelper(_getCastingHelper); - callbacks[63] = Marshal.GetFunctionPointerForDelegate(d63); - delegates[63] = d63; - var d64 = new __getSharedCCtorHelper(_getSharedCCtorHelper); - callbacks[64] = Marshal.GetFunctionPointerForDelegate(d64); - delegates[64] = d64; - var d65 = new __getSecurityPrologHelper(_getSecurityPrologHelper); - callbacks[65] = Marshal.GetFunctionPointerForDelegate(d65); - delegates[65] = d65; - var d66 = new __getTypeForBox(_getTypeForBox); - callbacks[66] = Marshal.GetFunctionPointerForDelegate(d66); - delegates[66] = d66; - var d67 = new __getBoxHelper(_getBoxHelper); - callbacks[67] = Marshal.GetFunctionPointerForDelegate(d67); - delegates[67] = d67; - var d68 = new __getUnBoxHelper(_getUnBoxHelper); - callbacks[68] = Marshal.GetFunctionPointerForDelegate(d68); - delegates[68] = d68; - var d69 = new __getReadyToRunHelper(_getReadyToRunHelper); - callbacks[69] = Marshal.GetFunctionPointerForDelegate(d69); - delegates[69] = d69; - var d70 = new __getReadyToRunDelegateCtorHelper(_getReadyToRunDelegateCtorHelper); - callbacks[70] = Marshal.GetFunctionPointerForDelegate(d70); - delegates[70] = d70; - var d71 = new __getHelperName(_getHelperName); - callbacks[71] = Marshal.GetFunctionPointerForDelegate(d71); - delegates[71] = d71; - var d72 = new __initClass(_initClass); - callbacks[72] = Marshal.GetFunctionPointerForDelegate(d72); - delegates[72] = d72; - var d73 = new __classMustBeLoadedBeforeCodeIsRun(_classMustBeLoadedBeforeCodeIsRun); - callbacks[73] = Marshal.GetFunctionPointerForDelegate(d73); - delegates[73] = d73; - var d74 = new __getBuiltinClass(_getBuiltinClass); - callbacks[74] = Marshal.GetFunctionPointerForDelegate(d74); - delegates[74] = d74; - var d75 = new __getTypeForPrimitiveValueClass(_getTypeForPrimitiveValueClass); - callbacks[75] = Marshal.GetFunctionPointerForDelegate(d75); - delegates[75] = d75; - var d76 = new __getTypeForPrimitiveNumericClass(_getTypeForPrimitiveNumericClass); - callbacks[76] = Marshal.GetFunctionPointerForDelegate(d76); - delegates[76] = d76; - var d77 = new __canCast(_canCast); - callbacks[77] = Marshal.GetFunctionPointerForDelegate(d77); - delegates[77] = d77; - var d78 = new __areTypesEquivalent(_areTypesEquivalent); - callbacks[78] = Marshal.GetFunctionPointerForDelegate(d78); - delegates[78] = d78; - var d79 = new __compareTypesForCast(_compareTypesForCast); - callbacks[79] = Marshal.GetFunctionPointerForDelegate(d79); - delegates[79] = d79; - var d80 = new __compareTypesForEquality(_compareTypesForEquality); - callbacks[80] = Marshal.GetFunctionPointerForDelegate(d80); - delegates[80] = d80; - var d81 = new __mergeClasses(_mergeClasses); - callbacks[81] = Marshal.GetFunctionPointerForDelegate(d81); - delegates[81] = d81; - var d82 = new __isMoreSpecificType(_isMoreSpecificType); - callbacks[82] = Marshal.GetFunctionPointerForDelegate(d82); - delegates[82] = d82; - var d83 = new __getParentType(_getParentType); - callbacks[83] = Marshal.GetFunctionPointerForDelegate(d83); - delegates[83] = d83; - var d84 = new __getChildType(_getChildType); - callbacks[84] = Marshal.GetFunctionPointerForDelegate(d84); - delegates[84] = d84; - var d85 = new __satisfiesClassConstraints(_satisfiesClassConstraints); - callbacks[85] = Marshal.GetFunctionPointerForDelegate(d85); - delegates[85] = d85; - var d86 = new __isSDArray(_isSDArray); - callbacks[86] = Marshal.GetFunctionPointerForDelegate(d86); - delegates[86] = d86; - var d87 = new __getArrayRank(_getArrayRank); - callbacks[87] = Marshal.GetFunctionPointerForDelegate(d87); - delegates[87] = d87; - var d88 = new __getArrayInitializationData(_getArrayInitializationData); - callbacks[88] = Marshal.GetFunctionPointerForDelegate(d88); - delegates[88] = d88; - var d89 = new __canAccessClass(_canAccessClass); - callbacks[89] = Marshal.GetFunctionPointerForDelegate(d89); - delegates[89] = d89; - var d90 = new __getFieldName(_getFieldName); - callbacks[90] = Marshal.GetFunctionPointerForDelegate(d90); - delegates[90] = d90; - var d91 = new __getFieldClass(_getFieldClass); - callbacks[91] = Marshal.GetFunctionPointerForDelegate(d91); - delegates[91] = d91; - var d92 = new __getFieldType(_getFieldType); - callbacks[92] = Marshal.GetFunctionPointerForDelegate(d92); - delegates[92] = d92; - var d93 = new __getFieldOffset(_getFieldOffset); - callbacks[93] = Marshal.GetFunctionPointerForDelegate(d93); - delegates[93] = d93; - var d94 = new __isWriteBarrierHelperRequired(_isWriteBarrierHelperRequired); - callbacks[94] = Marshal.GetFunctionPointerForDelegate(d94); - delegates[94] = d94; - var d95 = new __getFieldInfo(_getFieldInfo); - callbacks[95] = Marshal.GetFunctionPointerForDelegate(d95); - delegates[95] = d95; - var d96 = new __isFieldStatic(_isFieldStatic); - callbacks[96] = Marshal.GetFunctionPointerForDelegate(d96); - delegates[96] = d96; - var d97 = new __getBoundaries(_getBoundaries); - callbacks[97] = Marshal.GetFunctionPointerForDelegate(d97); - delegates[97] = d97; - var d98 = new __setBoundaries(_setBoundaries); - callbacks[98] = Marshal.GetFunctionPointerForDelegate(d98); - delegates[98] = d98; - var d99 = new __getVars(_getVars); - callbacks[99] = Marshal.GetFunctionPointerForDelegate(d99); - delegates[99] = d99; - var d100 = new __setVars(_setVars); - callbacks[100] = Marshal.GetFunctionPointerForDelegate(d100); - delegates[100] = d100; - var d101 = new __allocateArray(_allocateArray); - callbacks[101] = Marshal.GetFunctionPointerForDelegate(d101); - delegates[101] = d101; - var d102 = new __freeArray(_freeArray); - callbacks[102] = Marshal.GetFunctionPointerForDelegate(d102); - delegates[102] = d102; - var d103 = new __getArgNext(_getArgNext); - callbacks[103] = Marshal.GetFunctionPointerForDelegate(d103); - delegates[103] = d103; - var d104 = new __getArgType(_getArgType); - callbacks[104] = Marshal.GetFunctionPointerForDelegate(d104); - delegates[104] = d104; - var d105 = new __getArgClass(_getArgClass); - callbacks[105] = Marshal.GetFunctionPointerForDelegate(d105); - delegates[105] = d105; - var d106 = new __getHFAType(_getHFAType); - callbacks[106] = Marshal.GetFunctionPointerForDelegate(d106); - delegates[106] = d106; - var d107 = new __GetErrorHRESULT(_GetErrorHRESULT); - callbacks[107] = Marshal.GetFunctionPointerForDelegate(d107); - delegates[107] = d107; - var d108 = new __GetErrorMessage(_GetErrorMessage); - callbacks[108] = Marshal.GetFunctionPointerForDelegate(d108); - delegates[108] = d108; - var d109 = new __FilterException(_FilterException); - callbacks[109] = Marshal.GetFunctionPointerForDelegate(d109); - delegates[109] = d109; - var d110 = new __HandleException(_HandleException); - callbacks[110] = Marshal.GetFunctionPointerForDelegate(d110); - delegates[110] = d110; - var d111 = new __ThrowExceptionForJitResult(_ThrowExceptionForJitResult); - callbacks[111] = Marshal.GetFunctionPointerForDelegate(d111); - delegates[111] = d111; - var d112 = new __ThrowExceptionForHelper(_ThrowExceptionForHelper); - callbacks[112] = Marshal.GetFunctionPointerForDelegate(d112); - delegates[112] = d112; - var d113 = new __runWithErrorTrap(_runWithErrorTrap); - callbacks[113] = Marshal.GetFunctionPointerForDelegate(d113); - delegates[113] = d113; - var d114 = new __getEEInfo(_getEEInfo); - callbacks[114] = Marshal.GetFunctionPointerForDelegate(d114); - delegates[114] = d114; - var d115 = new __getJitTimeLogFilename(_getJitTimeLogFilename); - callbacks[115] = Marshal.GetFunctionPointerForDelegate(d115); - delegates[115] = d115; - var d116 = new __getMethodDefFromMethod(_getMethodDefFromMethod); - callbacks[116] = Marshal.GetFunctionPointerForDelegate(d116); - delegates[116] = d116; - var d117 = new __getMethodName(_getMethodName); - callbacks[117] = Marshal.GetFunctionPointerForDelegate(d117); - delegates[117] = d117; - var d118 = new __getMethodNameFromMetadata(_getMethodNameFromMetadata); - callbacks[118] = Marshal.GetFunctionPointerForDelegate(d118); - delegates[118] = d118; - var d119 = new __getMethodHash(_getMethodHash); - callbacks[119] = Marshal.GetFunctionPointerForDelegate(d119); - delegates[119] = d119; - var d120 = new __findNameOfToken(_findNameOfToken); - callbacks[120] = Marshal.GetFunctionPointerForDelegate(d120); - delegates[120] = d120; - var d121 = new __getSystemVAmd64PassStructInRegisterDescriptor(_getSystemVAmd64PassStructInRegisterDescriptor); - callbacks[121] = Marshal.GetFunctionPointerForDelegate(d121); - delegates[121] = d121; - var d122 = new __getThreadTLSIndex(_getThreadTLSIndex); - callbacks[122] = Marshal.GetFunctionPointerForDelegate(d122); - delegates[122] = d122; - var d123 = new __getInlinedCallFrameVptr(_getInlinedCallFrameVptr); - callbacks[123] = Marshal.GetFunctionPointerForDelegate(d123); - delegates[123] = d123; - var d124 = new __getAddrOfCaptureThreadGlobal(_getAddrOfCaptureThreadGlobal); - callbacks[124] = Marshal.GetFunctionPointerForDelegate(d124); - delegates[124] = d124; - var d125 = new __getHelperFtn(_getHelperFtn); - callbacks[125] = Marshal.GetFunctionPointerForDelegate(d125); - delegates[125] = d125; - var d126 = new __getFunctionEntryPoint(_getFunctionEntryPoint); - callbacks[126] = Marshal.GetFunctionPointerForDelegate(d126); - delegates[126] = d126; - var d127 = new __getFunctionFixedEntryPoint(_getFunctionFixedEntryPoint); - callbacks[127] = Marshal.GetFunctionPointerForDelegate(d127); - delegates[127] = d127; - var d128 = new __getMethodSync(_getMethodSync); - callbacks[128] = Marshal.GetFunctionPointerForDelegate(d128); - delegates[128] = d128; - var d129 = new __getLazyStringLiteralHelper(_getLazyStringLiteralHelper); - callbacks[129] = Marshal.GetFunctionPointerForDelegate(d129); - delegates[129] = d129; - var d130 = new __embedModuleHandle(_embedModuleHandle); - callbacks[130] = Marshal.GetFunctionPointerForDelegate(d130); - delegates[130] = d130; - var d131 = new __embedClassHandle(_embedClassHandle); - callbacks[131] = Marshal.GetFunctionPointerForDelegate(d131); - delegates[131] = d131; - var d132 = new __embedMethodHandle(_embedMethodHandle); - callbacks[132] = Marshal.GetFunctionPointerForDelegate(d132); - delegates[132] = d132; - var d133 = new __embedFieldHandle(_embedFieldHandle); - callbacks[133] = Marshal.GetFunctionPointerForDelegate(d133); - delegates[133] = d133; - var d134 = new __embedGenericHandle(_embedGenericHandle); - callbacks[134] = Marshal.GetFunctionPointerForDelegate(d134); - delegates[134] = d134; - var d135 = new __getLocationOfThisType(_getLocationOfThisType); - callbacks[135] = Marshal.GetFunctionPointerForDelegate(d135); - delegates[135] = d135; - var d136 = new __getPInvokeUnmanagedTarget(_getPInvokeUnmanagedTarget); - callbacks[136] = Marshal.GetFunctionPointerForDelegate(d136); - delegates[136] = d136; - var d137 = new __getAddressOfPInvokeFixup(_getAddressOfPInvokeFixup); - callbacks[137] = Marshal.GetFunctionPointerForDelegate(d137); - delegates[137] = d137; - var d138 = new __getAddressOfPInvokeTarget(_getAddressOfPInvokeTarget); - callbacks[138] = Marshal.GetFunctionPointerForDelegate(d138); - delegates[138] = d138; - var d139 = new __GetCookieForPInvokeCalliSig(_GetCookieForPInvokeCalliSig); - callbacks[139] = Marshal.GetFunctionPointerForDelegate(d139); - delegates[139] = d139; - var d140 = new __canGetCookieForPInvokeCalliSig(_canGetCookieForPInvokeCalliSig); - callbacks[140] = Marshal.GetFunctionPointerForDelegate(d140); - delegates[140] = d140; - var d141 = new __getJustMyCodeHandle(_getJustMyCodeHandle); - callbacks[141] = Marshal.GetFunctionPointerForDelegate(d141); - delegates[141] = d141; - var d142 = new __GetProfilingHandle(_GetProfilingHandle); - callbacks[142] = Marshal.GetFunctionPointerForDelegate(d142); - delegates[142] = d142; - var d143 = new __getCallInfo(_getCallInfo); - callbacks[143] = Marshal.GetFunctionPointerForDelegate(d143); - delegates[143] = d143; - var d144 = new __canAccessFamily(_canAccessFamily); - callbacks[144] = Marshal.GetFunctionPointerForDelegate(d144); - delegates[144] = d144; - var d145 = new __isRIDClassDomainID(_isRIDClassDomainID); - callbacks[145] = Marshal.GetFunctionPointerForDelegate(d145); - delegates[145] = d145; - var d146 = new __getClassDomainID(_getClassDomainID); - callbacks[146] = Marshal.GetFunctionPointerForDelegate(d146); - delegates[146] = d146; - var d147 = new __getFieldAddress(_getFieldAddress); - callbacks[147] = Marshal.GetFunctionPointerForDelegate(d147); - delegates[147] = d147; - var d148 = new __getStaticFieldCurrentClass(_getStaticFieldCurrentClass); - callbacks[148] = Marshal.GetFunctionPointerForDelegate(d148); - delegates[148] = d148; - var d149 = new __getVarArgsHandle(_getVarArgsHandle); - callbacks[149] = Marshal.GetFunctionPointerForDelegate(d149); - delegates[149] = d149; - var d150 = new __canGetVarArgsHandle(_canGetVarArgsHandle); - callbacks[150] = Marshal.GetFunctionPointerForDelegate(d150); - delegates[150] = d150; - var d151 = new __constructStringLiteral(_constructStringLiteral); - callbacks[151] = Marshal.GetFunctionPointerForDelegate(d151); - delegates[151] = d151; - var d152 = new __emptyStringLiteral(_emptyStringLiteral); - callbacks[152] = Marshal.GetFunctionPointerForDelegate(d152); - delegates[152] = d152; - var d153 = new __getFieldThreadLocalStoreID(_getFieldThreadLocalStoreID); - callbacks[153] = Marshal.GetFunctionPointerForDelegate(d153); - delegates[153] = d153; - var d154 = new __setOverride(_setOverride); - callbacks[154] = Marshal.GetFunctionPointerForDelegate(d154); - delegates[154] = d154; - var d155 = new __addActiveDependency(_addActiveDependency); - callbacks[155] = Marshal.GetFunctionPointerForDelegate(d155); - delegates[155] = d155; - var d156 = new __GetDelegateCtor(_GetDelegateCtor); - callbacks[156] = Marshal.GetFunctionPointerForDelegate(d156); - delegates[156] = d156; - var d157 = new __MethodCompileComplete(_MethodCompileComplete); - callbacks[157] = Marshal.GetFunctionPointerForDelegate(d157); - delegates[157] = d157; - var d158 = new __getTailCallCopyArgsThunk(_getTailCallCopyArgsThunk); - callbacks[158] = Marshal.GetFunctionPointerForDelegate(d158); - delegates[158] = d158; - var d159 = new __convertPInvokeCalliToCall(_convertPInvokeCalliToCall); - callbacks[159] = Marshal.GetFunctionPointerForDelegate(d159); - delegates[159] = d159; - var d160 = new __getMemoryManager(_getMemoryManager); - callbacks[160] = Marshal.GetFunctionPointerForDelegate(d160); - delegates[160] = d160; - var d161 = new __allocMem(_allocMem); - callbacks[161] = Marshal.GetFunctionPointerForDelegate(d161); - delegates[161] = d161; - var d162 = new __reserveUnwindInfo(_reserveUnwindInfo); - callbacks[162] = Marshal.GetFunctionPointerForDelegate(d162); - delegates[162] = d162; - var d163 = new __allocUnwindInfo(_allocUnwindInfo); - callbacks[163] = Marshal.GetFunctionPointerForDelegate(d163); - delegates[163] = d163; - var d164 = new __allocGCInfo(_allocGCInfo); - callbacks[164] = Marshal.GetFunctionPointerForDelegate(d164); - delegates[164] = d164; - var d165 = new __yieldExecution(_yieldExecution); - callbacks[165] = Marshal.GetFunctionPointerForDelegate(d165); - delegates[165] = d165; - var d166 = new __setEHcount(_setEHcount); - callbacks[166] = Marshal.GetFunctionPointerForDelegate(d166); - delegates[166] = d166; - var d167 = new __setEHinfo(_setEHinfo); - callbacks[167] = Marshal.GetFunctionPointerForDelegate(d167); - delegates[167] = d167; - var d168 = new __logMsg(_logMsg); - callbacks[168] = Marshal.GetFunctionPointerForDelegate(d168); - delegates[168] = d168; - var d169 = new __doAssert(_doAssert); - callbacks[169] = Marshal.GetFunctionPointerForDelegate(d169); - delegates[169] = d169; - var d170 = new __reportFatalError(_reportFatalError); - callbacks[170] = Marshal.GetFunctionPointerForDelegate(d170); - delegates[170] = d170; - var d171 = new __allocMethodBlockCounts(_allocMethodBlockCounts); - callbacks[171] = Marshal.GetFunctionPointerForDelegate(d171); - delegates[171] = d171; - var d172 = new __getMethodBlockCounts(_getMethodBlockCounts); - callbacks[172] = Marshal.GetFunctionPointerForDelegate(d172); - delegates[172] = d172; - var d173 = new __recordCallSite(_recordCallSite); - callbacks[173] = Marshal.GetFunctionPointerForDelegate(d173); - delegates[173] = d173; - var d174 = new __recordRelocation(_recordRelocation); - callbacks[174] = Marshal.GetFunctionPointerForDelegate(d174); - delegates[174] = d174; - var d175 = new __getRelocTypeHint(_getRelocTypeHint); - callbacks[175] = Marshal.GetFunctionPointerForDelegate(d175); - delegates[175] = d175; - var d176 = new __getModuleNativeEntryPointRange(_getModuleNativeEntryPointRange); - callbacks[176] = Marshal.GetFunctionPointerForDelegate(d176); - delegates[176] = d176; - var d177 = new __getExpectedTargetArchitecture(_getExpectedTargetArchitecture); - callbacks[177] = Marshal.GetFunctionPointerForDelegate(d177); - delegates[177] = d177; - var d178 = new __getJitFlags(_getJitFlags); - callbacks[178] = Marshal.GetFunctionPointerForDelegate(d178); - delegates[178] = d178; - - keepAlive = delegates; - return (IntPtr)callbacks; - } - } -} - diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoHelpFunc.cs deleted file mode 100644 index b879af5a919..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoHelpFunc.cs +++ /dev/null @@ -1,320 +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 System.Collections.Generic; -using System.Text; - -namespace Internal.JitInterface -{ - // CorInfoHelpFunc defines the set of helpers (accessed via the ICorDynamicInfo::getHelperFtn()) - // These helpers can be called by native code which executes in the runtime. - // Compilers can emit calls to these helpers. - - public enum CorInfoHelpFunc - { - CORINFO_HELP_UNDEF, // invalid value. This should never be used - - /* Arithmetic helpers */ - - CORINFO_HELP_DIV, // For the ARM 32-bit integer divide uses a helper call :-( - CORINFO_HELP_MOD, - CORINFO_HELP_UDIV, - CORINFO_HELP_UMOD, - - CORINFO_HELP_LLSH, - CORINFO_HELP_LRSH, - CORINFO_HELP_LRSZ, - CORINFO_HELP_LMUL, - CORINFO_HELP_LMUL_OVF, - CORINFO_HELP_ULMUL_OVF, - CORINFO_HELP_LDIV, - CORINFO_HELP_LMOD, - CORINFO_HELP_ULDIV, - CORINFO_HELP_ULMOD, - CORINFO_HELP_LNG2DBL, // Convert a signed int64 to a double - CORINFO_HELP_ULNG2DBL, // Convert a unsigned int64 to a double - CORINFO_HELP_DBL2INT, - CORINFO_HELP_DBL2INT_OVF, - CORINFO_HELP_DBL2LNG, - CORINFO_HELP_DBL2LNG_OVF, - CORINFO_HELP_DBL2UINT, - CORINFO_HELP_DBL2UINT_OVF, - CORINFO_HELP_DBL2ULNG, - CORINFO_HELP_DBL2ULNG_OVF, - CORINFO_HELP_FLTREM, - CORINFO_HELP_DBLREM, - CORINFO_HELP_FLTROUND, - CORINFO_HELP_DBLROUND, - - /* Allocating a new object. Always use ICorClassInfo::getNewHelper() to decide - which is the right helper to use to allocate an object of a given type. */ - - CORINFO_HELP_NEW_CROSSCONTEXT, // cross context new object - CORINFO_HELP_NEWFAST, - CORINFO_HELP_NEWSFAST, // allocator for small, non-finalizer, non-array object - CORINFO_HELP_NEWSFAST_FINALIZE, // allocator for small, finalizable, non-array object - CORINFO_HELP_NEWSFAST_ALIGN8, // allocator for small, non-finalizer, non-array object, 8 byte aligned - CORINFO_HELP_NEWSFAST_ALIGN8_VC,// allocator for small, value class, 8 byte aligned - CORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE, // allocator for small, finalizable, non-array object, 8 byte aligned - CORINFO_HELP_NEW_MDARR, // multi-dim array helper (with or without lower bounds - dimensions passed in as vararg) - CORINFO_HELP_NEW_MDARR_NONVARARG,// multi-dim array helper (with or without lower bounds - dimensions passed in as unmanaged array) - CORINFO_HELP_NEWARR_1_DIRECT, // helper for any one dimensional array creation - CORINFO_HELP_NEWARR_1_R2R_DIRECT, // wrapper for R2R direct call, which extracts method table from ArrayTypeDesc - CORINFO_HELP_NEWARR_1_OBJ, // optimized 1-D object arrays - CORINFO_HELP_NEWARR_1_VC, // optimized 1-D value class arrays - CORINFO_HELP_NEWARR_1_ALIGN8, // like VC, but aligns the array start - - CORINFO_HELP_STRCNS, // create a new string literal - CORINFO_HELP_STRCNS_CURRENT_MODULE, // create a new string literal from the current module (used by NGen code) - /* Object model */ - - CORINFO_HELP_INITCLASS, // Initialize class if not already initialized - CORINFO_HELP_INITINSTCLASS, // Initialize class for instantiated type - - // Use ICorClassInfo::getCastingHelper to determine - // the right helper to use - - CORINFO_HELP_ISINSTANCEOFINTERFACE, // Optimized helper for interfaces - CORINFO_HELP_ISINSTANCEOFARRAY, // Optimized helper for arrays - CORINFO_HELP_ISINSTANCEOFCLASS, // Optimized helper for classes - CORINFO_HELP_ISINSTANCEOFANY, // Slow helper for any type - - CORINFO_HELP_CHKCASTINTERFACE, - CORINFO_HELP_CHKCASTARRAY, - CORINFO_HELP_CHKCASTCLASS, - CORINFO_HELP_CHKCASTANY, - CORINFO_HELP_CHKCASTCLASS_SPECIAL, // Optimized helper for classes. Assumes that the trivial cases - // has been taken care of by the inlined check - - CORINFO_HELP_BOX, - CORINFO_HELP_BOX_NULLABLE, // special form of boxing for Nullable - CORINFO_HELP_UNBOX, - CORINFO_HELP_UNBOX_NULLABLE, // special form of unboxing for Nullable - CORINFO_HELP_GETREFANY, // Extract the byref from a TypedReference, checking that it is the expected type - - CORINFO_HELP_ARRADDR_ST, // assign to element of object array with type-checking - CORINFO_HELP_LDELEMA_REF, // does a precise type comparision and returns address - - /* Exceptions */ - - CORINFO_HELP_THROW, // Throw an exception object - CORINFO_HELP_RETHROW, // Rethrow the currently active exception - CORINFO_HELP_USER_BREAKPOINT, // For a user program to break to the debugger - CORINFO_HELP_RNGCHKFAIL, // array bounds check failed - CORINFO_HELP_OVERFLOW, // throw an overflow exception - CORINFO_HELP_THROWDIVZERO, // throw a divide by zero exception - CORINFO_HELP_THROWNULLREF, // throw a null reference exception - - CORINFO_HELP_INTERNALTHROW, // Support for really fast jit - CORINFO_HELP_VERIFICATION, // Throw a VerificationException - CORINFO_HELP_SEC_UNMGDCODE_EXCPT, // throw a security unmanaged code exception - CORINFO_HELP_FAIL_FAST, // Kill the process avoiding any exceptions or stack and data dependencies (use for GuardStack unsafe buffer checks) - - CORINFO_HELP_METHOD_ACCESS_EXCEPTION,//Throw an access exception due to a failed member/class access check. - CORINFO_HELP_FIELD_ACCESS_EXCEPTION, - CORINFO_HELP_CLASS_ACCESS_EXCEPTION, - - CORINFO_HELP_ENDCATCH, // call back into the EE at the end of a catch block - - /* Synchronization */ - - CORINFO_HELP_MON_ENTER, - CORINFO_HELP_MON_EXIT, - CORINFO_HELP_MON_ENTER_STATIC, - CORINFO_HELP_MON_EXIT_STATIC, - - CORINFO_HELP_GETCLASSFROMMETHODPARAM, // Given a generics method handle, returns a class handle - CORINFO_HELP_GETSYNCFROMCLASSHANDLE, // Given a generics class handle, returns the sync monitor - // in its ManagedClassObject - - /* Security callout support */ - - CORINFO_HELP_SECURITY_PROLOG, // Required if CORINFO_FLG_SECURITYCHECK is set, or CORINFO_FLG_NOSECURITYWRAP is not set - CORINFO_HELP_SECURITY_PROLOG_FRAMED, // Slow version of CORINFO_HELP_SECURITY_PROLOG. Used for instrumentation. - - CORINFO_HELP_METHOD_ACCESS_CHECK, // Callouts to runtime security access checks - CORINFO_HELP_FIELD_ACCESS_CHECK, - CORINFO_HELP_CLASS_ACCESS_CHECK, - - CORINFO_HELP_DELEGATE_SECURITY_CHECK, // Callout to delegate security transparency check - - /* Verification runtime callout support */ - - CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, // Do a Demand for UnmanagedCode permission at runtime - - /* GC support */ - - CORINFO_HELP_STOP_FOR_GC, // Call GC (force a GC) - CORINFO_HELP_POLL_GC, // Ask GC if it wants to collect - - CORINFO_HELP_STRESS_GC, // Force a GC, but then update the JITTED code to be a noop call - CORINFO_HELP_CHECK_OBJ, // confirm that ECX is a valid object pointer (debugging only) - - /* GC Write barrier support */ - - CORINFO_HELP_ASSIGN_REF, // universal helpers with F_CALL_CONV calling convention - CORINFO_HELP_CHECKED_ASSIGN_REF, - CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP, // Do the store, and ensure that the target was not in the heap. - - CORINFO_HELP_ASSIGN_BYREF, - CORINFO_HELP_ASSIGN_STRUCT, - - - /* Accessing fields */ - - // For COM object support (using COM get/set routines to update object) - // and EnC and cross-context support - CORINFO_HELP_GETFIELD8, - CORINFO_HELP_SETFIELD8, - CORINFO_HELP_GETFIELD16, - CORINFO_HELP_SETFIELD16, - CORINFO_HELP_GETFIELD32, - CORINFO_HELP_SETFIELD32, - CORINFO_HELP_GETFIELD64, - CORINFO_HELP_SETFIELD64, - CORINFO_HELP_GETFIELDOBJ, - CORINFO_HELP_SETFIELDOBJ, - CORINFO_HELP_GETFIELDSTRUCT, - CORINFO_HELP_SETFIELDSTRUCT, - CORINFO_HELP_GETFIELDFLOAT, - CORINFO_HELP_SETFIELDFLOAT, - CORINFO_HELP_GETFIELDDOUBLE, - CORINFO_HELP_SETFIELDDOUBLE, - - CORINFO_HELP_GETFIELDADDR, - - CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT, // Helper for context-static fields - CORINFO_HELP_GETSTATICFIELDADDR_TLS, // Helper for PE TLS fields - - // There are a variety of specialized helpers for accessing static fields. The JIT should use - // ICorClassInfo::getSharedStaticsOrCCtorHelper to determine which helper to use - - // Helpers for regular statics - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, - CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS, - // Helper to class initialize shared generic with dynamicclass, but not get static field address - CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS, - - // Helpers for thread statics - CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, - CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, - - /* Debugger */ - - CORINFO_HELP_DBG_IS_JUST_MY_CODE, // Check if this is "JustMyCode" and needs to be stepped through. - - /* Profiling enter/leave probe addresses */ - CORINFO_HELP_PROF_FCN_ENTER, // record the entry to a method (caller) - CORINFO_HELP_PROF_FCN_LEAVE, // record the completion of current method (caller) - CORINFO_HELP_PROF_FCN_TAILCALL, // record the completionof current method through tailcall (caller) - - /* Miscellaneous */ - - CORINFO_HELP_BBT_FCN_ENTER, // record the entry to a method for collecting Tuning data - - CORINFO_HELP_PINVOKE_CALLI, // Indirect pinvoke call - CORINFO_HELP_TAILCALL, // Perform a tail call - - CORINFO_HELP_GETCURRENTMANAGEDTHREADID, - - CORINFO_HELP_INIT_PINVOKE_FRAME, // initialize an inlined PInvoke Frame for the JIT-compiler - - CORINFO_HELP_MEMSET, // Init block of memory - CORINFO_HELP_MEMCPY, // Copy block of memory - - CORINFO_HELP_RUNTIMEHANDLE_METHOD, // determine a type/field/method handle at run-time - CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG,// determine a type/field/method handle at run-time, with IBC logging - CORINFO_HELP_RUNTIMEHANDLE_CLASS, // determine a type/field/method handle at run-time - CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG,// determine a type/field/method handle at run-time, with IBC logging - - CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time - CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time, the type may be null - CORINFO_HELP_METHODDESC_TO_STUBRUNTIMEMETHOD, // Convert from a MethodDesc (native structure pointer) to RuntimeMethodHandle at run-time - CORINFO_HELP_FIELDDESC_TO_STUBRUNTIMEFIELD, // Convert from a FieldDesc (native structure pointer) to RuntimeFieldHandle at run-time - CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time - CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time, handle might point to a null type - - CORINFO_HELP_ARE_TYPES_EQUIVALENT, // Check whether two TypeHandles (native structure pointers) are equivalent - - CORINFO_HELP_VIRTUAL_FUNC_PTR, // look up a virtual method at run-time - //CORINFO_HELP_VIRTUAL_FUNC_PTR_LOG, // look up a virtual method at run-time, with IBC logging - - // Not a real helpers. Instead of taking handle arguments, these helpers point to a small stub that loads the handle argument and calls the static helper. - CORINFO_HELP_READYTORUN_NEW, - CORINFO_HELP_READYTORUN_NEWARR_1, - CORINFO_HELP_READYTORUN_ISINSTANCEOF, - CORINFO_HELP_READYTORUN_CHKCAST, - CORINFO_HELP_READYTORUN_STATIC_BASE, - CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, - CORINFO_HELP_READYTORUN_GENERIC_HANDLE, - CORINFO_HELP_READYTORUN_DELEGATE_CTOR, - CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE, - - CORINFO_HELP_EE_PRESTUB, // Not real JIT helper. Used in native images. - - CORINFO_HELP_EE_PRECODE_FIXUP, // Not real JIT helper. Used for Precode fixup in native images. - CORINFO_HELP_EE_PINVOKE_FIXUP, // Not real JIT helper. Used for PInvoke target fixup in native images. - CORINFO_HELP_EE_VSD_FIXUP, // Not real JIT helper. Used for VSD cell fixup in native images. - CORINFO_HELP_EE_EXTERNAL_FIXUP, // Not real JIT helper. Used for to fixup external method thunks in native images. - CORINFO_HELP_EE_VTABLE_FIXUP, // Not real JIT helper. Used for inherited vtable slot fixup in native images. - - CORINFO_HELP_EE_REMOTING_THUNK, // Not real JIT helper. Used for remoting precode in native images. - - CORINFO_HELP_EE_PERSONALITY_ROUTINE,// Not real JIT helper. Used in native images. - CORINFO_HELP_EE_PERSONALITY_ROUTINE_FILTER_FUNCLET,// Not real JIT helper. Used in native images to detect filter funclets. - - // ASSIGN_REF_EAX - CHECKED_ASSIGN_REF_EBP: NOGC_WRITE_BARRIERS JIT helper calls - // - // For unchecked versions EDX is required to point into GC heap. - // - // NOTE: these helpers are only used for x86. - CORINFO_HELP_ASSIGN_REF_EAX, // EAX holds GC ptr, do a 'mov [EDX], EAX' and inform GC - CORINFO_HELP_ASSIGN_REF_EBX, // EBX holds GC ptr, do a 'mov [EDX], EBX' and inform GC - CORINFO_HELP_ASSIGN_REF_ECX, // ECX holds GC ptr, do a 'mov [EDX], ECX' and inform GC - CORINFO_HELP_ASSIGN_REF_ESI, // ESI holds GC ptr, do a 'mov [EDX], ESI' and inform GC - CORINFO_HELP_ASSIGN_REF_EDI, // EDI holds GC ptr, do a 'mov [EDX], EDI' and inform GC - CORINFO_HELP_ASSIGN_REF_EBP, // EBP holds GC ptr, do a 'mov [EDX], EBP' and inform GC - - CORINFO_HELP_CHECKED_ASSIGN_REF_EAX, // These are the same as ASSIGN_REF above ... - CORINFO_HELP_CHECKED_ASSIGN_REF_EBX, // ... but also check if EDX points into heap. - CORINFO_HELP_CHECKED_ASSIGN_REF_ECX, - CORINFO_HELP_CHECKED_ASSIGN_REF_ESI, - CORINFO_HELP_CHECKED_ASSIGN_REF_EDI, - CORINFO_HELP_CHECKED_ASSIGN_REF_EBP, - - CORINFO_HELP_LOOP_CLONE_CHOICE_ADDR, // Return the reference to a counter to decide to take cloned path in debug stress. - CORINFO_HELP_DEBUG_LOG_LOOP_CLONING, // Print a message that a loop cloning optimization has occurred in debug mode. - - CORINFO_HELP_THROW_ARGUMENTEXCEPTION, // throw ArgumentException - CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, // throw ArgumentOutOfRangeException - CORINFO_HELP_THROW_NOT_IMPLEMENTED, // throw NotImplementedException - CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, // throw PlatformNotSupportedException - CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED, // throw TypeNotSupportedException - - CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument - CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument - - CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, // Transition to cooperative mode in reverse P/Invoke prolog, frame is the first argument - CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, // Transition to preemptive mode in reverse P/Invoke epilog, frame is the first argument - - CORINFO_HELP_GVMLOOKUP_FOR_SLOT, // Resolve a generic virtual method target from this pointer and runtime method handle - - CORINFO_HELP_STACK_PROBE, // Probes each page of the allocated stack frame - - CORINFO_HELP_COUNT, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoImpl.Intrinsics.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoImpl.Intrinsics.cs deleted file mode 100644 index f42e74a9e91..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoImpl.Intrinsics.cs +++ /dev/null @@ -1,269 +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 System.Diagnostics; - -using Internal.TypeSystem; - -namespace Internal.JitInterface -{ - internal unsafe partial class CorInfoImpl - { - private struct IntrinsicKey - { - public string MethodName; - public string TypeNamespace; - public string TypeName; - - public bool Equals(IntrinsicKey other) - { - return (MethodName == other.MethodName) && - (TypeNamespace == other.TypeNamespace) && - (TypeName == other.TypeName); - } - - public override int GetHashCode() - { - return MethodName.GetHashCode() + - ((TypeNamespace != null) ? TypeNamespace.GetHashCode() : 0) + - ((TypeName != null) ? TypeName.GetHashCode() : 0); - } - } - - private class IntrinsicEntry - { - public IntrinsicKey Key; - public CorInfoIntrinsics Id; - } - - private class IntrinsicHashtable : LockFreeReaderHashtable - { - protected override bool CompareKeyToValue(IntrinsicKey key, IntrinsicEntry value) - { - return key.Equals(value.Key); - } - protected override bool CompareValueToValue(IntrinsicEntry value1, IntrinsicEntry value2) - { - return value1.Key.Equals(value2.Key); - } - protected override IntrinsicEntry CreateValueFromKey(IntrinsicKey key) - { - Debug.Fail("CreateValueFromKey not supported"); - return null; - } - protected override int GetKeyHashCode(IntrinsicKey key) - { - return key.GetHashCode(); - } - protected override int GetValueHashCode(IntrinsicEntry value) - { - return value.Key.GetHashCode(); - } - - public void Add(CorInfoIntrinsics id, string methodName, string typeNamespace, string typeName) - { - var entry = new IntrinsicEntry(); - entry.Id = id; - entry.Key.MethodName = methodName; - entry.Key.TypeNamespace = typeNamespace; - entry.Key.TypeName = typeName; - AddOrGetExisting(entry); - } - } - - static IntrinsicHashtable InitializeIntrinsicHashtable() - { - IntrinsicHashtable table = new IntrinsicHashtable(); - - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sin, "Sin", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sin, "Sin", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cos, "Cos", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cos, "Cos", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cbrt, "Cbrt", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cbrt, "Cbrt", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sqrt, "Sqrt", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sqrt, "Sqrt", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Abs, "Abs", "System", "Math"); - // No System.MathF entry for CORINFO_INTRTINSIC_Abs as System.Math exposes and handles both float and double - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Round, "Round", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Round, "Round", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cosh, "Cosh", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cosh, "Cosh", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sinh, "Sinh", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sinh, "Sinh", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tan, "Tan", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tan, "Tan", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tanh, "Tanh", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tanh, "Tanh", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asin, "Asin", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asin, "Asin", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asinh, "Asinh", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asinh, "Asinh", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acos, "Acos", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acos, "Acos", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acosh, "Acosh", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acosh, "Acosh", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan, "Atan", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan, "Atan", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan2, "Atan2", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan2, "Atan2", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atanh, "Atanh", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atanh, "Atanh", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Log10, "Log10", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Log10, "Log10", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Pow, "Pow", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Pow, "Pow", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Exp, "Exp", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Exp, "Exp", "System", "MathF"); -#if !READYTORUN - // These are normally handled via the SSE4.1 instructions ROUNDSS/ROUNDSD. - // However, we don't know the ISAs the target machine supports so we should - // fallback to the method call implementation instead. - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Ceiling, "Ceiling", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Ceiling, "Ceiling", "System", "MathF"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Floor, "Floor", "System", "Math"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Floor, "Floor", "System", "MathF"); -#endif - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetChar, null, null, null); // unused - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_GetDimLength, "GetLength", "System", "Array"); // not handled - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Get, "Get", null, null); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Address, "Address", null, null); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Set, "Set", null, null); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StringGetChar, "get_Chars", "System", "String"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StringLength, "get_Length", "System", "String"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InitializeArray, "InitializeArray", "System.Runtime.CompilerServices", "RuntimeHelpers"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetTypeFromHandle, "GetTypeFromHandle", "System", "Type"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_RTH_GetValueInternal, "GetValueInternal", "System", "RuntimeTypeHandle"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_TypeEQ, "op_Equality", "System", "Type"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_TypeNEQ, "op_Inequality", "System", "Type"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Object_GetType, "GetType", "System", "Object"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetStubContext, "GetStubContext", "System.StubHelpers", "StubHelpers"); // interop-specific - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr, "GetStubContextAddr", "System.StubHelpers", "StubHelpers"); // interop-specific - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetNDirectTarget, "GetNDirectTarget", "System.StubHelpers", "StubHelpers"); // interop-specific - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedAdd32, "Add", System.Threading", "Interlocked"); // unused - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedAdd64, "Add", System.Threading", "Interlocked"); // unused - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd32, "ExchangeAdd", "System.Threading", "Interlocked"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd64, "ExchangeAdd", "System.Threading", "Interlocked"); // ambiguous match - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg32, "Exchange", "System.Threading", "Interlocked"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg64, "Exchange", "System.Threading", "Interlocked"); // ambiguous match - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg32, "CompareExchange", "System.Threading", "Interlocked"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg64, "CompareExchange", "System.Threading", "Interlocked"); // ambiguous match - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_MemoryBarrier, "MemoryBarrier", "System.Threading", "Interlocked"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetCurrentManagedThread, "GetCurrentThreadNative", "System", "Thread"); // not in .NET Core - // 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"); - 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 == 54); - - return table; - } - - static IntrinsicHashtable s_IntrinsicHashtable = InitializeIntrinsicHashtable(); - - private CorInfoIntrinsics getIntrinsicID(CORINFO_METHOD_STRUCT_* ftn, byte* pMustExpand) - { - var method = HandleToObject(ftn); - return getIntrinsicID(method, pMustExpand); - } - - private CorInfoIntrinsics getIntrinsicID(MethodDesc method, byte* pMustExpand) - { - if (pMustExpand != null) - *pMustExpand = 0; - - Debug.Assert(method.IsIntrinsic); - - IntrinsicKey key = new IntrinsicKey(); - key.MethodName = method.Name; - - var metadataType = method.OwningType as MetadataType; - if (metadataType != null) - { - key.TypeNamespace = metadataType.Namespace; - key.TypeName = metadataType.Name; - } - - IntrinsicEntry entry; - if (!s_IntrinsicHashtable.TryGetValue(key, out entry)) - return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; - - // Some intrinsics need further disambiguation - CorInfoIntrinsics id = entry.Id; - switch (id) - { - case CorInfoIntrinsics.CORINFO_INTRINSIC_Abs: - { - // RyuJIT handles floating point overloads only - var returnTypeCategory = method.Signature.ReturnType.Category; - if (returnTypeCategory != TypeFlags.Double && returnTypeCategory != TypeFlags.Single) - return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; - } - break; - case CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Get: - case CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Address: - case CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Set: - if (!method.OwningType.IsArray) - return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; - break; - - case CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd32: - case CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg32: - case CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg32: - { - // RyuJIT handles int32 and int64 overloads only - var returnTypeCategory = method.Signature.ReturnType.Category; - if (returnTypeCategory != TypeFlags.Int32 && returnTypeCategory != TypeFlags.Int64 && returnTypeCategory != TypeFlags.IntPtr) - return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; - - // int64 overloads have different ids - if (returnTypeCategory == TypeFlags.Int64) - { - Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd32 + 1 == (int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd64); - Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg32 + 1 == (int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXchg64); - Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg32 + 1 == (int)CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg64); - id = (CorInfoIntrinsics)((int)id + 1); - } - } - break; - - case CorInfoIntrinsics.CORINFO_INTRINSIC_RTH_GetValueInternal: -#if !READYTORUN - case CorInfoIntrinsics.CORINFO_INTRINSIC_InitializeArray: -#endif - case CorInfoIntrinsics.CORINFO_INTRINSIC_ByReference_Ctor: - case CorInfoIntrinsics.CORINFO_INTRINSIC_ByReference_Value: - if (pMustExpand != null) - *pMustExpand = 1; - break; - - case CorInfoIntrinsics.CORINFO_INTRINSIC_GetRawHandle: - if (pMustExpand != null) - *pMustExpand = 1; - break; - - case CorInfoIntrinsics.CORINFO_INTRINSIC_Span_GetItem: - case CorInfoIntrinsics.CORINFO_INTRINSIC_ReadOnlySpan_GetItem: - { - // RyuJIT handles integer overload only - var argumentTypeCategory = method.Signature[0].Category; - if (argumentTypeCategory != TypeFlags.Int32) - return CorInfoIntrinsics.CORINFO_INTRINSIC_Illegal; - } - break; - - default: - break; - } - - return id; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoImpl.cs deleted file mode 100644 index 86fdeea8743..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoImpl.cs +++ /dev/null @@ -1,3074 +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 System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Runtime.CompilerServices; -using System.Runtime.ExceptionServices; -using System.Runtime.InteropServices; - -#if SUPPORT_JIT -using Internal.Runtime.CompilerServices; -#endif - -using Internal.IL; -using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; - -using ILCompiler; -using ILCompiler.DependencyAnalysis; - -#if READYTORUN -using System.Reflection.Metadata.Ecma335; -using ILCompiler.DependencyAnalysis.ReadyToRun; -#endif - -namespace Internal.JitInterface -{ - internal unsafe sealed partial class CorInfoImpl - { - // - // Global initialization and state - // - private enum ImageFileMachine - { - I386 = 0x014c, - IA64 = 0x0200, - AMD64 = 0x8664, - ARM = 0x01c4, - } - - private const string JitLibrary = "clrjitilc"; - -#if SUPPORT_JIT - private const string JitSupportLibrary = "*"; -#else - private const string JitSupportLibrary = "jitinterface"; -#endif - - private IntPtr _jit; - - private IntPtr _unmanagedCallbacks; // array of pointers to JIT-EE interface callbacks - private Object _keepAlive; // Keeps delegates for the callbacks alive - - private ExceptionDispatchInfo _lastException; - - private static bool s_jitRegistered = RegisterJITModule(); - - [DllImport(JitLibrary)] - private extern static IntPtr PAL_RegisterModule([MarshalAs(UnmanagedType.LPUTF8Str)] string moduleName); - - [DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)] // stdcall in CoreCLR! - private extern static IntPtr jitStartup(IntPtr host); - - [DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)] - private extern static IntPtr getJit(); - - [DllImport(JitSupportLibrary)] - private extern static IntPtr GetJitHost(IntPtr configProvider); - - // - // Per-method initialization and state - // - private static CorInfoImpl GetThis(IntPtr thisHandle) - { - CorInfoImpl _this = Unsafe.Read((void*)thisHandle); - Debug.Assert(_this is CorInfoImpl); - return _this; - } - - [DllImport(JitSupportLibrary)] - private extern static CorJitResult JitCompileMethod(out IntPtr exception, - IntPtr jit, IntPtr thisHandle, IntPtr callbacks, - ref CORINFO_METHOD_INFO info, uint flags, out IntPtr nativeEntry, out uint codeSize); - - [DllImport(JitSupportLibrary)] - private extern static uint GetMaxIntrinsicSIMDVectorLength(IntPtr jit, CORJIT_FLAGS* flags); - - [DllImport(JitSupportLibrary)] - private extern static IntPtr AllocException([MarshalAs(UnmanagedType.LPWStr)]string message, int messageLength); - - private IntPtr AllocException(Exception ex) - { - _lastException = ExceptionDispatchInfo.Capture(ex); - - string exString = ex.ToString(); - IntPtr nativeException = AllocException(exString, exString.Length); - if (_nativeExceptions == null) - { - _nativeExceptions = new List(); - } - _nativeExceptions.Add(nativeException); - return nativeException; - } - - [DllImport(JitSupportLibrary)] - private extern static void FreeException(IntPtr obj); - - [DllImport(JitSupportLibrary)] - private extern static char* GetExceptionMessage(IntPtr obj); - - private JitConfigProvider _jitConfig; - - private readonly UnboxingMethodDescFactory _unboxingThunkFactory; - - private static bool RegisterJITModule() - { - if ((Environment.OSVersion.Platform == PlatformID.Unix) || (Environment.OSVersion.Platform == PlatformID.MacOSX)) - { - return PAL_RegisterModule("libclrjitilc.so") != (IntPtr)1; - } - else - { - return true; - } - } - - private IntPtr JitLibraryResolver(string libraryName, System.Reflection.Assembly assembly, DllImportSearchPath? searchPath) - { - IntPtr libHandle = IntPtr.Zero; - if (libraryName == JitLibrary) - { - libHandle = NativeLibrary.Load(_jitConfig.JitPath, assembly, searchPath); - } - return libHandle; - } - - public CorInfoImpl(JitConfigProvider jitConfig) - { - // - // Global initialization - // - _jitConfig = jitConfig; - if (!s_jitRegistered) - { - throw new IOException("Failed to register JIT"); - } - - if (_jitConfig.JitPath != null) - { - NativeLibrary.SetDllImportResolver(typeof(CorInfoImpl).Assembly, JitLibraryResolver); - } - - jitStartup(GetJitHost(_jitConfig.UnmanagedInstance)); - - _jit = getJit(); - if (_jit == IntPtr.Zero) - { - throw new IOException("Failed to initialize JIT"); - } - - _unmanagedCallbacks = GetUnmanagedCallbacks(out _keepAlive); - - _unboxingThunkFactory = new UnboxingMethodDescFactory(); - } - - public TextWriter Log - { - get - { - return _compilation.Logger.Writer; - } - } - - private CORINFO_MODULE_STRUCT_* _methodScope; // Needed to resolve CORINFO_EH_CLAUSE tokens - - private bool _isFallbackBodyCompilation; // True if we're compiling a fallback method body after compiling the real body failed - - private void CompileMethodInternal(IMethodNode methodCodeNodeNeedingCode, MethodIL methodIL = null) - { - _isFallbackBodyCompilation = methodIL != null; - - CORINFO_METHOD_INFO methodInfo; - methodIL = Get_CORINFO_METHOD_INFO(MethodBeingCompiled, methodIL, &methodInfo); - - // This is e.g. an "extern" method in C# without a DllImport or InternalCall. - if (methodIL == null) - { - ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramSpecific, MethodBeingCompiled); - } - - _methodScope = methodInfo.scope; - -#if !READYTORUN - SetDebugInformation(methodCodeNodeNeedingCode, methodIL); -#endif - - CorInfoImpl _this = this; - - IntPtr exception; - IntPtr nativeEntry; - uint codeSize; - var result = JitCompileMethod(out exception, - _jit, (IntPtr)Unsafe.AsPointer(ref _this), _unmanagedCallbacks, - ref methodInfo, (uint)CorJitFlag.CORJIT_FLAG_CALL_GETJITFLAGS, out nativeEntry, out codeSize); - if (exception != IntPtr.Zero) - { - if (_lastException != null) - { - // If we captured a managed exception, rethrow that. - // TODO: might not actually be the real reason. It could be e.g. a JIT failure/bad IL that followed - // an inlining attempt with a type system problem in it... -#if SUPPORT_JIT - _lastException.Throw(); -#else - if (_lastException.SourceException is TypeSystemException) - { - // Type system exceptions can be turned into code that throws the exception at runtime. - _lastException.Throw(); - } -#if READYTORUN - else if (_lastException.SourceException is RequiresRuntimeJitException) - { - // Runtime JIT requirement is not a cause for failure, we just mustn't JIT a particular method - _lastException.Throw(); - } -#endif - else - { - // This is just a bug somewhere. - throw new CodeGenerationFailedException(_methodCodeNode.Method, _lastException.SourceException); - } -#endif - } - - // This is a failure we don't know much about. - char* szMessage = GetExceptionMessage(exception); - string message = szMessage != null ? new string(szMessage) : "JIT Exception"; - throw new Exception(message); - } - if (result == CorJitResult.CORJIT_BADCODE) - { - ThrowHelper.ThrowInvalidProgramException(); - } - if (result != CorJitResult.CORJIT_OK) - { -#if SUPPORT_JIT - // FailFast? - throw new Exception("JIT failed"); -#else - throw new CodeGenerationFailedException(_methodCodeNode.Method); -#endif - } - - PublishCode(); - } - - private void PublishCode() - { - var relocs = _relocs.ToArray(); - Array.Sort(relocs, (x, y) => (x.Offset - y.Offset)); - - int alignment = _jitConfig.HasFlag(CorJitFlag.CORJIT_FLAG_SIZE_OPT) ? - _compilation.NodeFactory.Target.MinimumFunctionAlignment : - _compilation.NodeFactory.Target.OptimumFunctionAlignment; - - var objectData = new ObjectNode.ObjectData(_code, - relocs, - alignment, - new ISymbolDefinitionNode[] { _methodCodeNode }); - ObjectNode.ObjectData ehInfo = _ehClauses != null ? EncodeEHInfo() : null; - DebugEHClauseInfo[] debugEHClauseInfos = null; - if (_ehClauses != null) - { - debugEHClauseInfos = new DebugEHClauseInfo[_ehClauses.Length]; - for (int i = 0; i < _ehClauses.Length; i++) - { - var clause = _ehClauses[i]; - debugEHClauseInfos[i] = new DebugEHClauseInfo(clause.TryOffset, clause.TryLength, - clause.HandlerOffset, clause.HandlerLength); - } - } - - _methodCodeNode.SetCode(objectData -#if !SUPPORT_JIT && !READYTORUN - , isFoldable: (_compilation._compilationOptions & RyuJitCompilationOptions.MethodBodyFolding) != 0 -#endif - ); - - _methodCodeNode.InitializeFrameInfos(_frameInfos); - _methodCodeNode.InitializeDebugEHClauseInfos(debugEHClauseInfos); - _methodCodeNode.InitializeGCInfo(_gcInfo); - _methodCodeNode.InitializeEHInfo(ehInfo); - - _methodCodeNode.InitializeDebugLocInfos(_debugLocInfos); - _methodCodeNode.InitializeDebugVarInfos(_debugVarInfos); - PublishProfileData(); - } - - partial void PublishProfileData(); - - private MethodDesc MethodBeingCompiled - { - get - { - return _methodCodeNode.Method; - } - } - - private int PointerSize - { - get - { - return _compilation.TypeSystemContext.Target.PointerSize; - } - } - - private Dictionary _pins = new Dictionary(); - - private IntPtr GetPin(Object obj) - { - GCHandle handle; - if (!_pins.TryGetValue(obj, out handle)) - { - handle = GCHandle.Alloc(obj, GCHandleType.Pinned); - _pins.Add(obj, handle); - } - return handle.AddrOfPinnedObject(); - } - - private List _nativeExceptions; - - private void CompileMethodCleanup() - { - foreach (var pin in _pins) - pin.Value.Free(); - _pins.Clear(); - - if (_nativeExceptions != null) - { - foreach (IntPtr ex in _nativeExceptions) - FreeException(ex); - _nativeExceptions = null; - } - - _methodCodeNode = null; - - _code = null; - _coldCode = null; - - _roData = null; - _roDataBlob = null; - - _relocs = new ArrayBuilder(); - - _numFrameInfos = 0; - _usedFrameInfos = 0; - _frameInfos = null; - - _gcInfo = null; - _ehClauses = null; - -#if !READYTORUN - _sequencePoints = null; - _variableToTypeDesc = null; -#endif - _debugLocInfos = null; - _debugVarInfos = null; - _lastException = null; - -#if READYTORUN - _profileDataNode = null; -#endif - } - - private Dictionary _objectToHandle = new Dictionary(); - private List _handleToObject = new List(); - - private const int handleMultipler = 8; - private const int handleBase = 0x420000; - - private IntPtr ObjectToHandle(Object obj) - { - IntPtr handle; - if (!_objectToHandle.TryGetValue(obj, out handle)) - { - handle = (IntPtr)(handleMultipler * _handleToObject.Count + handleBase); - _handleToObject.Add(obj); - _objectToHandle.Add(obj, handle); - } - return handle; - } - - private Object HandleToObject(IntPtr handle) - { - int index = ((int)handle - handleBase) / handleMultipler; - return _handleToObject[index]; - } - - private MethodDesc HandleToObject(CORINFO_METHOD_STRUCT_* method) { return (MethodDesc)HandleToObject((IntPtr)method); } - private CORINFO_METHOD_STRUCT_* ObjectToHandle(MethodDesc method) { return (CORINFO_METHOD_STRUCT_*)ObjectToHandle((Object)method); } - - private TypeDesc HandleToObject(CORINFO_CLASS_STRUCT_* type) { return (TypeDesc)HandleToObject((IntPtr)type); } - private CORINFO_CLASS_STRUCT_* ObjectToHandle(TypeDesc type) { return (CORINFO_CLASS_STRUCT_*)ObjectToHandle((Object)type); } - - private FieldDesc HandleToObject(CORINFO_FIELD_STRUCT_* field) { return (FieldDesc)HandleToObject((IntPtr)field); } - private CORINFO_FIELD_STRUCT_* ObjectToHandle(FieldDesc field) { return (CORINFO_FIELD_STRUCT_*)ObjectToHandle((Object)field); } - - private MethodIL Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, CORINFO_METHOD_INFO* methodInfo) - { - // MethodIL can be provided externally for the case of a method whose IL was replaced because we couldn't compile it. - if (methodIL == null) - methodIL = _compilation.GetMethodIL(method); - - if (methodIL == null) - { - *methodInfo = default(CORINFO_METHOD_INFO); - return null; - } - - methodInfo->ftn = ObjectToHandle(method); - methodInfo->scope = (CORINFO_MODULE_STRUCT_*)ObjectToHandle(methodIL); - var ilCode = methodIL.GetILBytes(); - methodInfo->ILCode = (byte*)GetPin(ilCode); - methodInfo->ILCodeSize = (uint)ilCode.Length; - methodInfo->maxStack = (uint)methodIL.MaxStack; - methodInfo->EHcount = (uint)methodIL.GetExceptionRegions().Length; - methodInfo->options = methodIL.IsInitLocals ? CorInfoOptions.CORINFO_OPT_INIT_LOCALS : (CorInfoOptions)0; - - if (method.AcquiresInstMethodTableFromThis()) - { - methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_FROM_THIS; - } - else if (method.RequiresInstMethodDescArg()) - { - methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_FROM_METHODDESC; - } - else if (method.RequiresInstMethodTableArg()) - { - methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_FROM_METHODTABLE; - } - - methodInfo->regionKind = CorInfoRegionKind.CORINFO_REGION_NONE; - Get_CORINFO_SIG_INFO(method, &methodInfo->args); - Get_CORINFO_SIG_INFO(methodIL.GetLocals(), &methodInfo->locals); - - return methodIL; - } - - private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool suppressHiddenArgument = false) - { - Get_CORINFO_SIG_INFO(method.Signature, sig); - - // Does the method have a hidden parameter? - bool hasHiddenParameter = !suppressHiddenArgument && method.RequiresInstArg(); - - if (method.IsIntrinsic) - { - // Some intrinsics will beg to differ about the hasHiddenParameter decision -#if !READYTORUN - if (_compilation.TypeSystemContext.IsSpecialUnboxingThunkTargetMethod(method)) - hasHiddenParameter = false; -#endif - - if (method.IsArrayAddressMethod()) - hasHiddenParameter = true; - - // We only populate sigInst for intrinsic methods because most of the time, - // JIT doesn't care what the instantiation is and this is expensive. - Instantiation owningTypeInst = method.OwningType.Instantiation; - sig->sigInst.classInstCount = (uint)owningTypeInst.Length; - if (owningTypeInst.Length > 0) - { - var classInst = new IntPtr[owningTypeInst.Length]; - for (int i = 0; i < owningTypeInst.Length; i++) - classInst[i] = (IntPtr)ObjectToHandle(owningTypeInst[i]); - sig->sigInst.classInst = (CORINFO_CLASS_STRUCT_**)GetPin(classInst); - } - } - - if (hasHiddenParameter) - { - sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_PARAMTYPE; - } - } - - private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* sig) - { - sig->callConv = (CorInfoCallConv)(signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask); - - // Varargs are not supported in .NET Core - if (sig->callConv == CorInfoCallConv.CORINFO_CALLCONV_VARARG) - ThrowHelper.ThrowBadImageFormatException(); - - if (!signature.IsStatic) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_HASTHIS; - - TypeDesc returnType = signature.ReturnType; - - CorInfoType corInfoRetType = asCorInfoType(signature.ReturnType, &sig->retTypeClass); - sig->_retType = (byte)corInfoRetType; - sig->retTypeSigClass = sig->retTypeClass; // The difference between the two is not relevant for ILCompiler - - sig->flags = 0; // used by IL stubs code - - sig->numArgs = (ushort)signature.Length; - - sig->args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index - - sig->sigInst.classInst = null; // Not used by the JIT - sig->sigInst.classInstCount = 0; // Not used by the JIT - sig->sigInst.methInst = null; // Not used by the JIT - sig->sigInst.methInstCount = (uint)signature.GenericParameterCount; - - sig->pSig = (byte*)ObjectToHandle(signature); - sig->cbSig = 0; // Not used by the JIT - sig->scope = null; // Not used by the JIT - sig->token = 0; // Not used by the JIT - } - - private void Get_CORINFO_SIG_INFO(LocalVariableDefinition[] locals, CORINFO_SIG_INFO* sig) - { - sig->callConv = CorInfoCallConv.CORINFO_CALLCONV_DEFAULT; - sig->_retType = (byte)CorInfoType.CORINFO_TYPE_VOID; - sig->retTypeClass = null; - sig->retTypeSigClass = null; - sig->flags = (byte)CorInfoSigInfoFlags.CORINFO_SIGFLAG_IS_LOCAL_SIG; - - sig->numArgs = (ushort)locals.Length; - - sig->sigInst.classInst = null; - sig->sigInst.classInstCount = 0; - sig->sigInst.methInst = null; - sig->sigInst.methInstCount = 0; - - sig->args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index - - sig->pSig = (byte*)ObjectToHandle(locals); - sig->cbSig = 0; // Not used by the JIT - sig->scope = null; // Not used by the JIT - sig->token = 0; // Not used by the JIT - } - - private CorInfoType asCorInfoType(TypeDesc type) - { - if (type.IsEnum) - { - type = type.UnderlyingType; - } - - if (type.IsPrimitive) - { - Debug.Assert((CorInfoType)TypeFlags.Void == CorInfoType.CORINFO_TYPE_VOID); - Debug.Assert((CorInfoType)TypeFlags.Double == CorInfoType.CORINFO_TYPE_DOUBLE); - - return (CorInfoType)type.Category; - } - - if (type.IsPointer || type.IsFunctionPointer) - { - return CorInfoType.CORINFO_TYPE_PTR; - } - - if (type.IsByRef) - { - return CorInfoType.CORINFO_TYPE_BYREF; - } - - if (type.IsValueType) - { - return CorInfoType.CORINFO_TYPE_VALUECLASS; - } - - return CorInfoType.CORINFO_TYPE_CLASS; - } - - private CorInfoType asCorInfoType(TypeDesc type, CORINFO_CLASS_STRUCT_** structType) - { - var corInfoType = asCorInfoType(type); - *structType = ((corInfoType == CorInfoType.CORINFO_TYPE_CLASS) || - (corInfoType == CorInfoType.CORINFO_TYPE_VALUECLASS) || - (corInfoType == CorInfoType.CORINFO_TYPE_BYREF)) ? ObjectToHandle(type) : null; - return corInfoType; - } - - private CORINFO_CONTEXT_STRUCT* contextFromMethod(MethodDesc method) - { - return (CORINFO_CONTEXT_STRUCT*)(((ulong)ObjectToHandle(method)) | (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_METHOD); - } - - private CORINFO_CONTEXT_STRUCT* contextFromType(TypeDesc type) - { - return (CORINFO_CONTEXT_STRUCT*)(((ulong)ObjectToHandle(type)) | (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_CLASS); - } - - private MethodDesc methodFromContext(CORINFO_CONTEXT_STRUCT* contextStruct) - { - if (((ulong)contextStruct & (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK) == (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_CLASS) - { - return null; - } - else - { - return HandleToObject((CORINFO_METHOD_STRUCT_*)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK)); - } - } - - private TypeDesc typeFromContext(CORINFO_CONTEXT_STRUCT* contextStruct) - { - if (((ulong)contextStruct & (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK) == (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_CLASS) - { - return HandleToObject((CORINFO_CLASS_STRUCT_*)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK)); - } - else - { - return methodFromContext(contextStruct).OwningType; - } - } - - private TypeSystemEntity entityFromContext(CORINFO_CONTEXT_STRUCT* contextStruct) - { - return (TypeSystemEntity)HandleToObject((IntPtr)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK)); - } - - private uint getMethodAttribsInternal(MethodDesc method) - { - CorInfoFlag result = 0; - - // CORINFO_FLG_PROTECTED - verification only - - if (method.Signature.IsStatic) - result |= CorInfoFlag.CORINFO_FLG_STATIC; - - if (method.IsSynchronized) - result |= CorInfoFlag.CORINFO_FLG_SYNCH; - if (method.IsIntrinsic) - result |= CorInfoFlag.CORINFO_FLG_INTRINSIC | CorInfoFlag.CORINFO_FLG_JIT_INTRINSIC; - if (method.IsVirtual) - result |= CorInfoFlag.CORINFO_FLG_VIRTUAL; - if (method.IsAbstract) - result |= CorInfoFlag.CORINFO_FLG_ABSTRACT; - if (method.IsConstructor || method.IsStaticConstructor) - result |= CorInfoFlag.CORINFO_FLG_CONSTRUCTOR; - - // - // See if we need to embed a .cctor call at the head of the - // method body. - // - - // method or class might have the final bit - if (_compilation.IsEffectivelySealed(method)) - result |= CorInfoFlag.CORINFO_FLG_FINAL; - - if (method.IsSharedByGenericInstantiations) - result |= CorInfoFlag.CORINFO_FLG_SHAREDINST; - - if (method.IsPInvoke) - { - result |= CorInfoFlag.CORINFO_FLG_PINVOKE; - - if (method.IsRawPInvoke()) - { - result |= CorInfoFlag.CORINFO_FLG_FORCEINLINE; - } - } - -#if READYTORUN - if (method.RequireSecObject) - { - result |= CorInfoFlag.CORINFO_FLG_DONT_INLINE_CALLER; - } -#endif - - if (method.IsAggressiveOptimization) - { - result |= CorInfoFlag.CORINFO_FLG_AGGRESSIVE_OPT; - } - - // TODO: Cache inlining hits - // Check for an inlining directive. - - if (method.IsNoInlining) - { - /* Function marked as not inlineable */ - result |= CorInfoFlag.CORINFO_FLG_DONT_INLINE; - } - else if (method.IsAggressiveInlining) - { - result |= CorInfoFlag.CORINFO_FLG_FORCEINLINE; - } - - if (method.OwningType.IsDelegate && method.Name == "Invoke") - { - // This is now used to emit efficient invoke code for any delegate invoke, - // including multicast. - result |= CorInfoFlag.CORINFO_FLG_DELEGATE_INVOKE; - - // RyuJIT special cases this method; it would assert if it's not final - // and we might not have set the bit in the code above. - result |= CorInfoFlag.CORINFO_FLG_FINAL; - } - -#if READYTORUN - // Check for SIMD intrinsics - DefType owningDefType = method.OwningType as DefType; - if (owningDefType != null && VectorFieldLayoutAlgorithm.IsVectorOfTType(owningDefType)) - { - throw new RequiresRuntimeJitException("This function is using SIMD intrinsics, their size is machine specific"); - } -#endif - - // Check for hardware intrinsics - if (HardwareIntrinsicHelpers.IsHardwareIntrinsic(method)) - { -#if READYTORUN - if (!isMethodDefinedInCoreLib()) - { - throw new RequiresRuntimeJitException("This function is not defined in CoreLib and it is using hardware intrinsics."); - } -#endif -#if !READYTORUN - // Do not report the get_IsSupported method as an intrinsic - RyuJIT would expand it to - // a constant depending on the code generation flags passed to it, but we would like to - // do a dynamic check instead. - if (!HardwareIntrinsicHelpers.IsIsSupportedMethod(method) - || HardwareIntrinsicHelpers.IsKnownSupportedIntrinsicAtCompileTime(method)) -#endif - { - result |= CorInfoFlag.CORINFO_FLG_JIT_INTRINSIC; - } - } - - result |= CorInfoFlag.CORINFO_FLG_NOSECURITYWRAP; - - return (uint)result; - } - - private void setMethodAttribs(CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) - { - // TODO: Inlining - } - - private void getMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) - { - MethodDesc method = HandleToObject(ftn); - - // There might be a more concrete parent type specified - this can happen when inlining. - if (memberParent != null) - { - TypeDesc type = HandleToObject(memberParent); - - // Typically, the owning type of the method is a canonical type and the member parent - // supplied by RyuJIT is a concrete instantiation. - if (type != method.OwningType) - { - Debug.Assert(type.HasSameTypeDefinition(method.OwningType)); - Instantiation methodInst = method.Instantiation; - method = _compilation.TypeSystemContext.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)type); - if (methodInst.Length > 0) - { - method = method.MakeInstantiatedMethod(methodInst); - } - } - } - - Get_CORINFO_SIG_INFO(method, sig); - } - - private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info) - { - MethodIL methodIL = Get_CORINFO_METHOD_INFO(HandleToObject(ftn), null, info); - return methodIL != null; - } - - private CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint pRestrictions) - { - MethodDesc callerMethod = HandleToObject(callerHnd); - MethodDesc calleeMethod = HandleToObject(calleeHnd); - - if (_compilation.CanInline(callerMethod, calleeMethod)) - { - // No restrictions on inlining - return CorInfoInline.INLINE_PASS; - } - else - { - // Call may not be inlined - return CorInfoInline.INLINE_NEVER; - } - } - - private void reportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) - { - } - - private void reportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason) - { - } - - private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) - { - var methodIL = _compilation.GetMethodIL(HandleToObject(ftn)); - - var ehRegion = methodIL.GetExceptionRegions()[EHnumber]; - - clause.Flags = (CORINFO_EH_CLAUSE_FLAGS)ehRegion.Kind; - clause.TryOffset = (uint)ehRegion.TryOffset; - clause.TryLength = (uint)ehRegion.TryLength; - clause.HandlerOffset = (uint)ehRegion.HandlerOffset; - clause.HandlerLength = (uint)ehRegion.HandlerLength; - clause.ClassTokenOrOffset = (uint)((ehRegion.Kind == ILExceptionRegionKind.Filter) ? ehRegion.FilterOffset : ehRegion.ClassToken); - } - - private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) - { - var m = HandleToObject(method); - return ObjectToHandle(m.OwningType); - } - - private CORINFO_MODULE_STRUCT_* getMethodModule(CORINFO_METHOD_STRUCT_* method) - { - MethodDesc m = HandleToObject(method); - if (m is UnboxingMethodDesc unboxingMethodDesc) - { - m = unboxingMethodDesc.Target; - } - - MethodIL methodIL = _compilation.GetMethodIL(m); - if (methodIL == null) - { - return null; - } - return (CORINFO_MODULE_STRUCT_*)ObjectToHandle(methodIL); - } - - private CORINFO_METHOD_STRUCT_* resolveVirtualMethod(CORINFO_METHOD_STRUCT_* baseMethod, CORINFO_CLASS_STRUCT_* derivedClass, CORINFO_CONTEXT_STRUCT* ownerType) - { - TypeDesc implType = HandleToObject(derivedClass); - - // __Canon cannot be devirtualized - if (implType.IsCanonicalDefinitionType(CanonicalFormKind.Any)) - { - return null; - } - - MethodDesc decl = HandleToObject(baseMethod); - Debug.Assert(!decl.HasInstantiation); - - if (ownerType != null) - { - TypeDesc ownerTypeDesc = typeFromContext(ownerType); - if (decl.OwningType != ownerTypeDesc) - { - Debug.Assert(ownerTypeDesc is InstantiatedType); - decl = _compilation.TypeSystemContext.GetMethodForInstantiatedType(decl.GetTypicalMethodDefinition(), (InstantiatedType)ownerTypeDesc); - } - } - - MethodDesc impl = _compilation.ResolveVirtualMethod(decl, implType); - - if (impl != null) - { - if (impl.OwningType.IsValueType) - { - impl = _unboxingThunkFactory.GetUnboxingMethod(impl); - } - - return ObjectToHandle(impl); - } - - return null; - } - - private CORINFO_METHOD_STRUCT_* getUnboxedEntry(CORINFO_METHOD_STRUCT_* ftn, byte* requiresInstMethodTableArg) - { - MethodDesc result = null; - bool requiresInstMTArg = false; - - MethodDesc method = HandleToObject(ftn); - if (method.IsUnboxingThunk()) - { - result = method.GetUnboxedMethod(); - requiresInstMTArg = method.RequiresInstMethodTableArg(); - } - - if (requiresInstMethodTableArg != null) - { - *requiresInstMethodTableArg = requiresInstMTArg ? (byte)1 : (byte)0; - } - - return result != null ? ObjectToHandle(result) : null; - } - - private CORINFO_CLASS_STRUCT_* getDefaultEqualityComparerClass(CORINFO_CLASS_STRUCT_* elemType) - { - TypeDesc comparand = HandleToObject(elemType); - TypeDesc comparer = IL.Stubs.ComparerIntrinsics.GetEqualityComparerForType(comparand); - return comparer != null ? ObjectToHandle(comparer) : null; - } - - private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) - { - TypeDesc type = HandleToObject(classHnd); - return type.IsIntrinsic; - } - - private CorInfoUnmanagedCallConv getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method) - { - MethodSignatureFlags unmanagedCallConv = HandleToObject(method).GetPInvokeMethodMetadata().Flags.UnmanagedCallingConvention; - - // Verify that it is safe to convert MethodSignatureFlags.UnmanagedCallingConvention to CorInfoUnmanagedCallConv via a simple cast - Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_C == (int)MethodSignatureFlags.UnmanagedCallingConventionCdecl); - Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_STDCALL == (int)MethodSignatureFlags.UnmanagedCallingConventionStdCall); - Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_THISCALL == (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall); - - return (CorInfoUnmanagedCallConv)unmanagedCallConv; - } - - private bool satisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) - { 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 CorInfoInstantiationVerification isInstantiationOfVerifiedGeneric(CORINFO_METHOD_STRUCT_* method) - { throw new NotImplementedException("isInstantiationOfVerifiedGeneric"); } - private void initConstraintsForVerification(CORINFO_METHOD_STRUCT_* method, ref bool pfHasCircularClassConstraints, ref bool pfHasCircularMethodConstraint) - { throw new NotImplementedException("isInstantiationOfVerifiedGeneric"); } - - private CorInfoCanSkipVerificationResult canSkipMethodVerification(CORINFO_METHOD_STRUCT_* ftnHandle) - { - return CorInfoCanSkipVerificationResult.CORINFO_VERIFICATION_CAN_SKIP; - } - - private void methodMustBeLoadedBeforeCodeIsRun(CORINFO_METHOD_STRUCT_* method) - { - } - - private CORINFO_METHOD_STRUCT_* mapMethodDeclToMethodImpl(CORINFO_METHOD_STRUCT_* method) - { throw new NotImplementedException("mapMethodDeclToMethodImpl"); } - - private static object ResolveTokenWithSubstitution(MethodIL methodIL, mdToken token, Instantiation typeInst, Instantiation methodInst) - { - // Grab the generic definition of the method IL, resolve the token within the definition, - // and instantiate it with the given context. - object result = methodIL.GetMethodILDefinition().GetObject((int)token); - - if (result is MethodDesc methodResult) - { - result = methodResult.InstantiateSignature(typeInst, methodInst); - } - else if (result is FieldDesc fieldResult) - { - result = fieldResult.InstantiateSignature(typeInst, methodInst); - } - else - { - result = ((TypeDesc)result).InstantiateSignature(typeInst, methodInst); - } - - return result; - } - - private static object ResolveTokenInScope(MethodIL methodIL, object typeOrMethodContext, mdToken token) - { - MethodDesc owningMethod = methodIL.OwningMethod; - - // If token context differs from the scope, it means we're inlining. - // If we're inlining a shared method body, we might be able to un-share - // the referenced token and avoid runtime lookups. - // Resolve the token in the inlining context. - - object result; - if (owningMethod != typeOrMethodContext && - owningMethod.IsCanonicalMethod(CanonicalFormKind.Any)) - { - Instantiation typeInst = default; - Instantiation methodInst = default; - - if (typeOrMethodContext is TypeDesc typeContext) - { - Debug.Assert(typeContext.HasSameTypeDefinition(owningMethod.OwningType)); - typeInst = typeContext.Instantiation; - } - else - { - var methodContext = (MethodDesc)typeOrMethodContext; - Debug.Assert(methodContext.GetTypicalMethodDefinition() == owningMethod.GetTypicalMethodDefinition()); - typeInst = methodContext.OwningType.Instantiation; - methodInst = methodContext.Instantiation; - } - - result = ResolveTokenWithSubstitution(methodIL, token, typeInst, methodInst); - } - else - { - // Not inlining - just resolve the token within the methodIL - result = methodIL.GetObject((int)token); - } - - return result; - } - - private object GetRuntimeDeterminedObjectForToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) - { - // Since RyuJIT operates on canonical types (as opposed to runtime determined ones), but the - // dependency analysis operates on runtime determined ones, we convert the resolved token - // to the runtime determined form (e.g. Foo<__Canon> becomes Foo). - - var methodIL = (MethodIL)HandleToObject((IntPtr)pResolvedToken.tokenScope); - var typeOrMethodContext = HandleToObject((IntPtr)pResolvedToken.tokenContext); - - object result = ResolveTokenInScope(methodIL, typeOrMethodContext, pResolvedToken.token); - - if (result is MethodDesc method) - { - if (method.IsSharedByGenericInstantiations) - { - MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget(); - result = ResolveTokenWithSubstitution(methodIL, pResolvedToken.token, sharedMethod.OwningType.Instantiation, sharedMethod.Instantiation); - Debug.Assert(((MethodDesc)result).IsRuntimeDeterminedExactMethod); - } - } - else if (result is FieldDesc field) - { - if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget(); - result = ResolveTokenWithSubstitution(methodIL, pResolvedToken.token, sharedMethod.OwningType.Instantiation, sharedMethod.Instantiation); - Debug.Assert(((FieldDesc)result).OwningType.IsRuntimeDeterminedSubtype); - } - } - else - { - TypeDesc type = (TypeDesc)result; - if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget(); - result = ResolveTokenWithSubstitution(methodIL, pResolvedToken.token, sharedMethod.OwningType.Instantiation, sharedMethod.Instantiation); - Debug.Assert(((TypeDesc)result).IsRuntimeDeterminedSubtype || - /* If the resolved type is not runtime determined there's a chance we went down this path - because there was a literal typeof(__Canon) in the compiled IL - check for that - by resolving the token in the definition. */ - ((TypeDesc)methodIL.GetMethodILDefinition().GetObject((int)pResolvedToken.token)).IsCanonicalDefinitionType(CanonicalFormKind.Any)); - } - - if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Newarr) - result = ((TypeDesc)result).MakeArrayType(); - } - - return result; - } - - private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) - { - var methodIL = (MethodIL)HandleToObject((IntPtr)pResolvedToken.tokenScope); - var typeOrMethodContext = HandleToObject((IntPtr)pResolvedToken.tokenContext); - - object result = ResolveTokenInScope(methodIL, typeOrMethodContext, pResolvedToken.token); - - pResolvedToken.hClass = null; - pResolvedToken.hMethod = null; - pResolvedToken.hField = null; - -#if READYTORUN - TypeDesc owningType = methodIL.OwningMethod.GetTypicalMethodDefinition().OwningType; - bool recordToken = _compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(owningType) && owningType is EcmaType; -#endif - - if (result is MethodDesc) - { - MethodDesc method = result as MethodDesc; - pResolvedToken.hMethod = ObjectToHandle(method); - - TypeDesc owningClass = method.OwningType; - pResolvedToken.hClass = ObjectToHandle(owningClass); - -#if !SUPPORT_JIT - _compilation.TypeSystemContext.EnsureLoadableType(owningClass); -#endif - -#if READYTORUN - if (recordToken) - { - _compilation.NodeFactory.Resolver.AddModuleTokenForMethod(method, HandleToModuleToken(ref pResolvedToken)); - } -#endif - } - else - if (result is FieldDesc) - { - FieldDesc field = result as FieldDesc; - - // References to literal fields from IL body should never resolve. - // The CLR would throw a MissingFieldException while jitting and so should we. - if (field.IsLiteral) - ThrowHelper.ThrowMissingFieldException(field.OwningType, field.Name); - - pResolvedToken.hField = ObjectToHandle(field); - - TypeDesc owningClass = field.OwningType; - pResolvedToken.hClass = ObjectToHandle(owningClass); - -#if !SUPPORT_JIT - _compilation.TypeSystemContext.EnsureLoadableType(owningClass); -#endif - -#if READYTORUN - if (recordToken) - { - _compilation.NodeFactory.Resolver.AddModuleTokenForField(field, HandleToModuleToken(ref pResolvedToken)); - } -#endif - } - else - { - TypeDesc type = (TypeDesc)result; - -#if READYTORUN - if (recordToken) - { - _compilation.NodeFactory.Resolver.AddModuleTokenForType(type, HandleToModuleToken(ref pResolvedToken)); - } -#endif - - if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Newarr) - { - if (type.IsVoid) - ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramSpecific, methodIL.OwningMethod); - - type = type.MakeArrayType(); - } - pResolvedToken.hClass = ObjectToHandle(type); - -#if !SUPPORT_JIT - _compilation.TypeSystemContext.EnsureLoadableType(type); -#endif - } - - pResolvedToken.pTypeSpec = null; - pResolvedToken.cbTypeSpec = 0; - pResolvedToken.pMethodSpec = null; - pResolvedToken.cbMethodSpec = 0; - } - - private bool tryResolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) - { - resolveToken(ref pResolvedToken); - return true; - } - - private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) - { - var methodIL = (MethodIL)HandleToObject((IntPtr)module); - Get_CORINFO_SIG_INFO((MethodSignature)methodIL.GetObject((int)sigTOK), sig); - } - - private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) - { - var methodIL = (MethodIL)HandleToObject((IntPtr)module); - Get_CORINFO_SIG_INFO(((MethodDesc)methodIL.GetObject((int)methTOK)), sig); - } - - private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) - { - WellKnownType result = WellKnownType.RuntimeTypeHandle; - - if (pResolvedToken.hMethod != null) - { - result = WellKnownType.RuntimeMethodHandle; - } - else - if (pResolvedToken.hField != null) - { - result = WellKnownType.RuntimeFieldHandle; - } - - return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(result)); - } - - private CorInfoCanSkipVerificationResult canSkipVerification(CORINFO_MODULE_STRUCT_* module) - { - return CorInfoCanSkipVerificationResult.CORINFO_VERIFICATION_CAN_SKIP; - } - - private bool isValidToken(CORINFO_MODULE_STRUCT_* module, uint metaTOK) - { throw new NotImplementedException("isValidToken"); } - private bool isValidStringRef(CORINFO_MODULE_STRUCT_* module, uint metaTOK) - { throw new NotImplementedException("isValidStringRef"); } - private bool shouldEnforceCallvirtRestriction(CORINFO_MODULE_STRUCT_* scope) - { throw new NotImplementedException("shouldEnforceCallvirtRestriction"); } - - private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) - { - var type = HandleToObject(cls); - return asCorInfoType(type); - } - - private byte* getClassName(CORINFO_CLASS_STRUCT_* cls) - { - var type = HandleToObject(cls); - return (byte*)GetPin(StringToUTF8(type.ToString())); - } - - private byte* getClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) - { - var type = HandleToObject(cls) as MetadataType; - if (type != null) - { - if (namespaceName != null) - *namespaceName = (byte*)GetPin(StringToUTF8(type.Namespace)); - return (byte*)GetPin(StringToUTF8(type.Name)); - } - - if (namespaceName != null) - *namespaceName = null; - return null; - } - - private CORINFO_CLASS_STRUCT_* getTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index) - { - TypeDesc type = HandleToObject(cls); - Instantiation inst = type.Instantiation; - - return index < (uint)inst.Length ? ObjectToHandle(inst[(int)index]) : null; - } - - - private int appendClassName(short** ppBuf, ref int pnBufLen, CORINFO_CLASS_STRUCT_* cls, bool fNamespace, bool fFullInst, bool fAssembly) - { - // We support enough of this to make SIMD work, but not much else. - - Debug.Assert(fNamespace && !fFullInst && !fAssembly); - - var type = HandleToObject(cls); - string name = TypeString.Instance.FormatName(type); - - int length = name.Length; - if (pnBufLen > 0) - { - short* buffer = *ppBuf; - for (int i = 0; i < Math.Min(name.Length, pnBufLen); i++) - buffer[i] = (short)name[i]; - if (name.Length < pnBufLen) - buffer[name.Length] = 0; - else - buffer[pnBufLen - 1] = 0; - pnBufLen -= length; - *ppBuf = buffer + length; - } - - return length; - } - - private bool isValueClass(CORINFO_CLASS_STRUCT_* cls) - { - return HandleToObject(cls).IsValueType; - } - - private CorInfoInlineTypeCheck canInlineTypeCheck(CORINFO_CLASS_STRUCT_* cls, CorInfoInlineTypeCheckSource source) - { - // TODO: when we support multiple modules at runtime, this will need to do more work - // NOTE: cls can be null - return CorInfoInlineTypeCheck.CORINFO_INLINE_TYPECHECK_PASS; - } - - private bool canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_STRUCT_* cls) { throw new NotImplementedException(); } - - private uint getClassAttribs(CORINFO_CLASS_STRUCT_* cls) - { - TypeDesc type = HandleToObject(cls); - return getClassAttribsInternal(type); - } - - private uint getClassAttribsInternal(TypeDesc type) - { - // TODO: Support for verification (CORINFO_FLG_GENERIC_TYPE_VARIABLE) - - CorInfoFlag result = (CorInfoFlag)0; - - var metadataType = type as MetadataType; - - // The array flag is used to identify the faked-up methods on - // array types, i.e. .ctor, Get, Set and Address - if (type.IsArray) - result |= CorInfoFlag.CORINFO_FLG_ARRAY; - - if (type.IsInterface) - result |= CorInfoFlag.CORINFO_FLG_INTERFACE; - - if (type.IsArray || type.IsString) - result |= CorInfoFlag.CORINFO_FLG_VAROBJSIZE; - - if (type.IsValueType) - { - result |= CorInfoFlag.CORINFO_FLG_VALUECLASS; - - if (metadataType.IsByRefLike) - result |= CorInfoFlag.CORINFO_FLG_CONTAINS_STACK_PTR; - - // The CLR has more complicated rules around CUSTOMLAYOUT, but this will do. - if (metadataType.IsExplicitLayout || metadataType.IsWellKnownType(WellKnownType.TypedReference)) - result |= CorInfoFlag.CORINFO_FLG_CUSTOMLAYOUT; - - // TODO - // if (type.IsUnsafeValueType) - // result |= CorInfoFlag.CORINFO_FLG_UNSAFE_VALUECLASS; - } - - if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) - result |= CorInfoFlag.CORINFO_FLG_SHAREDINST; - - if (type.HasVariance) - result |= CorInfoFlag.CORINFO_FLG_VARIANCE; - - if (type.IsDelegate) - result |= CorInfoFlag.CORINFO_FLG_DELEGATE; - - if (_compilation.IsEffectivelySealed(type)) - result |= CorInfoFlag.CORINFO_FLG_FINAL; - - if (type.IsIntrinsic) - result |= CorInfoFlag.CORINFO_FLG_INTRINSIC_TYPE; - - if (metadataType != null) - { - if (metadataType.ContainsGCPointers) - result |= CorInfoFlag.CORINFO_FLG_CONTAINS_GC_PTR; - - if (metadataType.IsBeforeFieldInit) - result |= CorInfoFlag.CORINFO_FLG_BEFOREFIELDINIT; - - // Assume overlapping fields for explicit layout. - if (metadataType.IsExplicitLayout) - result |= CorInfoFlag.CORINFO_FLG_OVERLAPPING_FIELDS; - - if (metadataType.IsAbstract) - result |= CorInfoFlag.CORINFO_FLG_ABSTRACT; - } - - return (uint)result; - } - - private bool isStructRequiringStackAllocRetBuf(CORINFO_CLASS_STRUCT_* cls) - { - // Disable this optimization. It has limited value (only kicks in on x86, and only for less common structs), - // causes bugs and introduces odd ABI differences not compatible with ReadyToRun. - return false; - } - - private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls) - { throw new NotImplementedException("getClassModule"); } - private CORINFO_ASSEMBLY_STRUCT_* getModuleAssembly(CORINFO_MODULE_STRUCT_* mod) - { throw new NotImplementedException("getModuleAssembly"); } - private byte* getAssemblyName(CORINFO_ASSEMBLY_STRUCT_* assem) - { throw new NotImplementedException("getAssemblyName"); } - - private void* LongLifetimeMalloc(UIntPtr sz) - { - return (void*)Marshal.AllocCoTaskMem((int)sz); - } - - private void LongLifetimeFree(void* obj) - { - Marshal.FreeCoTaskMem((IntPtr)obj); - } - - private byte* getClassModuleIdForStatics(CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection) - { throw new NotImplementedException("getClassModuleIdForStatics"); } - - private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) - { - TypeDesc type = HandleToObject(cls); - LayoutInt classSize = type.GetElementSize(); -#if READYTORUN - if (classSize.IsIndeterminate) - { - throw new RequiresRuntimeJitException(type); - } -#endif - return (uint)classSize.AsInt; - } - - private uint getHeapClassSize(CORINFO_CLASS_STRUCT_* cls) - { - TypeDesc type = HandleToObject(cls); - - Debug.Assert(!type.IsValueType); - Debug.Assert(type.IsDefType); - Debug.Assert(!type.IsString); -#if READYTORUN - Debug.Assert(_compilation.IsInheritanceChainLayoutFixedInCurrentVersionBubble(type)); -#endif - - return (uint)((DefType)type).InstanceByteCount.AsInt; - } - - private bool canAllocateOnStack(CORINFO_CLASS_STRUCT_* cls) - { - TypeDesc type = HandleToObject(cls); - - Debug.Assert(!type.IsValueType); - Debug.Assert(type.IsDefType); - - bool result = !type.HasFinalizer; - -#if READYTORUN - if (!_compilation.IsInheritanceChainLayoutFixedInCurrentVersionBubble(type)) - result = false; -#endif - - return result; - } - - private uint getClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint) - { - DefType type = (DefType)HandleToObject(cls); - return (uint)type.InstanceFieldAlignment.AsInt; - } - - private int GatherClassGCLayout(TypeDesc type, byte* gcPtrs) - { - int result = 0; - - if (type.IsByReferenceOfT) - { - *gcPtrs = (byte)CorInfoGCType.TYPE_GC_BYREF; - return 1; - } - - foreach (var field in type.GetFields()) - { - if (field.IsStatic) - continue; - - CorInfoGCType gcType = CorInfoGCType.TYPE_GC_NONE; - - var fieldType = field.FieldType; - if (fieldType.IsValueType) - { - var fieldDefType = (DefType)fieldType; - if (!fieldDefType.ContainsGCPointers && !fieldDefType.IsByRefLike) - continue; - - gcType = CorInfoGCType.TYPE_GC_OTHER; - } - else if (fieldType.IsGCPointer) - { - gcType = CorInfoGCType.TYPE_GC_REF; - } - else if (fieldType.IsByRef) - { - gcType = CorInfoGCType.TYPE_GC_BYREF; - } - else - { - continue; - } - - Debug.Assert(field.Offset.AsInt % PointerSize == 0); - byte* fieldGcPtrs = gcPtrs + field.Offset.AsInt / PointerSize; - - if (gcType == CorInfoGCType.TYPE_GC_OTHER) - { - result += GatherClassGCLayout(fieldType, fieldGcPtrs); - } - else - { - // Ensure that if we have multiple fields with the same offset, - // that we don't double count the data in the gc layout. - if (*fieldGcPtrs == (byte)CorInfoGCType.TYPE_GC_NONE) - { - *fieldGcPtrs = (byte)gcType; - result++; - } - else - { - Debug.Assert(*fieldGcPtrs == (byte)gcType); - } - } - } - - return result; - } - - private uint getClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) - { - uint result = 0; - - DefType type = (DefType)HandleToObject(cls); - - int pointerSize = PointerSize; - - int ptrsCount = AlignmentHelper.AlignUp(type.InstanceFieldSize.AsInt, pointerSize) / pointerSize; - - // Assume no GC pointers at first - for (int i = 0; i < ptrsCount; i++) - gcPtrs[i] = (byte)CorInfoGCType.TYPE_GC_NONE; - - if (type.ContainsGCPointers || type.IsByRefLike) - { - result = (uint)GatherClassGCLayout(type, gcPtrs); - } - return result; - } - - private uint getClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls) - { - TypeDesc type = HandleToObject(cls); - - uint result = 0; - foreach (var field in type.GetFields()) - { - if (!field.IsStatic) - result++; - } - - return result; - } - - private CORINFO_FIELD_STRUCT_* getFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) - { - TypeDesc classWithFields = HandleToObject(clsHnd); - - int iCurrentFoundField = -1; - foreach (var field in classWithFields.GetFields()) - { - if (field.IsStatic) - continue; - - ++iCurrentFoundField; - if (iCurrentFoundField == num) - { - return ObjectToHandle(field); - } - } - - // We could not find the field that was searched for. - throw new InvalidOperationException(); - } - - private bool checkMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, bool fOptional) - { throw new NotImplementedException("checkMethodModifier"); } - - private CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) - { throw new NotImplementedException("getSharedCCtorHelper"); } - private CorInfoHelpFunc getSecurityPrologHelper(CORINFO_METHOD_STRUCT_* ftn) - { throw new NotImplementedException("getSecurityPrologHelper"); } - - private CORINFO_CLASS_STRUCT_* getTypeForBox(CORINFO_CLASS_STRUCT_* cls) - { - var type = HandleToObject(cls); - - var typeForBox = type.IsNullable ? type.Instantiation[0] : type; - - return ObjectToHandle(typeForBox); - } - - private CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_STRUCT_* cls) - { - var type = HandleToObject(cls); - - // we shouldn't allow boxing of types that contains stack pointers - // csc and vbc already disallow it. - if (type.IsByRefLike) - ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramSpecific, MethodBeingCompiled); - - return type.IsNullable ? CorInfoHelpFunc.CORINFO_HELP_BOX_NULLABLE : CorInfoHelpFunc.CORINFO_HELP_BOX; - } - - private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) - { - var type = HandleToObject(cls); - - return type.IsNullable ? CorInfoHelpFunc.CORINFO_HELP_UNBOX_NULLABLE : CorInfoHelpFunc.CORINFO_HELP_UNBOX; - } - - private byte* getHelperName(CorInfoHelpFunc helpFunc) - { - return (byte*)GetPin(StringToUTF8(helpFunc.ToString())); - } - - private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context, bool speculative) - { - FieldDesc fd = field == null ? null : HandleToObject(field); - Debug.Assert(fd == null || fd.IsStatic); - - MethodDesc md = HandleToObject(method); - TypeDesc type = fd != null ? fd.OwningType : typeFromContext(context); - - if (_isFallbackBodyCompilation || -#if READYTORUN - IsClassPreInited(type) -#else - !_compilation.HasLazyStaticConstructor(type) -#endif - ) - { - return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; - } - - MetadataType typeToInit = (MetadataType)type; - - if (fd == null) - { - if (typeToInit.IsBeforeFieldInit) - { - // We can wait for field accesses to run .cctor - return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; - } - - // Run .cctor on statics & constructors - if (md.Signature.IsStatic) - { - // Except don't class construct on .cctor - it would be circular - if (md.IsStaticConstructor) - { - return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; - } - } - else if (!md.IsConstructor && !typeToInit.IsValueType) - { - // According to the spec, we should be able to do this optimization for both reference and valuetypes. - // To maintain backward compatibility, we are doing it for reference types only. - // For instance methods of types with precise-initialization - // semantics, we can assume that the .ctor triggerred the - // type initialization. - // This does not hold for NULL "this" object. However, the spec does - // not require that case to work. - return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; - } - } - - if (typeToInit.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - // Shared generic code has to use helper. Moreover, tell JIT not to inline since - // inlining of generic dictionary lookups is not supported. - return CorInfoInitClassResult.CORINFO_INITCLASS_USE_HELPER | CorInfoInitClassResult.CORINFO_INITCLASS_DONT_INLINE; - } - - // - // Try to prove that the initialization is not necessary because of nesting - // - - if (fd == null) - { - // Handled above - Debug.Assert(!typeToInit.IsBeforeFieldInit); - - // Note that jit has both methods the same if asking whether to emit cctor - // for a given method's code (as opposed to inlining codegen). - MethodDesc contextMethod = methodFromContext(context); - if (contextMethod != MethodBeingCompiled && typeToInit == MethodBeingCompiled.OwningType) - { - // If we're inling a call to a method in our own type, then we should already - // have triggered the .cctor when caller was itself called. - return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; - } - } - else - { - // This optimization may cause static fields in reference types to be accessed without cctor being triggered - // for NULL "this" object. It does not conform with what the spec says. However, we have been historically - // doing it for perf reasons. - if (!typeToInit.IsValueType && !typeToInit.IsBeforeFieldInit) - { - if (typeToInit == typeFromContext(context) || typeToInit == MethodBeingCompiled.OwningType) - { - // The class will be initialized by the time we access the field. - return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; - } - } - - // If we are currently compiling the class constructor for this static field access then we can skip the initClass - if (MethodBeingCompiled.OwningType == typeToInit && MethodBeingCompiled.IsStaticConstructor) - { - // The class will be initialized by the time we access the field. - return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; - } - } - - return CorInfoInitClassResult.CORINFO_INITCLASS_USE_HELPER; - } - - private void classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_STRUCT_* cls) - { - } - - private CORINFO_CLASS_STRUCT_* getBuiltinClass(CorInfoClassId classId) - { - switch (classId) - { - case CorInfoClassId.CLASSID_SYSTEM_OBJECT: - return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Object)); - - case CorInfoClassId.CLASSID_TYPED_BYREF: - return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.TypedReference)); - - case CorInfoClassId.CLASSID_TYPE_HANDLE: - return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.RuntimeTypeHandle)); - - case CorInfoClassId.CLASSID_FIELD_HANDLE: - return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.RuntimeFieldHandle)); - - case CorInfoClassId.CLASSID_METHOD_HANDLE: - return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.RuntimeMethodHandle)); - - case CorInfoClassId.CLASSID_ARGUMENT_HANDLE: - ThrowHelper.ThrowTypeLoadException("System", "RuntimeArgumentHandle", _compilation.TypeSystemContext.SystemModule); - return null; - - case CorInfoClassId.CLASSID_STRING: - return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String)); - - case CorInfoClassId.CLASSID_RUNTIME_TYPE: - TypeDesc typeOfRuntimeType = _compilation.GetTypeOfRuntimeType(); - return typeOfRuntimeType != null ? ObjectToHandle(typeOfRuntimeType) : null; - - default: - throw new NotImplementedException(); - } - } - - private CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls) - { - var type = HandleToObject(cls); - - if (!type.IsPrimitive && !type.IsEnum) - return CorInfoType.CORINFO_TYPE_UNDEF; - - return asCorInfoType(type); - } - - private CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) - { - var type = HandleToObject(cls); - - switch (type.Category) - { - case TypeFlags.Byte: - case TypeFlags.SByte: - case TypeFlags.UInt16: - case TypeFlags.Int16: - case TypeFlags.UInt32: - case TypeFlags.Int32: - case TypeFlags.UInt64: - case TypeFlags.Int64: - case TypeFlags.Single: - case TypeFlags.Double: - return asCorInfoType(type); - - default: - return CorInfoType.CORINFO_TYPE_UNDEF; - } - } - - private bool canCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) - { throw new NotImplementedException("canCast"); } - private bool areTypesEquivalent(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { throw new NotImplementedException("areTypesEquivalent"); } - - private TypeCompareState compareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) - { - TypeDesc fromType = HandleToObject(fromClass); - TypeDesc toType = HandleToObject(toClass); - - TypeCompareState result = TypeCompareState.May; - - if (toType.IsNullable) - { - // If casting to Nullable, don't try to optimize - result = TypeCompareState.May; - } - else if (!fromType.IsCanonicalSubtype(CanonicalFormKind.Any) && !toType.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - // If the types are not shared, we can check directly. - if (fromType.CanCastTo(toType)) - result = TypeCompareState.Must; - else - result = TypeCompareState.MustNot; - } - else if (fromType.IsCanonicalSubtype(CanonicalFormKind.Any) && !toType.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - // Casting from a shared type to an unshared type. - // Only handle casts to interface types for now - if (toType.IsInterface) - { - // Do a preliminary check. - bool canCast = fromType.CanCastTo(toType); - - // Pass back positive results unfiltered. The unknown type - // parameters in fromClass did not come into play. - if (canCast) - { - result = TypeCompareState.Must; - } - // For negative results, the unknown type parameter in - // fromClass might match some instantiated interface, - // either directly or via variance. - // - // However, CanCastTo will report failure in such cases since - // __Canon won't match the instantiated type on the - // interface (which can't be __Canon since we screened out - // canonical subtypes for toClass above). So only report - // failure if the interface is not instantiated. - else if (!toType.HasInstantiation) - { - result = TypeCompareState.MustNot; - } - } - } - -#if READYTORUN - // In R2R it is a breaking change for a previously positive - // cast to become negative, but not for a previously negative - // cast to become positive. So in R2R a negative result is - // always reported back as May. - if (result == TypeCompareState.MustNot) - { - result = TypeCompareState.May; - } -#endif - - return result; - } - - private TypeCompareState compareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { - TypeCompareState result = TypeCompareState.May; - - TypeDesc type1 = HandleToObject(cls1); - TypeDesc type2 = HandleToObject(cls2); - - // If neither type is a canonical subtype, type handle comparison suffices - if (!type1.IsCanonicalSubtype(CanonicalFormKind.Any) && !type2.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - result = (type1 == type2 ? TypeCompareState.Must : TypeCompareState.MustNot); - } - // If either or both types are canonical subtypes, we can sometimes prove inequality. - else - { - // If either is a value type then the types cannot - // be equal unless the type defs are the same. - if (type1.IsValueType || type2.IsValueType) - { - if (!type1.IsCanonicalDefinitionType(CanonicalFormKind.Universal) && !type2.IsCanonicalDefinitionType(CanonicalFormKind.Universal)) - { - if (!type1.HasSameTypeDefinition(type2)) - { - result = TypeCompareState.MustNot; - } - } - } - // If we have two ref types that are not __Canon, then the - // types cannot be equal unless the type defs are the same. - else - { - if (!type1.IsCanonicalDefinitionType(CanonicalFormKind.Any) && !type2.IsCanonicalDefinitionType(CanonicalFormKind.Any)) - { - if (!type1.HasSameTypeDefinition(type2)) - { - result = TypeCompareState.MustNot; - } - } - } - } - - return result; - } - - private CORINFO_CLASS_STRUCT_* mergeClasses(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { - TypeDesc type1 = HandleToObject(cls1); - TypeDesc type2 = HandleToObject(cls2); - - TypeDesc merged = TypeExtensions.MergeTypesToCommonParent(type1, type2); - -#if DEBUG - // Make sure the merge is reflexive in the cases we "support". - TypeDesc reflexive = TypeExtensions.MergeTypesToCommonParent(type2, type1); - - // If both sides are classes than either they have a common non-interface parent (in which case it is - // reflexive) - // OR they share a common interface, and it can be order dependent (if they share multiple interfaces - // in common) - if (!type1.IsInterface && !type2.IsInterface) - { - if (merged.IsInterface) - { - Debug.Assert(reflexive.IsInterface); - } - else - { - Debug.Assert(merged == reflexive); - } - } - // Both results must either be interfaces or classes. They cannot be mixed. - Debug.Assert(merged.IsInterface == reflexive.IsInterface); - - // If the result of the merge was a class, then the result of the reflexive merge was the same class. - if (!merged.IsInterface) - { - Debug.Assert(merged == reflexive); - } - - // If both sides are arrays, then the result is either an array or g_pArrayClass. The above is - // actually true about the element type for references types, but I think that that is a little - // excessive for sanity. - if (type1.IsArray && type2.IsArray) - { - TypeDesc arrayClass = _compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Array); - Debug.Assert((merged.IsArray && reflexive.IsArray) - || ((merged == arrayClass) && (reflexive == arrayClass))); - } - - // The results must always be assignable - Debug.Assert(type1.CanCastTo(merged) && type2.CanCastTo(merged) && type1.CanCastTo(reflexive) - && type2.CanCastTo(reflexive)); -#endif - - return ObjectToHandle(merged); - } - - private bool isMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { - TypeDesc type1 = HandleToObject(cls1); - TypeDesc type2 = HandleToObject(cls2); - - // If we have a mixture of shared and unshared types, - // consider the unshared type as more specific. - bool isType1CanonSubtype = type1.IsCanonicalSubtype(CanonicalFormKind.Any); - bool isType2CanonSubtype = type2.IsCanonicalSubtype(CanonicalFormKind.Any); - if (isType1CanonSubtype != isType2CanonSubtype) - { - // Only one of type1 and type2 is shared. - // type2 is more specific if type1 is the shared type. - return isType1CanonSubtype; - } - - // Otherwise both types are either shared or not shared. - // Look for a common parent type. - TypeDesc merged = TypeExtensions.MergeTypesToCommonParent(type1, type2); - - // If the common parent is type1, then type2 is more specific. - return merged == type1; - } - - private CORINFO_CLASS_STRUCT_* getParentType(CORINFO_CLASS_STRUCT_* cls) - { throw new NotImplementedException("getParentType"); } - - private CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) - { - CorInfoType result = CorInfoType.CORINFO_TYPE_UNDEF; - - var td = HandleToObject(clsHnd); - if (td.IsArray || td.IsByRef) - { - TypeDesc returnType = ((ParameterizedType)td).ParameterType; - result = asCorInfoType(returnType, clsRet); - } - else - clsRet = null; - - return result; - } - - private bool satisfiesClassConstraints(CORINFO_CLASS_STRUCT_* cls) - { throw new NotImplementedException("satisfiesClassConstraints"); } - - private bool isSDArray(CORINFO_CLASS_STRUCT_* cls) - { - var td = HandleToObject(cls); - return td.IsSzArray; - } - - private uint getArrayRank(CORINFO_CLASS_STRUCT_* cls) - { - var td = HandleToObject(cls) as ArrayType; - Debug.Assert(td != null); - return (uint) td.Rank; - } - - private void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size) - { - var fd = HandleToObject(field); - - // Check for invalid arguments passed to InitializeArray intrinsic - if (!fd.HasRva || - size > fd.FieldType.GetElementSize().AsInt) - { - return null; - } - - return (void*)ObjectToHandle(_compilation.GetFieldRvaData(fd)); - } - - private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) - { - // TODO: Access check - return CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED; - } - - private byte* getFieldName(CORINFO_FIELD_STRUCT_* ftn, byte** moduleName) - { - var field = HandleToObject(ftn); - if (moduleName != null) - { - MetadataType typeDef = field.OwningType.GetTypeDefinition() as MetadataType; - if (typeDef != null) - *moduleName = (byte*)GetPin(StringToUTF8(typeDef.GetFullName())); - else - *moduleName = (byte*)GetPin(StringToUTF8("unknown")); - } - - return (byte*)GetPin(StringToUTF8(field.Name)); - } - - private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) - { - var fieldDesc = HandleToObject(field); - return ObjectToHandle(fieldDesc.OwningType); - } - - private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent) - { - FieldDesc fieldDesc = HandleToObject(field); - TypeDesc fieldType = fieldDesc.FieldType; - - CorInfoType type; - if (structType != null) - { - type = asCorInfoType(fieldType, structType); - } - else - { - type = asCorInfoType(fieldType); - } - - Debug.Assert(!fieldDesc.OwningType.IsByReferenceOfT || - fieldDesc.OwningType.GetKnownField("_value").FieldType.Category == TypeFlags.IntPtr); - if (type == CorInfoType.CORINFO_TYPE_NATIVEINT && fieldDesc.OwningType.IsByReferenceOfT) - { - Debug.Assert(structType == null || *structType == null); - Debug.Assert(fieldDesc.Offset.AsInt == 0); - type = CorInfoType.CORINFO_TYPE_BYREF; - } - - return type; - } - - private uint getFieldOffset(CORINFO_FIELD_STRUCT_* field) - { - var fieldDesc = HandleToObject(field); - - Debug.Assert(fieldDesc.Offset != FieldAndOffset.InvalidOffset); - - return (uint)fieldDesc.Offset.AsInt; - } - - private bool isWriteBarrierHelperRequired(CORINFO_FIELD_STRUCT_* field) - { throw new NotImplementedException("isWriteBarrierHelperRequired"); } - - private CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc field) - { - Debug.Assert(field.IsIntrinsic); - - var owningType = field.OwningType; - if ((owningType.IsWellKnownType(WellKnownType.IntPtr) || - owningType.IsWellKnownType(WellKnownType.UIntPtr)) && - field.Name == "Zero") - { - return CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INTRINSIC_ZERO; - } - else if (owningType.IsString && field.Name == "Empty") - { - return CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INTRINSIC_EMPTY_STRING; - } - else if (owningType.Name == "BitConverter" && owningType.Namespace == "System" && - field.Name == "IsLittleEndian") - { - return CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN; - } - - return (CORINFO_FIELD_ACCESSOR)(-1); - } - - private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) - { -#if DEBUG - // In debug, write some bogus data to the struct to ensure we have filled everything - // properly. - MemoryHelper.FillMemory((byte*)pResult, 0xcc, Marshal.SizeOf()); -#endif - - Debug.Assert(((int)flags & ((int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET | - (int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_SET | - (int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_ADDRESS | - (int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_INIT_ARRAY)) != 0); - - var field = HandleToObject(pResolvedToken.hField); -#if READYTORUN - MethodDesc callerMethod = HandleToObject(callerHandle); - - if (field.Offset.IsIndeterminate) - throw new RequiresRuntimeJitException(field); -#endif - - CORINFO_FIELD_ACCESSOR fieldAccessor; - CORINFO_FIELD_FLAGS fieldFlags = (CORINFO_FIELD_FLAGS)0; - uint fieldOffset = (field.IsStatic && field.HasRva ? 0xBAADF00D : (uint)field.Offset.AsInt); - - if (field.IsStatic) - { - fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC; - -#if READYTORUN - if (field.FieldType.IsValueType && field.HasGCStaticBase && !field.HasRva) - { - // statics of struct types are stored as implicitly boxed in CoreCLR i.e. - // we need to modify field access flags appropriately - fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC_IN_HEAP; - } -#endif - - if (field.HasRva) - { - fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_UNMANAGED; - - // TODO: Handle the case when the RVA is in the TLS range - fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_RVA_ADDRESS; - - // We are not going through a helper. The constructor has to be triggered explicitly. -#if READYTORUN - if (!IsClassPreInited(field.OwningType)) -#else - if (_compilation.HasLazyStaticConstructor(field.OwningType)) -#endif - { - fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_INITCLASS; - } - } - else if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - // The JIT wants to know how to access a static field on a generic type. We need a runtime lookup. -#if READYTORUN - fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER; - if (field.IsThreadStatic) - { - pResult->helper = (field.HasGCStaticBase ? - CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE: - CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE); - } - else - { - pResult->helper = (field.HasGCStaticBase ? - CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: - CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE); - } -#else - fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_READYTORUN_HELPER; - pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE; - - // Don't try to compute the runtime lookup if we're inlining. The JIT is going to abort the inlining - // attempt anyway. - MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); - if (contextMethod == MethodBeingCompiled) - { - FieldDesc runtimeDeterminedField = (FieldDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken); - - ReadyToRunHelperId helperId; - - // Find out what kind of base do we need to look up. - if (field.IsThreadStatic) - { - helperId = ReadyToRunHelperId.GetThreadStaticBase; - } - else if (field.HasGCStaticBase) - { - helperId = ReadyToRunHelperId.GetGCStaticBase; - } - else - { - helperId = ReadyToRunHelperId.GetNonGCStaticBase; - } - - // What generic context do we look up the base from. - ISymbolNode helper; - if (contextMethod.AcquiresInstMethodTableFromThis() || contextMethod.RequiresInstMethodTableArg()) - { - helper = _compilation.NodeFactory.ReadyToRunHelperFromTypeLookup( - helperId, runtimeDeterminedField.OwningType, contextMethod.OwningType); - } - else - { - Debug.Assert(contextMethod.RequiresInstMethodDescArg()); - helper = _compilation.NodeFactory.ReadyToRunHelperFromDictionaryLookup( - helperId, runtimeDeterminedField.OwningType, contextMethod); - } - - pResult->fieldLookup = CreateConstLookupToSymbol(helper); - } -#endif // READYTORUN - } - else - { - fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; - pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE; - - ReadyToRunHelperId helperId = ReadyToRunHelperId.Invalid; - CORINFO_FIELD_ACCESSOR intrinsicAccessor; - if (field.IsIntrinsic && - (flags & CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET) != 0 && - (intrinsicAccessor = getFieldIntrinsic(field)) != (CORINFO_FIELD_ACCESSOR)(-1)) - { - fieldAccessor = intrinsicAccessor; - } - else if (field.IsThreadStatic) - { -#if READYTORUN - if (field.HasGCStaticBase) - { - helperId = ReadyToRunHelperId.GetThreadStaticBase; - } - else - { - helperId = ReadyToRunHelperId.GetThreadNonGcStaticBase; - } -#else - helperId = ReadyToRunHelperId.GetThreadStaticBase; -#endif - } - else if (field.HasGCStaticBase) - { - helperId = ReadyToRunHelperId.GetGCStaticBase; - } - else - { - helperId = ReadyToRunHelperId.GetNonGCStaticBase; - } - -#if READYTORUN - if (!_compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(field.OwningType) && - fieldAccessor == CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER) - { - PreventRecursiveFieldInlinesOutsideVersionBubble(field, callerMethod); - - // Static fields outside of the version bubble need to be accessed using the ENCODE_FIELD_ADDRESS - // helper in accordance with ZapInfo::getFieldInfo in CoreCLR. - pResult->fieldLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.FieldAddress(field, GetSignatureContext())); - - pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE; - - fieldFlags &= ~CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC_IN_HEAP; // The dynamic helper takes care of the unboxing - fieldOffset = 0; - } - else -#endif - - if (helperId != ReadyToRunHelperId.Invalid) - { - pResult->fieldLookup = CreateConstLookupToSymbol( -#if READYTORUN - _compilation.SymbolNodeFactory.ReadyToRunHelper(helperId, field.OwningType, GetSignatureContext()) -#else - _compilation.NodeFactory.ReadyToRunHelper(helperId, field.OwningType) -#endif - ); - } - } - } - else - { - fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INSTANCE; - } - - if (field.IsInitOnly) - fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_FINAL; - - pResult->fieldAccessor = fieldAccessor; - pResult->fieldFlags = fieldFlags; - pResult->fieldType = getFieldType(pResolvedToken.hField, &pResult->structType, pResolvedToken.hClass); - pResult->accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED; - pResult->offset = fieldOffset; - -#if READYTORUN - EncodeFieldBaseOffset(field, pResult, callerMethod); -#endif - - // TODO: We need to implement access checks for fields and methods. See JitInterface.cpp in mrtjit - // and STS::AccessCheck::CanAccess. - } - - private bool isFieldStatic(CORINFO_FIELD_STRUCT_* fldHnd) - { - return HandleToObject(fldHnd).IsStatic; - } - - private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) - { - // TODO: Debugging - cILOffsets = 0; - pILOffsets = null; - *implicitBoundaries = BoundaryTypes.DEFAULT_BOUNDARIES; - } - - private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, ref bool extendOthers) - { - // TODO: Debugging - - cVars = 0; - *vars = null; - - // Just tell the JIT to extend everything. - extendOthers = true; - } - - private void* allocateArray(uint cBytes) - { - return (void*)Marshal.AllocCoTaskMem((int)cBytes); - } - - private void freeArray(void* array) - { - Marshal.FreeCoTaskMem((IntPtr)array); - } - - private CORINFO_ARG_LIST_STRUCT_* getArgNext(CORINFO_ARG_LIST_STRUCT_* args) - { - return (CORINFO_ARG_LIST_STRUCT_*)((int)args + 1); - } - - private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet) - { - int index = (int)args; - Object sigObj = HandleToObject((IntPtr)sig->pSig); - - MethodSignature methodSig = sigObj as MethodSignature; - - if (methodSig != null) - { - TypeDesc type = methodSig[index]; - - CorInfoType corInfoType = asCorInfoType(type, vcTypeRet); - return (CorInfoTypeWithMod)corInfoType; - } - else - { - LocalVariableDefinition[] locals = (LocalVariableDefinition[])sigObj; - TypeDesc type = locals[index].Type; - - CorInfoType corInfoType = asCorInfoType(type, vcTypeRet); - - return (CorInfoTypeWithMod)corInfoType | (locals[index].IsPinned ? CorInfoTypeWithMod.CORINFO_TYPE_MOD_PINNED : 0); - } - } - - private CORINFO_CLASS_STRUCT_* getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) - { - int index = (int)args; - Object sigObj = HandleToObject((IntPtr)sig->pSig); - - MethodSignature methodSig = sigObj as MethodSignature; - if (methodSig != null) - { - TypeDesc type = methodSig[index]; - return ObjectToHandle(type); - } - else - { - LocalVariableDefinition[] locals = (LocalVariableDefinition[])sigObj; - TypeDesc type = locals[index].Type; - return ObjectToHandle(type); - } - } - - private CorInfoType getHFAType(CORINFO_CLASS_STRUCT_* hClass) - { - var type = (DefType)HandleToObject(hClass); - return type.IsHfa ? asCorInfoType(type.HfaElementType) : CorInfoType.CORINFO_TYPE_UNDEF; - } - - private HRESULT GetErrorHRESULT(_EXCEPTION_POINTERS* pExceptionPointers) - { throw new NotImplementedException("GetErrorHRESULT"); } - private uint GetErrorMessage(short* buffer, uint bufferLength) - { throw new NotImplementedException("GetErrorMessage"); } - - private int FilterException(_EXCEPTION_POINTERS* pExceptionPointers) - { - // This method is completely handled by the C++ wrapper to the JIT-EE interface, - // and should never reach the managed implementation. - Debug.Fail("CorInfoImpl.FilterException should not be called"); - throw new NotSupportedException("FilterException"); - } - - private void HandleException(_EXCEPTION_POINTERS* pExceptionPointers) - { - // This method is completely handled by the C++ wrapper to the JIT-EE interface, - // and should never reach the managed implementation. - Debug.Fail("CorInfoImpl.HandleException should not be called"); - throw new NotSupportedException("HandleException"); - } - - private bool runWithErrorTrap(void* function, void* parameter) - { - // This method is completely handled by the C++ wrapper to the JIT-EE interface, - // and should never reach the managed implementation. - Debug.Fail("CorInfoImpl.runWithErrorTrap should not be called"); - throw new NotSupportedException("runWithErrorTrap"); - } - - private void ThrowExceptionForJitResult(HRESULT result) - { throw new NotImplementedException("ThrowExceptionForJitResult"); } - private void ThrowExceptionForHelper(ref CORINFO_HELPER_DESC throwHelper) - { throw new NotImplementedException("ThrowExceptionForHelper"); } - - private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) - { - pEEInfoOut = new CORINFO_EE_INFO(); - -#if DEBUG - // In debug, write some bogus data to the struct to ensure we have filled everything - // properly. - fixed (CORINFO_EE_INFO* tmp = &pEEInfoOut) - MemoryHelper.FillMemory((byte*)tmp, 0xcc, Marshal.SizeOf()); -#endif - - int pointerSize = this.PointerSize; - - pEEInfoOut.inlinedCallFrameInfo.size = (uint)SizeOfPInvokeTransitionFrame; - - pEEInfoOut.offsetOfDelegateInstance = (uint)pointerSize; // Delegate::m_firstParameter - pEEInfoOut.offsetOfDelegateFirstTarget = OffsetOfDelegateFirstTarget; - - pEEInfoOut.offsetOfObjArrayData = (uint)(2 * pointerSize); - - pEEInfoOut.sizeOfReversePInvokeFrame = (uint)(2 * pointerSize); - - pEEInfoOut.osPageSize = new UIntPtr(0x1000); - - pEEInfoOut.maxUncheckedOffsetForNullObject = (_compilation.NodeFactory.Target.IsWindows) ? - new UIntPtr(32 * 1024 - 1) : new UIntPtr((uint)pEEInfoOut.osPageSize / 2 - 1); - - pEEInfoOut.targetAbi = TargetABI; - } - - private string getJitTimeLogFilename() - { - return null; - } - - private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) - { - MethodDesc method = HandleToObject(hMethod); -#if READYTORUN - if (method is UnboxingMethodDesc unboxingMethodDesc) - { - method = unboxingMethodDesc.Target; - } -#endif - MethodDesc methodDefinition = method.GetTypicalMethodDefinition(); - - // Need to cast down to EcmaMethod. Do not use this as a precedent that casting to Ecma* - // within the JitInterface is fine. We might want to consider moving this to Compilation. - TypeSystem.Ecma.EcmaMethod ecmaMethodDefinition = methodDefinition as TypeSystem.Ecma.EcmaMethod; - if (ecmaMethodDefinition != null) - { - return (mdToken)System.Reflection.Metadata.Ecma335.MetadataTokens.GetToken(ecmaMethodDefinition.Handle); - } - - return 0; - } - - private static byte[] StringToUTF8(string s) - { - int byteCount = Encoding.UTF8.GetByteCount(s); - byte[] bytes = new byte[byteCount + 1]; - Encoding.UTF8.GetBytes(s, 0, s.Length, bytes, 0); - return bytes; - } - - private byte* getMethodName(CORINFO_METHOD_STRUCT_* ftn, byte** moduleName) - { - MethodDesc method = HandleToObject(ftn); - - if (moduleName != null) - { - MetadataType typeDef = method.OwningType.GetTypeDefinition() as MetadataType; - if (typeDef != null) - *moduleName = (byte*)GetPin(StringToUTF8(typeDef.GetFullName())); - else - *moduleName = (byte*)GetPin(StringToUTF8("unknown")); - } - - return (byte*)GetPin(StringToUTF8(method.Name)); - } - - private String getMethodNameFromMetadataImpl(MethodDesc method, out string className, out string namespaceName, out string enclosingClassName) - { - string result = null; - className = null; - namespaceName = null; - enclosingClassName = null; - - result = method.Name; - - MetadataType owningType = method.OwningType as MetadataType; - if (owningType != null) - { - className = owningType.Name; - namespaceName = owningType.Namespace; - - // Query enclosingClassName when the method is in a nested class - // and get the namespace of enclosing classes (nested class's namespace is empty) - var containingType = owningType.ContainingType; - if (containingType != null) - { - enclosingClassName = containingType.Name; - namespaceName = containingType.Namespace; - } - } - - return result; - } - - private byte* getMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassName) - { - MethodDesc method = HandleToObject(ftn); - - string result; - string classResult; - string namespaceResult; - string enclosingResult; - - result = getMethodNameFromMetadataImpl(method, out classResult, out namespaceResult, out enclosingResult); - - if (className != null) - *className = classResult != null ? (byte*)GetPin(StringToUTF8(classResult)) : null; - if (namespaceName != null) - *namespaceName = namespaceResult != null ? (byte*)GetPin(StringToUTF8(namespaceResult)) : null; - if (enclosingClassName != null) - *enclosingClassName = enclosingResult != null ? (byte*)GetPin(StringToUTF8(enclosingResult)) : null; - - return result != null ? (byte*)GetPin(StringToUTF8(result)) : null; - } - - private uint getMethodHash(CORINFO_METHOD_STRUCT_* ftn) - { - return (uint)HandleToObject(ftn).GetHashCode(); - } - - private byte* findNameOfToken(CORINFO_MODULE_STRUCT_* moduleHandle, mdToken token, byte* szFQName, UIntPtr FQNameCapacity) - { throw new NotImplementedException("findNameOfToken"); } - - SystemVStructClassificator _systemVStructClassificator = new SystemVStructClassificator(); - - private bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) - { - TypeDesc typeDesc = HandleToObject(structHnd); - - return _systemVStructClassificator.getSystemVAmd64PassStructInRegisterDescriptor(typeDesc, structPassInRegDescPtr); - } - - private uint getThreadTLSIndex(ref void* ppIndirection) - { throw new NotImplementedException("getThreadTLSIndex"); } - private void* getInlinedCallFrameVptr(ref void* ppIndirection) - { throw new NotImplementedException("getInlinedCallFrameVptr"); } - private int* getAddrOfCaptureThreadGlobal(ref void* ppIndirection) - { throw new NotImplementedException("getAddrOfCaptureThreadGlobal"); } - - private Dictionary _helperCache = new Dictionary(); - private void* getHelperFtn(CorInfoHelpFunc ftnNum, ref void* ppIndirection) - { - ISymbolNode entryPoint; - if (!_helperCache.TryGetValue(ftnNum, out entryPoint)) - { - entryPoint = GetHelperFtnUncached(ftnNum); - _helperCache.Add(ftnNum, entryPoint); - } - if (entryPoint.RepresentsIndirectionCell) - { - ppIndirection = (void*)ObjectToHandle(entryPoint); - return null; - } - else - { - ppIndirection = null; - return (void*)ObjectToHandle(entryPoint); - } - } - - private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult) - { throw new NotImplementedException("getFunctionFixedEntryPoint"); } - - private CorInfoHelpFunc getLazyStringLiteralHelper(CORINFO_MODULE_STRUCT_* handle) - { - // TODO: Lazy string literal helper - return CorInfoHelpFunc.CORINFO_HELP_UNDEF; - } - - private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) - { throw new NotImplementedException("embedModuleHandle"); } - private CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) - { throw new NotImplementedException("embedClassHandle"); } - - private CORINFO_FIELD_STRUCT_* embedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) - { throw new NotImplementedException("embedFieldHandle"); } - - private CORINFO_RUNTIME_LOOKUP_KIND GetGenericRuntimeLookupKind(MethodDesc method) - { - if (method.RequiresInstMethodDescArg()) - return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM; - else if (method.RequiresInstMethodTableArg()) - return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM; - else - { - Debug.Assert(method.AcquiresInstMethodTableFromThis()); - return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ; - } - } - - private void getLocationOfThisType(out CORINFO_LOOKUP_KIND result, CORINFO_METHOD_STRUCT_* context) - { - result = new CORINFO_LOOKUP_KIND(); - - MethodDesc method = HandleToObject(context); - - if (method.IsSharedByGenericInstantiations) - { - result.needsRuntimeLookup = true; - result.runtimeLookupKind = GetGenericRuntimeLookupKind(method); - } - else - { - result.needsRuntimeLookup = false; - result.runtimeLookupKind = CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ; - } - } - - private void* getPInvokeUnmanagedTarget(CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection) - { throw new NotImplementedException("getPInvokeUnmanagedTarget"); } - private void* getAddressOfPInvokeFixup(CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection) - { throw new NotImplementedException("getAddressOfPInvokeFixup"); } - private void* GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, ref void* ppIndirection) - { throw new NotImplementedException("GetCookieForPInvokeCalliSig"); } - private CORINFO_JUST_MY_CODE_HANDLE_* getJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) - { - ppIndirection = null; - return null; - } - private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) - { throw new NotImplementedException("GetProfilingHandle"); } - - /// - /// Create a CORINFO_CONST_LOOKUP to a symbol and put the address into the addr field - /// - private CORINFO_CONST_LOOKUP CreateConstLookupToSymbol(ISymbolNode symbol) - { - CORINFO_CONST_LOOKUP constLookup = new CORINFO_CONST_LOOKUP(); - constLookup.addr = (void*)ObjectToHandle(symbol); - constLookup.accessType = symbol.RepresentsIndirectionCell ? InfoAccessType.IAT_PVALUE : InfoAccessType.IAT_VALUE; - return constLookup; - } - - private bool canAccessFamily(CORINFO_METHOD_STRUCT_* hCaller, CORINFO_CLASS_STRUCT_* hInstanceType) - { throw new NotImplementedException("canAccessFamily"); } - private bool isRIDClassDomainID(CORINFO_CLASS_STRUCT_* cls) - { throw new NotImplementedException("isRIDClassDomainID"); } - private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection) - { throw new NotImplementedException("getClassDomainID"); } - - private void* getFieldAddress(CORINFO_FIELD_STRUCT_* field, void** ppIndirection) - { - FieldDesc fieldDesc = HandleToObject(field); - Debug.Assert(fieldDesc.HasRva); - ISymbolNode node = _compilation.GetFieldRvaData(fieldDesc); - void *handle = (void *)ObjectToHandle(node); - if (node.RepresentsIndirectionCell) - { - *ppIndirection = handle; - return null; - } - else - { - if (ppIndirection != null) - *ppIndirection = null; - return handle; - } - } - - private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) - { - if (pIsSpeculative != null) - *pIsSpeculative = 1; - - return null; - } - - private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, ref void* ppIndirection) - { throw new NotImplementedException("getVarArgsHandle"); } - private bool canGetVarArgsHandle(CORINFO_SIG_INFO* pSig) - { throw new NotImplementedException("canGetVarArgsHandle"); } - - private InfoAccessType emptyStringLiteral(ref void* ppValue) - { - return constructStringLiteral(_methodScope, (mdToken)CorTokenType.mdtString, ref ppValue); - } - - private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) - { throw new NotImplementedException("getFieldThreadLocalStoreID"); } - private void setOverride(IntPtr pOverride, CORINFO_METHOD_STRUCT_* currentMethod) - { throw new NotImplementedException("setOverride"); } - private void addActiveDependency(CORINFO_MODULE_STRUCT_* moduleFrom, CORINFO_MODULE_STRUCT_* moduleTo) - { throw new NotImplementedException("addActiveDependency"); } - private CORINFO_METHOD_STRUCT_* GetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) - { throw new NotImplementedException("GetDelegateCtor"); } - private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) - { throw new NotImplementedException("MethodCompileComplete"); } - - private void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) - { - // Slow tailcalls are not supported yet - // https://github.com/dotnet/corert/issues/1683 - return null; - } - - private void* getMemoryManager() - { - // This method is completely handled by the C++ wrapper to the JIT-EE interface, - // and should never reach the managed implementation. - Debug.Fail("CorInfoImpl.getMemoryManager should not be called"); - throw new NotSupportedException("getMemoryManager"); - } - - private byte[] _code; - private byte[] _coldCode; - - private byte[] _roData; - - private BlobNode _roDataBlob; - - private int _numFrameInfos; - private int _usedFrameInfos; - private FrameInfo[] _frameInfos; - - private byte[] _gcInfo; - private CORINFO_EH_CLAUSE[] _ehClauses; - - private void allocMem(uint hotCodeSize, uint coldCodeSize, uint roDataSize, uint xcptnsCount, CorJitAllocMemFlag flag, ref void* hotCodeBlock, ref void* coldCodeBlock, ref void* roDataBlock) - { - hotCodeBlock = (void*)GetPin(_code = new byte[hotCodeSize]); - - if (coldCodeSize != 0) - coldCodeBlock = (void*)GetPin(_coldCode = new byte[coldCodeSize]); - - if (roDataSize != 0) - { - int alignment = 8; - - if ((flag & CorJitAllocMemFlag.CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN) != 0) - { - alignment = 16; - } - else if (roDataSize < 8) - { - alignment = PointerSize; - } - - _roData = new byte[roDataSize]; - - _roDataBlob = _compilation.NodeFactory.ReadOnlyDataBlob( - "__readonlydata_" + _compilation.NameMangler.GetMangledMethodName(MethodBeingCompiled), - _roData, alignment); - - roDataBlock = (void*)GetPin(_roData); - } - - if (_numFrameInfos > 0) - { - _frameInfos = new FrameInfo[_numFrameInfos]; - } - } - - private void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize) - { - _numFrameInfos++; - } - - private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) - { - Debug.Assert(FrameInfoFlags.Filter == (FrameInfoFlags)CorJitFuncKind.CORJIT_FUNC_FILTER); - Debug.Assert(FrameInfoFlags.Handler == (FrameInfoFlags)CorJitFuncKind.CORJIT_FUNC_HANDLER); - - FrameInfoFlags flags = (FrameInfoFlags)funcKind; - - if (funcKind == CorJitFuncKind.CORJIT_FUNC_ROOT) - { - if (this.MethodBeingCompiled.IsNativeCallable) - flags |= FrameInfoFlags.ReversePInvoke; - } - - byte[] blobData = new byte[unwindSize]; - - for (uint i = 0; i < unwindSize; i++) - { - blobData[i] = pUnwindBlock[i]; - } - - _frameInfos[_usedFrameInfos++] = new FrameInfo(flags, (int)startOffset, (int)endOffset, blobData); - } - - private void* allocGCInfo(UIntPtr size) - { - _gcInfo = new byte[(int)size]; - return (void*)GetPin(_gcInfo); - } - - private void yieldExecution() - { - // Nothing to do - } - - private void setEHcount(uint cEH) - { - _ehClauses = new CORINFO_EH_CLAUSE[cEH]; - } - - private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) - { - _ehClauses[EHnumber] = clause; - } - - private bool logMsg(uint level, byte* fmt, IntPtr args) - { - // Console.WriteLine(Marshal.PtrToStringAnsi((IntPtr)fmt)); - return false; - } - - private int doAssert(byte* szFile, int iLine, byte* szExpr) - { - Log.WriteLine(Marshal.PtrToStringAnsi((IntPtr)szFile) + ":" + iLine); - Log.WriteLine(Marshal.PtrToStringAnsi((IntPtr)szExpr)); - - return 1; - } - - private void reportFatalError(CorJitResult result) - { - // We could add some logging here, but for now it's unnecessary. - // CompileMethod is going to fail with this CorJitResult anyway. - } - - private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) - { - } - - private ArrayBuilder _relocs; - - /// - /// Various type of block. - /// - public enum BlockType : sbyte - { - /// Not a generated block. - Unknown = -1, - /// Represent code. - Code = 0, - /// Represent cold code (i.e. code not called frequently). - ColdCode = 1, - /// Read-only data. - ROData = 2, - /// Instrumented Block Count Data - BBCounts = 3 - } - - private BlockType findKnownBlock(void* location, out int offset) - { - fixed (byte* pCode = _code) - { - if (pCode <= (byte*)location && (byte*)location < pCode + _code.Length) - { - offset = (int)((byte*)location - pCode); - return BlockType.Code; - } - } - - if (_coldCode != null) - { - fixed (byte* pColdCode = _coldCode) - { - if (pColdCode <= (byte*)location && (byte*)location < pColdCode + _coldCode.Length) - { - offset = (int)((byte*)location - pColdCode); - return BlockType.ColdCode; - } - } - } - - if (_roData != null) - { - fixed (byte* pROData = _roData) - { - if (pROData <= (byte*)location && (byte*)location < pROData + _roData.Length) - { - offset = (int)((byte*)location - pROData); - return BlockType.ROData; - } - } - } - - { - BlockType retBlockType = BlockType.Unknown; - offset = 0; - findKnownBBCountBlock(ref retBlockType, location, ref offset); - if (retBlockType == BlockType.BBCounts) - return retBlockType; - } - - offset = 0; - return BlockType.Unknown; - } - - partial void findKnownBBCountBlock(ref BlockType blockType, void* location, ref int offset); - - private void recordRelocation(void* location, void* target, ushort fRelocType, ushort slotNum, int addlDelta) - { - // slotNum is not unused - Debug.Assert(slotNum == 0); - - int relocOffset; - BlockType locationBlock = findKnownBlock(location, out relocOffset); - Debug.Assert(locationBlock != BlockType.Unknown, "BlockType.Unknown not expected"); - - if (locationBlock != BlockType.Code) - { - // TODO: https://github.com/dotnet/corert/issues/3877 - TargetArchitecture targetArchitecture = _compilation.TypeSystemContext.Target.Architecture; - if (targetArchitecture == TargetArchitecture.ARM) - return; - throw new NotImplementedException("Arbitrary relocs"); - } - - int relocDelta; - BlockType targetBlock = findKnownBlock(target, out relocDelta); - - ISymbolNode relocTarget; - switch (targetBlock) - { - case BlockType.Code: - relocTarget = _methodCodeNode; - break; - - case BlockType.ColdCode: - // TODO: Arbitrary relocs - throw new NotImplementedException("ColdCode relocs"); - - case BlockType.ROData: - relocTarget = _roDataBlob; - break; - -#if READYTORUN - case BlockType.BBCounts: - relocTarget = _profileDataNode; - break; -#endif - - default: - // Reloc points to something outside of the generated blocks - var targetObject = HandleToObject((IntPtr)target); - relocTarget = (ISymbolNode)targetObject; - break; - } - - relocDelta += addlDelta; - - // relocDelta is stored as the value - Relocation.WriteValue((RelocType)fRelocType, location, relocDelta); - - if (_relocs.Count == 0) - _relocs.EnsureCapacity(_code.Length / 32 + 1); - _relocs.Add(new Relocation((RelocType)fRelocType, relocOffset, relocTarget)); - } - - private ushort getRelocTypeHint(void* target) - { - switch (_compilation.TypeSystemContext.Target.Architecture) - { - case TargetArchitecture.X64: - return (ushort)ILCompiler.DependencyAnalysis.RelocType.IMAGE_REL_BASED_REL32; - - case TargetArchitecture.ARM: - return (ushort)ILCompiler.DependencyAnalysis.RelocType.IMAGE_REL_BASED_THUMB_BRANCH24; - - default: - return UInt16.MaxValue; - } - } - - private void getModuleNativeEntryPointRange(ref void* pStart, ref void* pEnd) - { throw new NotImplementedException("getModuleNativeEntryPointRange"); } - - private uint getExpectedTargetArchitecture() - { - TargetArchitecture arch = _compilation.TypeSystemContext.Target.Architecture; - - switch (arch) - { - case TargetArchitecture.X86: - return (uint)ImageFileMachine.I386; - case TargetArchitecture.X64: - return (uint)ImageFileMachine.AMD64; - case TargetArchitecture.ARM: - return (uint)ImageFileMachine.ARM; - case TargetArchitecture.ARM64: - return (uint)ImageFileMachine.ARM; - default: - throw new NotImplementedException("Expected target architecture is not supported"); - } - } - - private bool isMethodDefinedInCoreLib() - { - TypeDesc owningType = MethodBeingCompiled.OwningType; - MetadataType owningMetadataType = owningType as MetadataType; - if (owningMetadataType == null) - { - return false; - } - return owningMetadataType.Module == _compilation.TypeSystemContext.SystemModule; - } - - private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) - { - // Read the user-defined configuration options. - foreach (var flag in _jitConfig.Flags) - flags.Set(flag); - - // Set the rest of the flags that don't make sense to expose publically. - flags.Set(CorJitFlag.CORJIT_FLAG_SKIP_VERIFICATION); - flags.Set(CorJitFlag.CORJIT_FLAG_READYTORUN); - flags.Set(CorJitFlag.CORJIT_FLAG_RELOC); - flags.Set(CorJitFlag.CORJIT_FLAG_PREJIT); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_PINVOKE_HELPERS); - - if ((_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.X86 - || _compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.X64) -#if READYTORUN - && isMethodDefinedInCoreLib() -#endif - ) - { - // This list needs to match the list of intrinsics we can generate detection code for - // in HardwareIntrinsicHelpers.EmitIsSupportedIL. - flags.Set(CorJitFlag.CORJIT_FLAG_USE_AES); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_PCLMULQDQ); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSE3); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSSE3); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_LZCNT); - } - - if (this.MethodBeingCompiled.IsNativeCallable) - flags.Set(CorJitFlag.CORJIT_FLAG_REVERSE_PINVOKE); - - if (this.MethodBeingCompiled.IsPInvoke) - { - flags.Set(CorJitFlag.CORJIT_FLAG_IL_STUB); - } - - if (this.MethodBeingCompiled.IsNoOptimization) - flags.Set(CorJitFlag.CORJIT_FLAG_MIN_OPT); - - return (uint)sizeof(CORJIT_FLAGS); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoTypes.VarInfo.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoTypes.VarInfo.cs deleted file mode 100644 index 671b9dd408b..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoTypes.VarInfo.cs +++ /dev/null @@ -1,183 +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 System.Diagnostics; -using System.Runtime.InteropServices; - -// -// The types in this file are referenced directly from ILCompiler.Compiler -// so cannot be easily factored out into ILCompiler.RyuJit until we build -// some sort of abstraction. -// - -namespace Internal.JitInterface -{ - public enum VarLocType : uint - { - VLT_REG, // variable is in a register - VLT_REG_BYREF, // address of the variable is in a register - VLT_REG_FP, // variable is in an fp register - VLT_STK, // variable is on the stack (memory addressed relative to the frame-pointer) - VLT_STK_BYREF, // address of the variable is on the stack (memory addressed relative to the frame-pointer) - VLT_REG_REG, // variable lives in two registers - VLT_REG_STK, // variable lives partly in a register and partly on the stack - VLT_STK_REG, // reverse of VLT_REG_STK - VLT_STK2, // variable lives in two slots on the stack - VLT_FPSTK, // variable lives on the floating-point stack - VLT_FIXED_VA, // variable is a fixed argument in a varargs function (relative to VARARGS_HANDLE) - - VLT_COUNT, - VLT_INVALID - }; - - public struct NativeVarInfo - { - public uint startOffset; - public uint endOffset; - public uint varNumber; - public VarLoc varLoc; - }; - - // The following 16 bytes come from coreclr types. See comment below. - [StructLayout(LayoutKind.Sequential)] - public struct VarLoc - { - public IntPtr A; // vlType + padding - public int B; - public int C; - public int D; - - public VarLocType LocationType => (VarLocType)(A.ToInt64() & 0xFFFFFFFF); - - /* - Changes to the following types may require revisiting the above layout. - - In coreclr\src\inc\cordebuginfo.h - - enum VarLocType - { - VLT_REG, // variable is in a register - VLT_REG_BYREF, // address of the variable is in a register - VLT_REG_FP, // variable is in an fp register - VLT_STK, // variable is on the stack (memory addressed relative to the frame-pointer) - VLT_STK_BYREF, // address of the variable is on the stack (memory addressed relative to the frame-pointer) - VLT_REG_REG, // variable lives in two registers - VLT_REG_STK, // variable lives partly in a register and partly on the stack - VLT_STK_REG, // reverse of VLT_REG_STK - VLT_STK2, // variable lives in two slots on the stack - VLT_FPSTK, // variable lives on the floating-point stack - VLT_FIXED_VA, // variable is a fixed argument in a varargs function (relative to VARARGS_HANDLE) - - VLT_COUNT, - VLT_INVALID, - #ifdef MDIL - VLT_MDIL_SYMBOLIC = 0x20 - #endif - - }; - - struct VarLoc - { - VarLocType vlType; - - union - { - // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc) - // eg. EAX - // VLT_REG_BYREF -- the specified register contains the address of the variable - // eg. [EAX] - - struct - { - RegNum vlrReg; - } vlReg; - - // VLT_STK -- Any 32 bit value which is on the stack - // eg. [ESP+0x20], or [EBP-0x28] - // VLT_STK_BYREF -- the specified stack location contains the address of the variable - // eg. mov EAX, [ESP+0x20]; [EAX] - - struct - { - RegNum vlsBaseReg; - signed vlsOffset; - } vlStk; - - // VLT_REG_REG -- TYP_LONG with both DWords enregistred - // eg. RBM_EAXEDX - - struct - { - RegNum vlrrReg1; - RegNum vlrrReg2; - } vlRegReg; - - // VLT_REG_STK -- Partly enregistered TYP_LONG - // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] } - - struct - { - RegNum vlrsReg; - struct - { - RegNum vlrssBaseReg; - signed vlrssOffset; - } vlrsStk; - } vlRegStk; - - // VLT_STK_REG -- Partly enregistered TYP_LONG - // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX } - - struct - { - struct - { - RegNum vlsrsBaseReg; - signed vlsrsOffset; - } vlsrStk; - RegNum vlsrReg; - } vlStkReg; - - // VLT_STK2 -- Any 64 bit value which is on the stack, - // in 2 successsive DWords. - // eg 2 DWords at [ESP+0x10] - - struct - { - RegNum vls2BaseReg; - signed vls2Offset; - } vlStk2; - - // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack) - // eg. ST(3). Actually it is ST("FPstkHeigth - vpFpStk") - - struct - { - unsigned vlfReg; - } vlFPstk; - - // VLT_FIXED_VA -- fixed argument of a varargs function. - // The argument location depends on the size of the variable - // arguments (...). Inspecting the VARARGS_HANDLE indicates the - // location of the first arg. This argument can then be accessed - // relative to the position of the first arg - - struct - { - unsigned vlfvOffset; - } vlFixedVarArg; - - // VLT_MEMORY - - struct - { - void *rpValue; // pointer to the in-process - // location of the value. - } vlMemory; - }; - }; - */ - }; -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoTypes.cs deleted file mode 100644 index 2b1a8d9cbcc..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/CorInfoTypes.cs +++ /dev/null @@ -1,1470 +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 System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Internal.JitInterface -{ - public static class CORINFO - { - // CORINFO_MAXINDIRECTIONS is the maximum number of - // indirections used by runtime lookups. - // This accounts for up to 2 indirections to get at a dictionary followed by a possible spill slot - public const uint MAXINDIRECTIONS = 4; - public const ushort USEHELPER = 0xffff; - } - - public struct CORINFO_METHOD_STRUCT_ - { - internal static unsafe CORINFO_METHOD_STRUCT_* Construct(int i) - { - return (CORINFO_METHOD_STRUCT_*)((i + 1) << 4); - } - - internal static unsafe int GetValue(CORINFO_METHOD_STRUCT_* val) - { - return ((int)val - 1) >> 4; - } - } - - public struct CORINFO_FIELD_STRUCT_ - { - internal static unsafe CORINFO_FIELD_STRUCT_* Construct(int i) - { - return (CORINFO_FIELD_STRUCT_*)((i + 1) << 4); - } - internal static unsafe int GetValue(CORINFO_FIELD_STRUCT_* val) - { - return ((int)val - 1) >> 4; - } - } - - public struct CORINFO_CLASS_STRUCT_ - { - internal static unsafe CORINFO_CLASS_STRUCT_* Construct(int i) - { - return (CORINFO_CLASS_STRUCT_*)((i + 1) << 4); - } - - internal static unsafe int GetValue(CORINFO_CLASS_STRUCT_* val) - { - return ((int)val - 1) >> 4; - } - } - - public struct CORINFO_ARG_LIST_STRUCT_ - { - } - - public struct CORINFO_MODULE_STRUCT_ - { - internal static unsafe CORINFO_MODULE_STRUCT_* Construct(int i) - { - return (CORINFO_MODULE_STRUCT_*)((i + 1) << 4); - } - internal static unsafe int GetValue(CORINFO_MODULE_STRUCT_* val) - { - return ((int)val - 1) >> 4; - } - } - - public struct CORINFO_ASSEMBLY_STRUCT_ - { - } - - public struct CORINFO_CONTEXT_STRUCT - { - } - - public struct CORINFO_GENERIC_STRUCT_ - { - } - - public struct CORINFO_JUST_MY_CODE_HANDLE_ - { - } - - public struct CORINFO_VarArgInfo - { - } - - public enum _EXCEPTION_POINTERS - { } - - public unsafe struct CORINFO_SIG_INST - { - public uint classInstCount; - public CORINFO_CLASS_STRUCT_** classInst; // (representative, not exact) instantiation for class type variables in signature - public uint methInstCount; - public CORINFO_CLASS_STRUCT_** methInst; // (representative, not exact) instantiation for method type variables in signature - } - - public enum mdToken : uint - { } - - public enum CorTokenType - { - mdtModule = 0x00000000, - mdtTypeRef = 0x01000000, - mdtTypeDef = 0x02000000, - mdtFieldDef = 0x04000000, - mdtMethodDef = 0x06000000, - mdtParamDef = 0x08000000, - mdtInterfaceImpl = 0x09000000, - mdtMemberRef = 0x0a000000, - mdtCustomAttribute = 0x0c000000, - mdtPermission = 0x0e000000, - mdtSignature = 0x11000000, - mdtEvent = 0x14000000, - mdtProperty = 0x17000000, - mdtMethodImpl = 0x19000000, - mdtModuleRef = 0x1a000000, - mdtTypeSpec = 0x1b000000, - mdtAssembly = 0x20000000, - mdtAssemblyRef = 0x23000000, - mdtFile = 0x26000000, - mdtExportedType = 0x27000000, - mdtManifestResource = 0x28000000, - mdtGenericParam = 0x2a000000, - mdtMethodSpec = 0x2b000000, - mdtGenericParamConstraint = 0x2c000000, - - mdtString = 0x70000000, - mdtName = 0x71000000, - mdtBaseType = 0x72000000, - } - - public enum HRESULT { - E_NOTIMPL = -2147467263 - } - - public unsafe struct CORINFO_SIG_INFO - { - public CorInfoCallConv callConv; - public CORINFO_CLASS_STRUCT_* retTypeClass; // if the return type is a value class, this is its handle (enums are normalized) - public CORINFO_CLASS_STRUCT_* retTypeSigClass;// returns the value class as it is in the sig (enums are not converted to primitives) - public byte _retType; - public byte flags; // used by IL stubs code - public ushort numArgs; - public CORINFO_SIG_INST sigInst; // information about how type variables are being instantiated in generic code - public CORINFO_ARG_LIST_STRUCT_* args; - public byte* pSig; - public uint cbSig; - public CORINFO_MODULE_STRUCT_* scope; // passed to getArgClass - public mdToken token; - - public CorInfoType retType { get { return (CorInfoType)_retType; } set { _retType = (byte)value; } } - private CorInfoCallConv getCallConv() { return (CorInfoCallConv)((callConv & CorInfoCallConv.CORINFO_CALLCONV_MASK)); } - private bool hasThis() { return ((callConv & CorInfoCallConv.CORINFO_CALLCONV_HASTHIS) != 0); } - private bool hasExplicitThis() { return ((callConv & CorInfoCallConv.CORINFO_CALLCONV_EXPLICITTHIS) != 0); } - private uint totalILArgs() { return (uint)(numArgs + (hasThis() ? 1 : 0)); } - private bool isVarArg() { return ((getCallConv() == CorInfoCallConv.CORINFO_CALLCONV_VARARG) || (getCallConv() == CorInfoCallConv.CORINFO_CALLCONV_NATIVEVARARG)); } - internal bool hasTypeArg() { return ((callConv & CorInfoCallConv.CORINFO_CALLCONV_PARAMTYPE) != 0); } - }; - - //---------------------------------------------------------------------------- - // Looking up handles and addresses. - // - // When the JIT requests a handle, the EE may direct the JIT that it must - // access the handle in a variety of ways. These are packed as - // CORINFO_CONST_LOOKUP - // or CORINFO_LOOKUP (contains either a CORINFO_CONST_LOOKUP or a CORINFO_RUNTIME_LOOKUP) - // - // Constant Lookups v. Runtime Lookups (i.e. when will Runtime Lookups be generated?) - // ----------------------------------------------------------------------------------- - // - // CORINFO_LOOKUP_KIND is part of the result type of embedGenericHandle, - // getVirtualCallInfo and any other functions that may require a - // runtime lookup when compiling shared generic code. - // - // CORINFO_LOOKUP_KIND indicates whether a particular token in the instruction stream can be: - // (a) Mapped to a handle (type, field or method) at compile-time (!needsRuntimeLookup) - // (b) Must be looked up at run-time, and if so which runtime lookup technique should be used (see below) - // - // If the JIT or EE does not support code sharing for generic code, then - // all CORINFO_LOOKUP results will be "constant lookups", i.e. - // the needsRuntimeLookup of CORINFO_LOOKUP.lookupKind.needsRuntimeLookup - // will be false. - // - // Constant Lookups - // ---------------- - // - // Constant Lookups are either: - // IAT_VALUE: immediate (relocatable) values, - // IAT_PVALUE: immediate values access via an indirection through an immediate (relocatable) address - // IAT_RELPVALUE: immediate values access via a relative indirection through an immediate offset - // IAT_PPVALUE: immediate values access via a double indirection through an immediate (relocatable) address - // - // Runtime Lookups - // --------------- - // - // CORINFO_LOOKUP_KIND is part of the result type of embedGenericHandle, - // getVirtualCallInfo and any other functions that may require a - // runtime lookup when compiling shared generic code. - // - // CORINFO_LOOKUP_KIND indicates whether a particular token in the instruction stream can be: - // (a) Mapped to a handle (type, field or method) at compile-time (!needsRuntimeLookup) - // (b) Must be looked up at run-time using the class dictionary - // stored in the vtable of the this pointer (needsRuntimeLookup && THISOBJ) - // (c) Must be looked up at run-time using the method dictionary - // stored in the method descriptor parameter passed to a generic - // method (needsRuntimeLookup && METHODPARAM) - // (d) Must be looked up at run-time using the class dictionary stored - // in the vtable parameter passed to a method in a generic - // struct (needsRuntimeLookup && CLASSPARAM) - - public unsafe struct CORINFO_CONST_LOOKUP - { - // If the handle is obtained at compile-time, then this handle is the "exact" handle (class, method, or field) - // Otherwise, it's a representative... - // If accessType is - // IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address - // IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle - // IAT_RELPVALUE --> "addr" stores a relative pointer to a location which will hold the real handle - // IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle - - public InfoAccessType accessType; - - // _value represent the union of handle and addr - private IntPtr _value; - public CORINFO_GENERIC_STRUCT_* handle { get { return (CORINFO_GENERIC_STRUCT_*)_value; } set { _value = (IntPtr)value; } } - public void* addr { get { return (void*)_value; } set { _value = (IntPtr)value; } } - }; - - public enum CORINFO_RUNTIME_LOOKUP_KIND - { - CORINFO_LOOKUP_THISOBJ, - CORINFO_LOOKUP_METHODPARAM, - CORINFO_LOOKUP_CLASSPARAM, - } - - public unsafe struct CORINFO_LOOKUP_KIND - { - private byte _needsRuntimeLookup; - public bool needsRuntimeLookup { get { return _needsRuntimeLookup != 0; } set { _needsRuntimeLookup = value ? (byte)1 : (byte)0; } } - public CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind; - - // The 'runtimeLookupFlags' and 'runtimeLookupArgs' fields - // are just for internal VM / ZAP communication, not to be used by the JIT. - public ushort runtimeLookupFlags; - public void* runtimeLookupArgs; - } - - // CORINFO_RUNTIME_LOOKUP indicates the details of the runtime lookup - // operation to be performed. - // - - public unsafe struct CORINFO_RUNTIME_LOOKUP - { - // This is signature you must pass back to the runtime lookup helper - public void* signature; - - // Here is the helper you must call. It is one of CORINFO_HELP_RUNTIMEHANDLE_* helpers. - public CorInfoHelpFunc helper; - - // Number of indirections to get there - // CORINFO_USEHELPER = don't know how to get it, so use helper function at run-time instead - // 0 = use the this pointer itself (e.g. token is C inside code in sealed class C) - // or method desc itself (e.g. token is method void M::mymeth() inside code in M::mymeth) - // Otherwise, follow each byte-offset stored in the "offsets[]" array (may be negative) - public ushort indirections; - - // If set, test for null and branch to helper if null - public byte _testForNull; - public bool testForNull { get { return _testForNull != 0; } set { _testForNull = value ? (byte)1 : (byte)0; } } - - // If set, test the lowest bit and dereference if set (see code:FixupPointer) - public byte _testForFixup; - public bool testForFixup { get { return _testForFixup != 0; } set { _testForFixup = value ? (byte)1 : (byte)0; } } - - public IntPtr offset0; - 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; } } - - public byte _indirectSecondOffset; - public bool indirectSecondOffset { get { return _indirectSecondOffset != 0; } set { _indirectSecondOffset = value ? (byte)1 : (byte)0; } } - - } - - // Result of calling embedGenericHandle - public unsafe struct CORINFO_LOOKUP - { - public CORINFO_LOOKUP_KIND lookupKind; - - // If kind.needsRuntimeLookup then this indicates how to do the lookup - public CORINFO_RUNTIME_LOOKUP runtimeLookup; - - // If the handle is obtained at compile-time, then this handle is the "exact" handle (class, method, or field) - // Otherwise, it's a representative... If accessType is - // IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address - // IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle - // IAT_RELPVALUE --> "addr" stores a relative pointer to a location which will hold the real handle - // IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle - public ref CORINFO_CONST_LOOKUP constLookup - { - get - { - // constLookup is union with runtimeLookup - Debug.Assert(sizeof(CORINFO_RUNTIME_LOOKUP) >= sizeof(CORINFO_CONST_LOOKUP)); - fixed (CORINFO_RUNTIME_LOOKUP * p = &runtimeLookup) - return ref *(CORINFO_CONST_LOOKUP *)p; - } - } - } - - public unsafe struct CORINFO_RESOLVED_TOKEN - { - // - // [In] arguments of resolveToken - // - public CORINFO_CONTEXT_STRUCT* tokenContext; //Context for resolution of generic arguments - public CORINFO_MODULE_STRUCT_* tokenScope; - public mdToken token; //The source token - public CorInfoTokenKind tokenType; - - // - // [Out] arguments of resolveToken. - // - Type handle is always non-NULL. - // - At most one of method and field handles is non-NULL (according to the token type). - // - Method handle is an instantiating stub only for generic methods. Type handle - // is required to provide the full context for methods in generic types. - // - public CORINFO_CLASS_STRUCT_* hClass; - public CORINFO_METHOD_STRUCT_* hMethod; - public CORINFO_FIELD_STRUCT_* hField; - - // - // [Out] TypeSpec and MethodSpec signatures for generics. NULL otherwise. - // - public byte* pTypeSpec; - public uint cbTypeSpec; - public byte* pMethodSpec; - public uint cbMethodSpec; - } - - - // Flags computed by a runtime compiler - public enum CorInfoMethodRuntimeFlags - { - CORINFO_FLG_BAD_INLINEE = 0x00000001, // The method is not suitable for inlining - CORINFO_FLG_VERIFIABLE = 0x00000002, // The method has verifiable code - CORINFO_FLG_UNVERIFIABLE = 0x00000004, // The method has unverifiable code - CORINFO_FLG_SWITCHED_TO_MIN_OPT = 0x00000008, // The JIT decided to switch to MinOpt for this method, when it was not requested - CORINFO_FLG_SWITCHED_TO_OPTIMIZED = 0x00000010, // The JIT decided to switch to tier 1 for this method, when a different tier was requested - }; - - // The enumeration is returned in 'getSig' - - public enum CorInfoCallConv - { - // These correspond to CorCallingConvention - - CORINFO_CALLCONV_DEFAULT = 0x0, - CORINFO_CALLCONV_C = 0x1, - CORINFO_CALLCONV_STDCALL = 0x2, - CORINFO_CALLCONV_THISCALL = 0x3, - CORINFO_CALLCONV_FASTCALL = 0x4, - CORINFO_CALLCONV_VARARG = 0x5, - CORINFO_CALLCONV_FIELD = 0x6, - CORINFO_CALLCONV_LOCAL_SIG = 0x7, - CORINFO_CALLCONV_PROPERTY = 0x8, - CORINFO_CALLCONV_NATIVEVARARG = 0xb, // used ONLY for IL stub PInvoke vararg calls - - CORINFO_CALLCONV_MASK = 0x0f, // Calling convention is bottom 4 bits - CORINFO_CALLCONV_GENERIC = 0x10, - CORINFO_CALLCONV_HASTHIS = 0x20, - CORINFO_CALLCONV_EXPLICITTHIS = 0x40, - CORINFO_CALLCONV_PARAMTYPE = 0x80, // Passed last. Same as CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG - } - - public enum CorInfoUnmanagedCallConv - { - // These correspond to CorUnmanagedCallingConvention - - CORINFO_UNMANAGED_CALLCONV_UNKNOWN, - CORINFO_UNMANAGED_CALLCONV_C, - CORINFO_UNMANAGED_CALLCONV_STDCALL, - CORINFO_UNMANAGED_CALLCONV_THISCALL, - CORINFO_UNMANAGED_CALLCONV_FASTCALL - } - - public enum CORINFO_CALLINFO_FLAGS - { - CORINFO_CALLINFO_NONE = 0x0000, - CORINFO_CALLINFO_ALLOWINSTPARAM = 0x0001, // Can the compiler generate code to pass an instantiation parameters? Simple compilers should not use this flag - CORINFO_CALLINFO_CALLVIRT = 0x0002, // Is it a virtual call? - CORINFO_CALLINFO_KINDONLY = 0x0004, // This is set to only query the kind of call to perform, without getting any other information - CORINFO_CALLINFO_VERIFICATION = 0x0008, // Gets extra verification information. - CORINFO_CALLINFO_SECURITYCHECKS = 0x0010, // Perform security checks. - CORINFO_CALLINFO_LDFTN = 0x0020, // Resolving target of LDFTN - CORINFO_CALLINFO_ATYPICAL_CALLSITE = 0x0040, // Atypical callsite that cannot be disassembled by delay loading helper - } - - // Bit-twiddling of contexts assumes word-alignment of method handles and type handles - // If this ever changes, some other encoding will be needed - public enum CorInfoContextFlags - { - CORINFO_CONTEXTFLAGS_METHOD = 0x00, // CORINFO_CONTEXT_HANDLE is really a CORINFO_METHOD_HANDLE - CORINFO_CONTEXTFLAGS_CLASS = 0x01, // CORINFO_CONTEXT_HANDLE is really a CORINFO_CLASS_HANDLE - CORINFO_CONTEXTFLAGS_MASK = 0x01 - }; - - public enum CorInfoSigInfoFlags - { - CORINFO_SIGFLAG_IS_LOCAL_SIG = 0x01, - CORINFO_SIGFLAG_IL_STUB = 0x02, - }; - - // These are returned from getMethodOptions - public enum CorInfoOptions - { - CORINFO_OPT_INIT_LOCALS = 0x00000010, // zero initialize all variables - - CORINFO_GENERICS_CTXT_FROM_THIS = 0x00000020, // is this shared generic code that access the generic context from the this pointer? If so, then if the method has SEH then the 'this' pointer must always be reported and kept alive. - CORINFO_GENERICS_CTXT_FROM_METHODDESC = 0x00000040, // is this shared generic code that access the generic context from the ParamTypeArg(that is a MethodDesc)? If so, then if the method has SEH then the 'ParamTypeArg' must always be reported and kept alive. Same as CORINFO_CALLCONV_PARAMTYPE - CORINFO_GENERICS_CTXT_FROM_METHODTABLE = 0x00000080, // is this shared generic code that access the generic context from the ParamTypeArg(that is a MethodTable)? If so, then if the method has SEH then the 'ParamTypeArg' must always be reported and kept alive. Same as CORINFO_CALLCONV_PARAMTYPE - CORINFO_GENERICS_CTXT_MASK = (CORINFO_GENERICS_CTXT_FROM_THIS | - CORINFO_GENERICS_CTXT_FROM_METHODDESC | - CORINFO_GENERICS_CTXT_FROM_METHODTABLE), - CORINFO_GENERICS_CTXT_KEEP_ALIVE = 0x00000100, // Keep the generics context alive throughout the method even if there is no explicit use, and report its location to the CLR - } - - public enum CorInfoIntrinsics - { - CORINFO_INTRINSIC_Sin, - CORINFO_INTRINSIC_Cos, - CORINFO_INTRINSIC_Cbrt, - CORINFO_INTRINSIC_Sqrt, - CORINFO_INTRINSIC_Abs, - CORINFO_INTRINSIC_Round, - CORINFO_INTRINSIC_Cosh, - CORINFO_INTRINSIC_Sinh, - CORINFO_INTRINSIC_Tan, - CORINFO_INTRINSIC_Tanh, - CORINFO_INTRINSIC_Asin, - CORINFO_INTRINSIC_Asinh, - CORINFO_INTRINSIC_Acos, - CORINFO_INTRINSIC_Acosh, - CORINFO_INTRINSIC_Atan, - CORINFO_INTRINSIC_Atan2, - CORINFO_INTRINSIC_Atanh, - CORINFO_INTRINSIC_Log10, - CORINFO_INTRINSIC_Pow, - CORINFO_INTRINSIC_Exp, - CORINFO_INTRINSIC_Ceiling, - CORINFO_INTRINSIC_Floor, - CORINFO_INTRINSIC_GetChar, // fetch character out of string - CORINFO_INTRINSIC_Array_GetDimLength, // Get number of elements in a given dimension of an array - CORINFO_INTRINSIC_Array_Get, // Get the value of an element in an array - CORINFO_INTRINSIC_Array_Address, // Get the address of an element in an array - CORINFO_INTRINSIC_Array_Set, // Set the value of an element in an array - CORINFO_INTRINSIC_StringGetChar, // fetch character out of string - CORINFO_INTRINSIC_StringLength, // get the length - CORINFO_INTRINSIC_InitializeArray, // initialize an array from static data - CORINFO_INTRINSIC_GetTypeFromHandle, - CORINFO_INTRINSIC_RTH_GetValueInternal, - CORINFO_INTRINSIC_TypeEQ, - CORINFO_INTRINSIC_TypeNEQ, - CORINFO_INTRINSIC_Object_GetType, - CORINFO_INTRINSIC_StubHelpers_GetStubContext, - CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr, - CORINFO_INTRINSIC_StubHelpers_GetNDirectTarget, - CORINFO_INTRINSIC_InterlockedAdd32, - CORINFO_INTRINSIC_InterlockedAdd64, - CORINFO_INTRINSIC_InterlockedXAdd32, - CORINFO_INTRINSIC_InterlockedXAdd64, - CORINFO_INTRINSIC_InterlockedXchg32, - CORINFO_INTRINSIC_InterlockedXchg64, - CORINFO_INTRINSIC_InterlockedCmpXchg32, - CORINFO_INTRINSIC_InterlockedCmpXchg64, - CORINFO_INTRINSIC_MemoryBarrier, - CORINFO_INTRINSIC_GetCurrentManagedThread, - CORINFO_INTRINSIC_GetManagedThreadId, - CORINFO_INTRINSIC_ByReference_Ctor, - 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, - } - - // Can a value be accessed directly from JITed code. - public enum InfoAccessType - { - IAT_VALUE, // The info value is directly available - IAT_PVALUE, // The value needs to be accessed via an indirection - IAT_PPVALUE, // The value needs to be accessed via a double indirection - IAT_RELPVALUE // The value needs to be accessed via a relative indirection - } - - public enum CorInfoGCType - { - TYPE_GC_NONE, // no embedded objectrefs - TYPE_GC_REF, // Is an object ref - TYPE_GC_BYREF, // Is an interior pointer - promote it but don't scan it - TYPE_GC_OTHER // requires type-specific treatment - } - - public enum CorInfoClassId - { - CLASSID_SYSTEM_OBJECT, - CLASSID_TYPED_BYREF, - CLASSID_TYPE_HANDLE, - CLASSID_FIELD_HANDLE, - CLASSID_METHOD_HANDLE, - CLASSID_STRING, - CLASSID_ARGUMENT_HANDLE, - CLASSID_RUNTIME_TYPE, - } - public enum CorInfoInline - { - INLINE_PASS = 0, // Inlining OK - - // failures are negative - INLINE_FAIL = -1, // Inlining not OK for this case only - INLINE_NEVER = -2, // This method should never be inlined, regardless of context - } - - public enum CorInfoInlineTypeCheck - { - CORINFO_INLINE_TYPECHECK_NONE = 0x00000000, // It's not okay to compare type's vtable with a native type handle - CORINFO_INLINE_TYPECHECK_PASS = 0x00000001, // It's okay to compare type's vtable with a native type handle - CORINFO_INLINE_TYPECHECK_USE_HELPER = 0x00000002, // Use a specialized helper to compare type's vtable with native type handle - } - - public enum CorInfoInlineTypeCheckSource - { - CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE = 0x00000000, // Type handle comes from the vtable - CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN = 0x00000001, // Type handle comes from an ldtoken - } - - public enum CorInfoInlineRestrictions - { - INLINE_RESPECT_BOUNDARY = 0x00000001, // You can inline if there are no calls from the method being inlined - INLINE_NO_CALLEE_LDSTR = 0x00000002, // You can inline only if you guarantee that if inlinee does an ldstr - // inlinee's module will never see that string (by any means). - // This is due to how we implement the NoStringInterningAttribute - // (by reusing the fixup table). - INLINE_SAME_THIS = 0x00000004, // You can inline only if the callee is on the same this reference as caller - } - - // If you add more values here, keep it in sync with TailCallTypeMap in ..\vm\ClrEtwAll.man - // and the string enum in CEEInfo::reportTailCallDecision in ..\vm\JITInterface.cpp - public enum CorInfoTailCall - { - TAILCALL_OPTIMIZED = 0, // Optimized tail call (epilog + jmp) - TAILCALL_RECURSIVE = 1, // Optimized into a loop (only when a method tail calls itself) - TAILCALL_HELPER = 2, // Helper assisted tail call (call to JIT_TailCall) - - // failures are negative - TAILCALL_FAIL = -1, // Couldn't do a tail call - } - - public enum CorInfoCanSkipVerificationResult - { - CORINFO_VERIFICATION_CANNOT_SKIP = 0, // Cannot skip verification during jit time. - CORINFO_VERIFICATION_CAN_SKIP = 1, // Can skip verification during jit time. - CORINFO_VERIFICATION_RUNTIME_CHECK = 2, // Cannot skip verification during jit time, - // but need to insert a callout to the VM to ask during runtime - // whether to raise a verification or not (if the method is unverifiable). - CORINFO_VERIFICATION_DONT_JIT = 3, // Cannot skip verification during jit time, - // but do not jit the method if is is unverifiable. - } - - public enum CorInfoInitClassResult - { - CORINFO_INITCLASS_NOT_REQUIRED = 0x00, // No class initialization required, but the class is not actually initialized yet - // (e.g. we are guaranteed to run the static constructor in method prolog) - CORINFO_INITCLASS_INITIALIZED = 0x01, // Class initialized - CORINFO_INITCLASS_SPECULATIVE = 0x02, // Class may be initialized speculatively - CORINFO_INITCLASS_USE_HELPER = 0x04, // The JIT must insert class initialization helper call. - CORINFO_INITCLASS_DONT_INLINE = 0x08, // The JIT should not inline the method requesting the class initialization. The class - // initialization requires helper class now, but will not require initialization - // if the method is compiled standalone. Or the method cannot be inlined due to some - // requirement around class initialization such as shared generics. - } - - public enum CORINFO_ACCESS_FLAGS - { - CORINFO_ACCESS_ANY = 0x0000, // Normal access - CORINFO_ACCESS_THIS = 0x0001, // Accessed via the this reference - CORINFO_ACCESS_UNWRAP = 0x0002, // Accessed via an unwrap reference - - CORINFO_ACCESS_NONNULL = 0x0004, // Instance is guaranteed non-null - - CORINFO_ACCESS_LDFTN = 0x0010, // Accessed via ldftn - - // Field access flags - CORINFO_ACCESS_GET = 0x0100, // Field get (ldfld) - CORINFO_ACCESS_SET = 0x0200, // Field set (stfld) - CORINFO_ACCESS_ADDRESS = 0x0400, // Field address (ldflda) - CORINFO_ACCESS_INIT_ARRAY = 0x0800, // Field use for InitializeArray - CORINFO_ACCESS_ATYPICAL_CALLSITE = 0x4000, // Atypical callsite that cannot be disassembled by delay loading helper - CORINFO_ACCESS_INLINECHECK = 0x8000, // Return fieldFlags and fieldAccessor only. Used by JIT64 during inlining. - } - - - // these are the attribute flags for fields and methods (getMethodAttribs) - [Flags] - public enum CorInfoFlag : uint - { - // CORINFO_FLG_UNUSED = 0x00000001, - // CORINFO_FLG_UNUSED = 0x00000002, - CORINFO_FLG_PROTECTED = 0x00000004, - CORINFO_FLG_STATIC = 0x00000008, - CORINFO_FLG_FINAL = 0x00000010, - CORINFO_FLG_SYNCH = 0x00000020, - CORINFO_FLG_VIRTUAL = 0x00000040, - // CORINFO_FLG_UNUSED = 0x00000080, - CORINFO_FLG_NATIVE = 0x00000100, - CORINFO_FLG_INTRINSIC_TYPE = 0x00000200, // This type is marked by [Intrinsic] - CORINFO_FLG_ABSTRACT = 0x00000400, - - CORINFO_FLG_EnC = 0x00000800, // member was added by Edit'n'Continue - - // These are internal flags that can only be on methods - CORINFO_FLG_FORCEINLINE = 0x00010000, // The method should be inlined if possible. - CORINFO_FLG_SHAREDINST = 0x00020000, // the code for this method is shared between different generic instantiations (also set on classes/types) - CORINFO_FLG_DELEGATE_INVOKE = 0x00040000, // "Delegate - CORINFO_FLG_PINVOKE = 0x00080000, // Is a P/Invoke call - CORINFO_FLG_SECURITYCHECK = 0x00100000, // Is one of the security routines that does a stackwalk (e.g. Assert, Demand) - CORINFO_FLG_NOGCCHECK = 0x00200000, // This method is FCALL that has no GC check. Don't put alone in loops - CORINFO_FLG_INTRINSIC = 0x00400000, // This method MAY have an intrinsic ID - CORINFO_FLG_CONSTRUCTOR = 0x00800000, // This method is an instance or type initializer - CORINFO_FLG_AGGRESSIVE_OPT = 0x01000000, // The method may contain hot code and should be aggressively optimized if possible - CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS = 0x02000000, // Indicates that tier 0 JIT should not be used for a method that contains a loop - CORINFO_FLG_NOSECURITYWRAP = 0x04000000, // The method requires no security checks - CORINFO_FLG_DONT_INLINE = 0x10000000, // The method should not be inlined - CORINFO_FLG_DONT_INLINE_CALLER = 0x20000000, // The method should not be inlined, nor should its callers. It cannot be tail called. - CORINFO_FLG_JIT_INTRINSIC = 0x40000000, // Method is a potential jit intrinsic; verify identity by name check - - // These are internal flags that can only be on Classes - CORINFO_FLG_VALUECLASS = 0x00010000, // is the class a value class - // This flag is define din the Methods section, but is also valid on classes. - // CORINFO_FLG_SHAREDINST = 0x00020000, // This class is satisfies TypeHandle::IsCanonicalSubtype - CORINFO_FLG_VAROBJSIZE = 0x00040000, // the object size varies depending of constructor args - CORINFO_FLG_ARRAY = 0x00080000, // class is an array class (initialized differently) - CORINFO_FLG_OVERLAPPING_FIELDS = 0x00100000, // struct or class has fields that overlap (aka union) - CORINFO_FLG_INTERFACE = 0x00200000, // it is an interface - CORINFO_FLG_CONTEXTFUL = 0x00400000, // is this a contextful class? - CORINFO_FLG_CUSTOMLAYOUT = 0x00800000, // does this struct have custom layout? - CORINFO_FLG_CONTAINS_GC_PTR = 0x01000000, // does the class contain a gc ptr ? - CORINFO_FLG_DELEGATE = 0x02000000, // is this a subclass of delegate or multicast delegate ? - CORINFO_FLG_MARSHAL_BYREF = 0x04000000, // is this a subclass of MarshalByRef ? - CORINFO_FLG_CONTAINS_STACK_PTR = 0x08000000, // This class has a stack pointer inside it - CORINFO_FLG_VARIANCE = 0x10000000, // MethodTable::HasVariance (sealed does *not* mean uncast-able) - CORINFO_FLG_BEFOREFIELDINIT = 0x20000000, // Additional flexibility for when to run .cctor (see code:#ClassConstructionFlags) - CORINFO_FLG_GENERIC_TYPE_VARIABLE = 0x40000000, // This is really a handle for a variable type - CORINFO_FLG_UNSAFE_VALUECLASS = 0x80000000, // Unsafe (C++'s /GS) value type - } - - - //---------------------------------------------------------------------------- - // Exception handling - - // These are the flags set on an CORINFO_EH_CLAUSE - public enum CORINFO_EH_CLAUSE_FLAGS - { - CORINFO_EH_CLAUSE_NONE = 0, - CORINFO_EH_CLAUSE_FILTER = 0x0001, // If this bit is on, then this EH entry is for a filter - CORINFO_EH_CLAUSE_FINALLY = 0x0002, // This clause is a finally clause - CORINFO_EH_CLAUSE_FAULT = 0x0004, // This clause is a fault clause - CORINFO_EH_CLAUSE_DUPLICATED = 0x0008, // Duplicated clause. This clause was duplicated to a funclet which was pulled out of line - CORINFO_EH_CLAUSE_SAMETRY = 0x0010, // This clause covers same try block as the previous one. (Used by CoreRT ABI.) - }; - - public struct CORINFO_EH_CLAUSE - { - public CORINFO_EH_CLAUSE_FLAGS Flags; - public uint TryOffset; - public uint TryLength; - public uint HandlerOffset; - public uint HandlerLength; - public uint ClassTokenOrOffset; - /* union - { - DWORD ClassToken; // use for type-based exception handlers - DWORD FilterOffset; // use for filter-based exception handlers (COR_ILEXCEPTION_FILTER is set) - };*/ - } - - public struct BlockCounts // Also defined here: code:CORBBTPROF_BLOCK_DATA - { - public uint ILOffset; - public uint ExecutionCount; - } - - // The enumeration is returned in 'getSig','getType', getArgType methods - public enum CorInfoType - { - CORINFO_TYPE_UNDEF = 0x0, - CORINFO_TYPE_VOID = 0x1, - CORINFO_TYPE_BOOL = 0x2, - CORINFO_TYPE_CHAR = 0x3, - CORINFO_TYPE_BYTE = 0x4, - CORINFO_TYPE_UBYTE = 0x5, - CORINFO_TYPE_SHORT = 0x6, - CORINFO_TYPE_USHORT = 0x7, - CORINFO_TYPE_INT = 0x8, - CORINFO_TYPE_UINT = 0x9, - CORINFO_TYPE_LONG = 0xa, - CORINFO_TYPE_ULONG = 0xb, - CORINFO_TYPE_NATIVEINT = 0xc, - CORINFO_TYPE_NATIVEUINT = 0xd, - CORINFO_TYPE_FLOAT = 0xe, - CORINFO_TYPE_DOUBLE = 0xf, - CORINFO_TYPE_STRING = 0x10, // Not used, should remove - CORINFO_TYPE_PTR = 0x11, - CORINFO_TYPE_BYREF = 0x12, - CORINFO_TYPE_VALUECLASS = 0x13, - CORINFO_TYPE_CLASS = 0x14, - CORINFO_TYPE_REFANY = 0x15, - - // CORINFO_TYPE_VAR is for a generic type variable. - // Generic type variables only appear when the JIT is doing - // verification (not NOT compilation) of generic code - // for the EE, in which case we're running - // the JIT in "import only" mode. - - CORINFO_TYPE_VAR = 0x16, - CORINFO_TYPE_COUNT, // number of jit types - } - - public enum CorInfoIsAccessAllowedResult - { - CORINFO_ACCESS_ALLOWED = 0, // Call allowed - CORINFO_ACCESS_ILLEGAL = 1, // Call not allowed - CORINFO_ACCESS_RUNTIME_CHECK = 2, // Ask at runtime whether to allow the call or not - } - - //---------------------------------------------------------------------------- - // Embedding type, method and field handles (for "ldtoken" or to pass back to helpers) - - // Result of calling embedGenericHandle - public unsafe struct CORINFO_GENERICHANDLE_RESULT - { - public CORINFO_LOOKUP lookup; - - // compileTimeHandle is guaranteed to be either NULL or a handle that is usable during compile time. - // It must not be embedded in the code because it might not be valid at run-time. - public CORINFO_GENERIC_STRUCT_* compileTimeHandle; - - // Type of the result - public CorInfoGenericHandleType handleType; - } - - public enum CorInfoGenericHandleType - { - CORINFO_HANDLETYPE_UNKNOWN, - CORINFO_HANDLETYPE_CLASS, - CORINFO_HANDLETYPE_METHOD, - CORINFO_HANDLETYPE_FIELD - } - - /* data to optimize delegate construction */ - public unsafe struct DelegateCtorArgs - { - public void* pMethod; - public void* pArg3; - public void* pArg4; - public void* pArg5; - } - - // When using CORINFO_HELPER_TAILCALL, the JIT needs to pass certain special - // calling convention/argument passing/handling details to the helper - public enum CorInfoHelperTailCallSpecialHandling - { - CORINFO_TAILCALL_NORMAL = 0x00000000, - CORINFO_TAILCALL_STUB_DISPATCH_ARG = 0x00000001, - } - - /*****************************************************************************/ - // These are flags passed to ICorJitInfo::allocMem - // to guide the memory allocation for the code, readonly data, and read-write data - public enum CorJitAllocMemFlag - { - CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN = 0x00000000, // The code will be use the normal alignment - CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN = 0x00000001, // The code will be 16-byte aligned - CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN = 0x00000002, // The read-only data will be 16-byte aligned - } - - public enum CorJitFuncKind - { - CORJIT_FUNC_ROOT, // The main/root function (always id==0) - CORJIT_FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler) - CORJIT_FUNC_FILTER // a funclet associated with an EH filter - } - - - public unsafe struct CORINFO_METHOD_INFO - { - public CORINFO_METHOD_STRUCT_* ftn; - public CORINFO_MODULE_STRUCT_* scope; - public byte* ILCode; - public uint ILCodeSize; - public uint maxStack; - public uint EHcount; - public CorInfoOptions options; - public CorInfoRegionKind regionKind; - public CORINFO_SIG_INFO args; - public CORINFO_SIG_INFO locals; - } - // - // what type of code region we are in - // - public enum CorInfoRegionKind - { - CORINFO_REGION_NONE, - CORINFO_REGION_HOT, - CORINFO_REGION_COLD, - CORINFO_REGION_JIT, - } - - // This is for use when the JIT is compiling an instantiation - // of generic code. The JIT needs to know if the generic code itself - // (which can be verified once and for all independently of the - // instantiations) passed verification. - public enum CorInfoInstantiationVerification - { - // The method is NOT a concrete instantiation (eg. List.Add()) of a method - // in a generic class or a generic method. It is either the typical instantiation - // (eg. List.Add()) or entirely non-generic. - INSTVER_NOT_INSTANTIATION = 0, - - // The method is an instantiation of a method in a generic class or a generic method, - // and the generic class was successfully verified - INSTVER_GENERIC_PASSED_VERIFICATION = 1, - - // The method is an instantiation of a method in a generic class or a generic method, - // and the generic class failed verification - INSTVER_GENERIC_FAILED_VERIFICATION = 2, - }; - - public enum CorInfoTypeWithMod - { - CORINFO_TYPE_MASK = 0x3F, // lower 6 bits are type mask - CORINFO_TYPE_MOD_PINNED = 0x40, // can be applied to CLASS, or BYREF to indiate pinned - }; - - public struct CORINFO_HELPER_ARG - { - public IntPtr argHandle; - public CorInfoAccessAllowedHelperArgType argType; - } - - public enum CorInfoAccessAllowedHelperArgType - { - CORINFO_HELPER_ARG_TYPE_Invalid = 0, - CORINFO_HELPER_ARG_TYPE_Field = 1, - CORINFO_HELPER_ARG_TYPE_Method = 2, - CORINFO_HELPER_ARG_TYPE_Class = 3, - CORINFO_HELPER_ARG_TYPE_Module = 4, - CORINFO_HELPER_ARG_TYPE_Const = 5, - } - - public struct CORINFO_HELPER_DESC - { - public CorInfoHelpFunc helperNum; - public uint numArgs; - public CORINFO_HELPER_ARG args0; - public CORINFO_HELPER_ARG args1; - public CORINFO_HELPER_ARG args2; - public CORINFO_HELPER_ARG args3; - } - - - public enum CORINFO_OS - { - CORINFO_WINNT, - CORINFO_PAL, - } - - public enum CORINFO_RUNTIME_ABI - { - CORINFO_DESKTOP_ABI = 0x100, - CORINFO_CORECLR_ABI = 0x200, - CORINFO_CORERT_ABI = 0x300, - } - - // For some highly optimized paths, the JIT must generate code that directly - // manipulates internal EE data structures. The getEEInfo() helper returns - // this structure containing the needed offsets and values. - public struct CORINFO_EE_INFO - { - // Information about the InlinedCallFrame structure layout - public struct InlinedCallFrameInfo - { - // Size of the Frame structure - public uint size; - - public uint offsetOfGSCookie; - public uint offsetOfFrameVptr; - public uint offsetOfFrameLink; - public uint offsetOfCallSiteSP; - public uint offsetOfCalleeSavedFP; - public uint offsetOfCallTarget; - public uint offsetOfReturnAddress; - public uint offsetOfSPAfterProlog; - } - public InlinedCallFrameInfo inlinedCallFrameInfo; - - // Offsets into the Thread structure - public uint offsetOfThreadFrame; // offset of the current Frame - public uint offsetOfGCState; // offset of the preemptive/cooperative state of the Thread - - // Delegate offsets - public uint offsetOfDelegateInstance; - public uint offsetOfDelegateFirstTarget; - - // Wrapper delegate offsets - public uint offsetOfWrapperDelegateIndirectCell; - - // Remoting offsets - public uint offsetOfTransparentProxyRP; - public uint offsetOfRealProxyServer; - - // Array offsets - public uint offsetOfObjArrayData; - - // Reverse PInvoke offsets - public uint sizeOfReversePInvokeFrame; - - // OS Page size - public UIntPtr osPageSize; - - // Null object offset - public UIntPtr maxUncheckedOffsetForNullObject; - - // Target ABI. Combined with target architecture and OS to determine - // GC, EH, and unwind styles. - public CORINFO_RUNTIME_ABI targetAbi; - - public CORINFO_OS osType; - public uint osMajor; - public uint osMinor; - public uint osBuild; - } - - public enum CORINFO_THIS_TRANSFORM - { - CORINFO_NO_THIS_TRANSFORM, - CORINFO_BOX_THIS, - CORINFO_DEREF_THIS - }; - - //---------------------------------------------------------------------------- - // getCallInfo and CORINFO_CALL_INFO: The EE instructs the JIT about how to make a call - // - // callKind - // -------- - // - // CORINFO_CALL : - // Indicates that the JIT can use getFunctionEntryPoint to make a call, - // i.e. there is nothing abnormal about the call. The JITs know what to do if they get this. - // Except in the case of constraint calls (see below), [targetMethodHandle] will hold - // the CORINFO_METHOD_HANDLE that a call to findMethod would - // have returned. - // This flag may be combined with nullInstanceCheck=TRUE for uses of callvirt on methods that can - // be resolved at compile-time (non-virtual, final or sealed). - // - // CORINFO_CALL_CODE_POINTER (shared generic code only) : - // Indicates that the JIT should do an indirect call to the entrypoint given by address, which may be specified - // as a runtime lookup by CORINFO_CALL_INFO::codePointerLookup. - // [targetMethodHandle] will not hold a valid value. - // This flag may be combined with nullInstanceCheck=TRUE for uses of callvirt on methods whose target method can - // be resolved at compile-time but whose instantiation can be resolved only through runtime lookup. - // - // CORINFO_VIRTUALCALL_STUB (interface calls) : - // Indicates that the EE supports "stub dispatch" and request the JIT to make a - // "stub dispatch" call (an indirect call through CORINFO_CALL_INFO::stubLookup, - // similar to CORINFO_CALL_CODE_POINTER). - // "Stub dispatch" is a specialized calling sequence (that may require use of NOPs) - // which allow the runtime to determine the call-site after the call has been dispatched. - // If the call is too complex for the JIT (e.g. because - // fetching the dispatch stub requires a runtime lookup, i.e. lookupKind.needsRuntimeLookup - // is set) then the JIT is allowed to implement the call as if it were CORINFO_VIRTUALCALL_LDVIRTFTN - // [targetMethodHandle] will hold the CORINFO_METHOD_HANDLE that a call to findMethod would - // have returned. - // This flag is always accompanied by nullInstanceCheck=TRUE. - // - // CORINFO_VIRTUALCALL_LDVIRTFTN (virtual generic methods) : - // Indicates that the EE provides no way to implement the call directly and - // that the JIT should use a LDVIRTFTN sequence (as implemented by CORINFO_HELP_VIRTUAL_FUNC_PTR) - // followed by an indirect call. - // [targetMethodHandle] will hold the CORINFO_METHOD_HANDLE that a call to findMethod would - // have returned. - // This flag is always accompanied by nullInstanceCheck=TRUE though typically the null check will - // be implicit in the access through the instance pointer. - // - // CORINFO_VIRTUALCALL_VTABLE (regular virtual methods) : - // Indicates that the EE supports vtable dispatch and that the JIT should use getVTableOffset etc. - // to implement the call. - // [targetMethodHandle] will hold the CORINFO_METHOD_HANDLE that a call to findMethod would - // have returned. - // This flag is always accompanied by nullInstanceCheck=TRUE though typically the null check will - // be implicit in the access through the instance pointer. - // - // thisTransform and constraint calls - // ---------------------------------- - // - // For evertyhing besides "constrained." calls "thisTransform" is set to - // CORINFO_NO_THIS_TRANSFORM. - // - // For "constrained." calls the EE attempts to resolve the call at compile - // time to a more specific method, or (shared generic code only) to a runtime lookup - // for a code pointer for the more specific method. - // - // In order to permit this, the "this" pointer supplied for a "constrained." call - // is a byref to an arbitrary type (see the IL spec). The "thisTransform" field - // will indicate how the JIT must transform the "this" pointer in order - // to be able to call the resolved method: - // - // CORINFO_NO_THIS_TRANSFORM --> Leave it as a byref to an unboxed value type - // CORINFO_BOX_THIS --> Box it to produce an object - // CORINFO_DEREF_THIS --> Deref the byref to get an object reference - // - // In addition, the "kind" field will be set as follows for constraint calls: - - // CORINFO_CALL --> the call was resolved at compile time, and - // can be compiled like a normal call. - // CORINFO_CALL_CODE_POINTER --> the call was resolved, but the target address will be - // computed at runtime. Only returned for shared generic code. - // CORINFO_VIRTUALCALL_STUB, - // CORINFO_VIRTUALCALL_LDVIRTFTN, - // CORINFO_VIRTUALCALL_VTABLE --> usual values indicating that a virtual call must be made - - public enum CORINFO_CALL_KIND - { - CORINFO_CALL, - CORINFO_CALL_CODE_POINTER, - CORINFO_VIRTUALCALL_STUB, - CORINFO_VIRTUALCALL_LDVIRTFTN, - CORINFO_VIRTUALCALL_VTABLE - }; - - public enum CORINFO_VIRTUALCALL_NO_CHUNK : uint - { - Value = 0xFFFFFFFF, - } - - public unsafe struct CORINFO_CALL_INFO - { - public CORINFO_METHOD_STRUCT_* hMethod; //target method handle - public uint methodFlags; //flags for the target method - - public uint classFlags; //flags for CORINFO_RESOLVED_TOKEN::hClass - - public CORINFO_SIG_INFO sig; - - //Verification information - public uint verMethodFlags; // flags for CORINFO_RESOLVED_TOKEN::hMethod - public CORINFO_SIG_INFO verSig; - //All of the regular method data is the same... hMethod might not be the same as CORINFO_RESOLVED_TOKEN::hMethod - - - //If set to: - // - CORINFO_ACCESS_ALLOWED - The access is allowed. - // - CORINFO_ACCESS_ILLEGAL - This access cannot be allowed (i.e. it is public calling private). The - // JIT may either insert the callsiteCalloutHelper into the code (as per a verification error) or - // call throwExceptionFromHelper on the callsiteCalloutHelper. In this case callsiteCalloutHelper - // is guaranteed not to return. - // - CORINFO_ACCESS_RUNTIME_CHECK - The jit must insert the callsiteCalloutHelper at the call site. - // the helper may return - public CorInfoIsAccessAllowedResult accessAllowed; - public CORINFO_HELPER_DESC callsiteCalloutHelper; - - // See above section on constraintCalls to understand when these are set to unusual values. - public CORINFO_THIS_TRANSFORM thisTransform; - - public CORINFO_CALL_KIND kind; - - public uint _nullInstanceCheck; - public bool nullInstanceCheck { get { return _nullInstanceCheck != 0; } set { _nullInstanceCheck = value ? (byte)1 : (byte)0; } } - - // Context for inlining and hidden arg - public CORINFO_CONTEXT_STRUCT* contextHandle; - - public uint _exactContextNeedsRuntimeLookup; // Set if contextHandle is approx handle. Runtime lookup is required to get the exact handle. - public bool exactContextNeedsRuntimeLookup { get { return _exactContextNeedsRuntimeLookup != 0; } set { _exactContextNeedsRuntimeLookup = value ? (byte)1 : (byte)0; } } - - // If kind.CORINFO_VIRTUALCALL_STUB then stubLookup will be set. - // If kind.CORINFO_CALL_CODE_POINTER then entryPointLookup will be set. - public CORINFO_LOOKUP codePointerOrStubLookup; - - // Used by Ready-to-Run - public CORINFO_CONST_LOOKUP instParamLookup; - - public uint _wrapperDelegateInvoke; - public bool wrapperDelegateInvoke { get { return _wrapperDelegateInvoke != 0; } set { _wrapperDelegateInvoke = value ? (byte)1 : (byte)0; } } - } - - - //---------------------------------------------------------------------------- - // getFieldInfo and CORINFO_FIELD_INFO: The EE instructs the JIT about how to access a field - - public enum CORINFO_FIELD_ACCESSOR - { - CORINFO_FIELD_INSTANCE, // regular instance field at given offset from this-ptr - CORINFO_FIELD_INSTANCE_WITH_BASE, // instance field with base offset (used by Ready-to-Run) - CORINFO_FIELD_INSTANCE_HELPER, // instance field accessed using helper (arguments are this, FieldDesc * and the value) - CORINFO_FIELD_INSTANCE_ADDR_HELPER, // instance field accessed using address-of helper (arguments are this and FieldDesc *) - - CORINFO_FIELD_STATIC_ADDRESS, // field at given address - CORINFO_FIELD_STATIC_RVA_ADDRESS, // RVA field at given address - CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER, // static field accessed using the "shared static" helper (arguments are ModuleID + ClassID) - CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER, // static field access using the "generic static" helper (argument is MethodTable *) - CORINFO_FIELD_STATIC_ADDR_HELPER, // static field accessed using address-of helper (argument is FieldDesc *) - CORINFO_FIELD_STATIC_TLS, // unmanaged TLS access - CORINFO_FIELD_STATIC_READYTORUN_HELPER, // static field access using a runtime lookup helper - - CORINFO_FIELD_INTRINSIC_ZERO, // intrinsic zero (IntPtr.Zero, UIntPtr.Zero) - CORINFO_FIELD_INTRINSIC_EMPTY_STRING, // intrinsic emptry string (String.Empty) - CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN, // intrinsic BitConverter.IsLittleEndian - } - - // Set of flags returned in CORINFO_FIELD_INFO::fieldFlags - public enum CORINFO_FIELD_FLAGS - { - CORINFO_FLG_FIELD_STATIC = 0x00000001, - CORINFO_FLG_FIELD_UNMANAGED = 0x00000002, // RVA field - CORINFO_FLG_FIELD_FINAL = 0x00000004, - CORINFO_FLG_FIELD_STATIC_IN_HEAP = 0x00000008, // See code:#StaticFields. This static field is in the GC heap as a boxed object - CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN = 0x00000010, // Field can be returned safely (has GC heap lifetime) - CORINFO_FLG_FIELD_INITCLASS = 0x00000020, // initClass has to be called before accessing the field - CORINFO_FLG_FIELD_PROTECTED = 0x00000040, - } - - public unsafe struct CORINFO_FIELD_INFO - { - public CORINFO_FIELD_ACCESSOR fieldAccessor; - public CORINFO_FIELD_FLAGS fieldFlags; - - // Helper to use if the field access requires it - public CorInfoHelpFunc helper; - - // Field offset if there is one - public uint offset; - - public CorInfoType fieldType; - public CORINFO_CLASS_STRUCT_* structType; //possibly null - - //See CORINFO_CALL_INFO.accessAllowed - public CorInfoIsAccessAllowedResult accessAllowed; - public CORINFO_HELPER_DESC accessCalloutHelper; - - // Used by Ready-to-Run - public CORINFO_CONST_LOOKUP fieldLookup; - }; - - // System V struct passing - // The Classification types are described in the ABI spec at http://www.x86-64.org/documentation/abi.pdf - public enum SystemVClassificationType : byte - { - SystemVClassificationTypeUnknown = 0, - SystemVClassificationTypeStruct = 1, - SystemVClassificationTypeNoClass = 2, - SystemVClassificationTypeMemory = 3, - SystemVClassificationTypeInteger = 4, - SystemVClassificationTypeIntegerReference = 5, - SystemVClassificationTypeIntegerByRef = 6, - SystemVClassificationTypeSSE = 7, - // SystemVClassificationTypeSSEUp = Unused, // Not supported by the CLR. - // SystemVClassificationTypeX87 = Unused, // Not supported by the CLR. - // SystemVClassificationTypeX87Up = Unused, // Not supported by the CLR. - // SystemVClassificationTypeComplexX87 = Unused, // Not supported by the CLR. - - // Internal flags - never returned outside of the classification implementation. - - // This value represents a very special type with two eightbytes. - // First ByRef, second Integer (platform int). - // The VM has a special Elem type for this type - ELEMENT_TYPE_TYPEDBYREF. - // This is the classification counterpart for that element type. It is used to detect - // the special TypedReference type and specialize its classification. - // This type is represented as a struct with two fields. The classification needs to do - // special handling of it since the source/methadata type of the fieds is IntPtr. - // The VM changes the first to ByRef. The second is left as IntPtr (TYP_I_IMPL really). The classification needs to match this and - // special handling is warranted (similar thing is done in the getGCLayout function for this type). - SystemVClassificationTypeTypedReference = 8, - SystemVClassificationTypeMAX = 9 - }; - - public struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR - { - public const int CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS = 2; - public const int CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS = 16; - - public const int SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES = 8; // Size of an eightbyte in bytes. - public const int SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT = 16; // Maximum number of fields in struct passed in registers - - public byte _passedInRegisters; - // Whether the struct is passable/passed (this includes struct returning) in registers. - public bool passedInRegisters { get { return _passedInRegisters != 0; } set { _passedInRegisters = value ? (byte)1 : (byte)0; } } - - // Number of eightbytes for this struct. - public byte eightByteCount; - - // The eightbytes type classification. - public SystemVClassificationType eightByteClassifications0; - public SystemVClassificationType eightByteClassifications1; - - // The size of the eightbytes (an eightbyte could include padding. This represents the no padding size of the eightbyte). - public byte eightByteSizes0; - public byte eightByteSizes1; - - // The start offset of the eightbytes (in bytes). - public byte eightByteOffsets0; - public byte eightByteOffsets1; - }; - - // DEBUGGER DATA - public enum MappingTypes - { - NO_MAPPING = -1, // -- The IL offset corresponds to no source code (such as EH step blocks). - PROLOG = -2, // -- The IL offset indicates a prolog - EPILOG = -3 // -- The IL offset indicates an epilog - } - - public enum BoundaryTypes - { - NO_BOUNDARIES = 0x00, // No implicit boundaries - STACK_EMPTY_BOUNDARIES = 0x01, // Boundary whenever the IL evaluation stack is empty - NOP_BOUNDARIES = 0x02, // Before every CEE_NOP instruction - CALL_SITE_BOUNDARIES = 0x04, // Before every CEE_CALL, CEE_CALLVIRT, etc instruction - - // Set of boundaries that debugger should always reasonably ask the JIT for. - DEFAULT_BOUNDARIES = STACK_EMPTY_BOUNDARIES | NOP_BOUNDARIES | CALL_SITE_BOUNDARIES - } - - // Note that SourceTypes can be OR'd together - it's possible that - // a sequence point will also be a stack_empty point, and/or a call site. - // The debugger will check to see if a boundary offset's source field & - // SEQUENCE_POINT is true to determine if the boundary is a sequence point. - [Flags] - public enum SourceTypes - { - SOURCE_TYPE_INVALID = 0x00, // To indicate that nothing else applies - SEQUENCE_POINT = 0x01, // The debugger asked for it. - STACK_EMPTY = 0x02, // The stack is empty here - CALL_SITE = 0x04, // This is a call site. - NATIVE_END_OFFSET_UNKNOWN = 0x08, // Indicates a epilog endpoint - CALL_INSTRUCTION = 0x10 // The actual instruction of a call. - }; - - public struct OffsetMapping - { - public uint nativeOffset; - public uint ilOffset; - public SourceTypes source; // The debugger needs this so that - // we don't put Edit and Continue breakpoints where - // the stack isn't empty. We can put regular breakpoints - // there, though, so we need a way to discriminate - // between offsets. - }; - - public enum ILNum - { - VARARGS_HND_ILNUM = -1, // Value for the CORINFO_VARARGS_HANDLE varNumber - RETBUF_ILNUM = -2, // Pointer to the return-buffer - TYPECTXT_ILNUM = -3, // ParamTypeArg for CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG - - UNKNOWN_ILNUM = -4, // Unknown variable - - MAX_ILNUM = -4 // Sentinal value. This should be set to the largest magnitude value in the enum - // so that the compression routines know the enum's range. - }; - - public struct ILVarInfo - { - public uint startOffset; - public uint endOffset; - public uint varNumber; - }; - - // This enum is used for JIT to tell EE where this token comes from. - // E.g. Depending on different opcodes, we might allow/disallow certain types of tokens or - // return different types of handles (e.g. boxed vs. regular entrypoints) - public enum CorInfoTokenKind - { - CORINFO_TOKENKIND_Class = 0x01, - CORINFO_TOKENKIND_Method = 0x02, - CORINFO_TOKENKIND_Field = 0x04, - CORINFO_TOKENKIND_Mask = 0x07, - - // token comes from CEE_LDTOKEN - CORINFO_TOKENKIND_Ldtoken = 0x10 | CORINFO_TOKENKIND_Class | CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field, - - // token comes from CEE_CASTCLASS or CEE_ISINST - CORINFO_TOKENKIND_Casting = 0x20 | CORINFO_TOKENKIND_Class, - - // token comes from CEE_NEWARR - CORINFO_TOKENKIND_Newarr = 0x40 | CORINFO_TOKENKIND_Class, - - // token comes from CEE_BOX - CORINFO_TOKENKIND_Box = 0x80 | CORINFO_TOKENKIND_Class, - - // token comes from CEE_CONSTRAINED - CORINFO_TOKENKIND_Constrained = 0x100 | CORINFO_TOKENKIND_Class, - - // token comes from CEE_NEWOBJ - CORINFO_TOKENKIND_NewObj = 0x200 | CORINFO_TOKENKIND_Method, - - // token comes from CEE_LDVIRTFTN - CORINFO_TOKENKIND_Ldvirtftn = 0x400 | CORINFO_TOKENKIND_Method, - }; - - // These are error codes returned by CompileMethod - public enum CorJitResult - { - // Note that I dont use FACILITY_NULL for the facility number, - // we may want to get a 'real' facility number - CORJIT_OK = 0 /*NO_ERROR*/, - CORJIT_BADCODE = unchecked((int)0x80000001)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 1)*/, - CORJIT_OUTOFMEM = unchecked((int)0x80000002)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 2)*/, - CORJIT_INTERNALERROR = unchecked((int)0x80000003)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 3)*/, - CORJIT_SKIPPED = unchecked((int)0x80000004)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 4)*/, - CORJIT_RECOVERABLEERROR = unchecked((int)0x80000005)/*MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, 5)*/ - }; - - public enum TypeCompareState - { - MustNot = -1, // types are not equal - May = 0, // types may be equal (must test at runtime) - Must = 1, // type are equal - } - - public enum CorJitFlag : uint - { - CORJIT_FLAG_CALL_GETJITFLAGS = 0xffffffff, // Indicates that the JIT should retrieve flags in the form of a - // pointer to a CORJIT_FLAGS value via ICorJitInfo::getJitFlags(). - CORJIT_FLAG_SPEED_OPT = 0, - CORJIT_FLAG_SIZE_OPT = 1, - CORJIT_FLAG_DEBUG_CODE = 2, // generate "debuggable" code (no code-mangling optimizations) - CORJIT_FLAG_DEBUG_EnC = 3, // We are in Edit-n-Continue mode - CORJIT_FLAG_DEBUG_INFO = 4, // generate line and local-var info - CORJIT_FLAG_MIN_OPT = 5, // disable all jit optimizations (not necesarily debuggable code) - CORJIT_FLAG_GCPOLL_CALLS = 6, // Emit calls to JIT_POLLGC for thread suspension. - CORJIT_FLAG_MCJIT_BACKGROUND = 7, // Calling from multicore JIT background thread, do not call JitComplete - CORJIT_FLAG_UNUSED1 = 8, - CORJIT_FLAG_UNUSED2 = 9, - CORJIT_FLAG_UNUSED3 = 10, - CORJIT_FLAG_UNUSED4 = 11, - CORJIT_FLAG_UNUSED5 = 12, - CORJIT_FLAG_UNUSED6 = 13, - CORJIT_FLAG_USE_AVX = 14, - CORJIT_FLAG_USE_AVX2 = 15, - CORJIT_FLAG_USE_AVX_512 = 16, - CORJIT_FLAG_FEATURE_SIMD = 17, - CORJIT_FLAG_MAKEFINALCODE = 18, // Use the final code generator, i.e., not the interpreter. - CORJIT_FLAG_READYTORUN = 19, // Use version-resilient code generation - CORJIT_FLAG_PROF_ENTERLEAVE = 20, // Instrument prologues/epilogues - CORJIT_FLAG_PROF_REJIT_NOPS = 21, // Insert NOPs to ensure code is re-jitable - CORJIT_FLAG_PROF_NO_PINVOKE_INLINE = 22, // Disables PInvoke inlining - CORJIT_FLAG_SKIP_VERIFICATION = 23, // (lazy) skip verification - determined without doing a full resolve. See comment below - CORJIT_FLAG_PREJIT = 24, // jit or prejit is the execution engine. - CORJIT_FLAG_RELOC = 25, // Generate relocatable code - CORJIT_FLAG_IMPORT_ONLY = 26, // Only import the function - CORJIT_FLAG_IL_STUB = 27, // method is an IL stub - CORJIT_FLAG_PROCSPLIT = 28, // JIT should separate code into hot and cold sections - CORJIT_FLAG_BBINSTR = 29, // Collect basic block profile information - CORJIT_FLAG_BBOPT = 30, // Optimize method based on profile information - CORJIT_FLAG_FRAMED = 31, // All methods have an EBP frame - CORJIT_FLAG_ALIGN_LOOPS = 32, // add NOPs before loops to align them at 16 byte boundaries - CORJIT_FLAG_PUBLISH_SECRET_PARAM = 33, // JIT must place stub secret param into local 0. (used by IL stubs) - CORJIT_FLAG_GCPOLL_INLINE = 34, // JIT must inline calls to GCPoll when possible - CORJIT_FLAG_SAMPLING_JIT_BACKGROUND = 35, // JIT is being invoked as a result of stack sampling for hot methods in the background - CORJIT_FLAG_USE_PINVOKE_HELPERS = 36, // The JIT should use the PINVOKE_{BEGIN,END} helpers instead of emitting inline transitions - CORJIT_FLAG_REVERSE_PINVOKE = 37, // The JIT should insert REVERSE_PINVOKE_{ENTER,EXIT} helpers into method prolog/epilog - CORJIT_FLAG_DESKTOP_QUIRKS = 38, // The JIT should generate desktop-quirk-compatible code - CORJIT_FLAG_TIER0 = 39, // This is the initial tier for tiered compilation which should generate code as quickly as possible - CORJIT_FLAG_TIER1 = 40, // This is the final tier (for now) for tiered compilation which should generate high quality code - CORJIT_FLAG_RELATIVE_CODE_RELOCS = 41, // JIT should generate PC-relative address computations instead of EE relocation records - CORJIT_FLAG_NO_INLINING = 42, // JIT should not inline any called method into this method - -#region ARM64 - CORJIT_FLAG_HAS_ARM64_AES = 43, // ID_AA64ISAR0_EL1.AES is 1 or better - CORJIT_FLAG_HAS_ARM64_ATOMICS = 44, // ID_AA64ISAR0_EL1.Atomic is 2 or better - CORJIT_FLAG_HAS_ARM64_CRC32 = 45, // ID_AA64ISAR0_EL1.CRC32 is 1 or better - CORJIT_FLAG_HAS_ARM64_DCPOP = 46, // ID_AA64ISAR1_EL1.DPB is 1 or better - CORJIT_FLAG_HAS_ARM64_DP = 47, // ID_AA64ISAR0_EL1.DP is 1 or better - CORJIT_FLAG_HAS_ARM64_FCMA = 48, // ID_AA64ISAR1_EL1.FCMA is 1 or better - CORJIT_FLAG_HAS_ARM64_FP = 49, // ID_AA64PFR0_EL1.FP is 0 or better - CORJIT_FLAG_HAS_ARM64_FP16 = 50, // ID_AA64PFR0_EL1.FP is 1 or better - CORJIT_FLAG_HAS_ARM64_JSCVT = 51, // ID_AA64ISAR1_EL1.JSCVT is 1 or better - CORJIT_FLAG_HAS_ARM64_LRCPC = 52, // ID_AA64ISAR1_EL1.LRCPC is 1 or better - CORJIT_FLAG_HAS_ARM64_PMULL = 53, // ID_AA64ISAR0_EL1.AES is 2 or better - CORJIT_FLAG_HAS_ARM64_SHA1 = 54, // ID_AA64ISAR0_EL1.SHA1 is 1 or better - CORJIT_FLAG_HAS_ARM64_SHA256 = 55, // ID_AA64ISAR0_EL1.SHA2 is 1 or better - CORJIT_FLAG_HAS_ARM64_SHA512 = 56, // ID_AA64ISAR0_EL1.SHA2 is 2 or better - CORJIT_FLAG_HAS_ARM64_SHA3 = 57, // ID_AA64ISAR0_EL1.SHA3 is 1 or better - CORJIT_FLAG_HAS_ARM64_SIMD = 58, // ID_AA64PFR0_EL1.AdvSIMD is 0 or better - CORJIT_FLAG_HAS_ARM64_SIMD_V81 = 59, // ID_AA64ISAR0_EL1.RDM is 1 or better - CORJIT_FLAG_HAS_ARM64_SIMD_FP16 = 60, // ID_AA64PFR0_EL1.AdvSIMD is 1 or better - CORJIT_FLAG_HAS_ARM64_SM3 = 61, // ID_AA64ISAR0_EL1.SM3 is 1 or better - CORJIT_FLAG_HAS_ARM64_SM4 = 62, // ID_AA64ISAR0_EL1.SM4 is 1 or better - CORJIT_FLAG_HAS_ARM64_SVE = 63, // ID_AA64PFR0_EL1.SVE is 1 or better -#endregion - -#region x86/x64 - CORJIT_FLAG_USE_SSE3 = 43, - CORJIT_FLAG_USE_SSSE3 = 44, - CORJIT_FLAG_USE_SSE41 = 45, - CORJIT_FLAG_USE_SSE42 = 46, - CORJIT_FLAG_USE_AES = 47, - CORJIT_FLAG_USE_BMI1 = 48, - CORJIT_FLAG_USE_BMI2 = 49, - CORJIT_FLAG_USE_FMA = 50, - CORJIT_FLAG_USE_LZCNT = 51, - CORJIT_FLAG_USE_PCLMULQDQ = 52, - CORJIT_FLAG_USE_POPCNT = 53, -#endregion - } - - public struct CORJIT_FLAGS - { - private UInt64 _corJitFlags; - - public void Reset() - { - _corJitFlags = 0; - } - - public void Set(CorJitFlag flag) - { - _corJitFlags |= 1UL << (int)flag; - } - - public void Clear(CorJitFlag flag) - { - _corJitFlags &= ~(1UL << (int)flag); - } - - public bool IsSet(CorJitFlag flag) - { - return (_corJitFlags & (1UL << (int)flag)) != 0; - } - - public void Add(ref CORJIT_FLAGS other) - { - _corJitFlags |= other._corJitFlags; - } - - public void Remove(ref CORJIT_FLAGS other) - { - _corJitFlags &= ~other._corJitFlags; - } - - public bool IsEmpty() - { - return _corJitFlags == 0; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/JitConfigProvider.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/JitConfigProvider.cs deleted file mode 100644 index 0e73be8bf6a..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/JitConfigProvider.cs +++ /dev/null @@ -1,137 +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 System.Collections.Generic; -using System.Runtime.InteropServices; - -using NumberStyles = System.Globalization.NumberStyles; - -namespace Internal.JitInterface -{ - public sealed class JitConfigProvider - { - private CorJitFlag[] _jitFlags; - private Dictionary _config = new Dictionary(StringComparer.OrdinalIgnoreCase); - private object _keepAlive; // Keeps callback delegates alive - - public IntPtr UnmanagedInstance - { - get; - } - - public string JitPath - { - get; - } - - public IEnumerable Flags => _jitFlags; - - /// - /// Creates a new instance of . - /// - /// A collection of JIT compiler flags. - /// A collection of parameter name/value pairs. - /// A path to the JIT library to be used (may be null). - public JitConfigProvider(IEnumerable jitFlags, IEnumerable> parameters, string jitPath = null) - { - ArrayBuilder jitFlagBuilder = new ArrayBuilder(); - foreach (CorJitFlag jitFlag in jitFlags) - { - jitFlagBuilder.Add(jitFlag); - } - _jitFlags = jitFlagBuilder.ToArray(); - - foreach (var param in parameters) - { - _config[param.Key] = param.Value; - } - - JitPath = jitPath; - UnmanagedInstance = CreateUnmanagedInstance(); - } - - public bool HasFlag(CorJitFlag flag) - { - foreach (CorJitFlag definedFlag in _jitFlags) - if (definedFlag == flag) - return true; - - return false; - } - - public int GetIntConfigValue(string name, int defaultValue) - { - // Note: Parse the string as hex - string stringValue; - int intValue; - if (_config.TryGetValue(name, out stringValue) && - Int32.TryParse(stringValue, NumberStyles.AllowHexSpecifier, null, out intValue)) - { - return intValue; - } - - return defaultValue; - } - - public string GetStringConfigValue(string name) - { - string stringValue; - if (_config.TryGetValue(name, out stringValue)) - { - return stringValue; - } - - return String.Empty; - } - - #region Unmanaged instance - - private unsafe IntPtr CreateUnmanagedInstance() - { - // TODO: this potentially leaks memory, but since we only expect to have one per compilation, - // it shouldn't matter... - - const int numCallbacks = 2; - - IntPtr* callbacks = (IntPtr*)Marshal.AllocCoTaskMem(sizeof(IntPtr) * numCallbacks); - object[] delegates = new object[numCallbacks]; - - var d0 = new __getIntConfigValue(getIntConfigValue); - callbacks[0] = Marshal.GetFunctionPointerForDelegate(d0); - delegates[0] = d0; - - var d1 = new __getStringConfigValue(getStringConfigValue); - callbacks[1] = Marshal.GetFunctionPointerForDelegate(d1); - delegates[1] = d1; - - _keepAlive = delegates; - IntPtr instance = Marshal.AllocCoTaskMem(sizeof(IntPtr)); - *(IntPtr**)instance = callbacks; - - return instance; - } - - [UnmanagedFunctionPointer(default(CallingConvention))] - private unsafe delegate int __getIntConfigValue(IntPtr thisHandle, [MarshalAs(UnmanagedType.LPWStr)] string name, int defaultValue); - private unsafe int getIntConfigValue(IntPtr thisHandle, string name, int defaultValue) - { - return GetIntConfigValue(name, defaultValue); - } - - [UnmanagedFunctionPointer(default(CallingConvention))] - private unsafe delegate int __getStringConfigValue(IntPtr thisHandle, [MarshalAs(UnmanagedType.LPWStr)] string name, char* retBuffer, int retBufferLength); - private unsafe int getStringConfigValue(IntPtr thisHandle, string name, char* retBuffer, int retBufferLength) - { - string result = GetStringConfigValue(name); - - for (int i = 0; i < Math.Min(retBufferLength, result.Length); i++) - retBuffer[i] = result[i]; - - return result.Length; - } - - #endregion - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/MemoryHelper.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/MemoryHelper.cs deleted file mode 100644 index a9647f37fa7..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/MemoryHelper.cs +++ /dev/null @@ -1,20 +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; - -namespace Internal.JitInterface -{ - internal static unsafe class MemoryHelper - { - public static void FillMemory(byte* dest, byte fill, int count) - { - for (; count > 0; count--) - { - *dest = fill; - dest++; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/SystemVStructClassificator.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/SystemVStructClassificator.cs deleted file mode 100644 index fe7f13deaef..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/SystemVStructClassificator.cs +++ /dev/null @@ -1,607 +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 System.Collections.Generic; -using System.Diagnostics; -using ILCompiler; -using Internal.TypeSystem; - -namespace Internal.JitInterface -{ - using static SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR; - using static SystemVClassificationType; - - internal class SystemVStructClassificator - { - private Dictionary _classificationCache = new Dictionary(); - - private struct SystemVStructRegisterPassingHelper - { - internal SystemVStructRegisterPassingHelper(int totalStructSize) - { - StructSize = totalStructSize; - EightByteCount = 0; - InEmbeddedStruct = false; - CurrentUniqueOffsetField = 0; - LargestFieldOffset = -1; - - EightByteClassifications = new SystemVClassificationType[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; - EightByteSizes = new int[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; - EightByteOffsets = new int[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; - - FieldClassifications = new SystemVClassificationType[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; - FieldSizes = new int[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; - FieldOffsets = new int[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; - - for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++) - { - EightByteClassifications[i] = SystemVClassificationTypeNoClass; - EightByteSizes[i] = 0; - EightByteOffsets[i] = 0; - } - - // Initialize the work arrays - for (int i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++) - { - FieldClassifications[i] = SystemVClassificationTypeNoClass; - FieldSizes[i] = 0; - FieldOffsets[i] = 0; - } - } - - // Input state. - public int StructSize; - - // These fields are the output; these are what is computed by the classification algorithm. - public int EightByteCount; - public SystemVClassificationType[] EightByteClassifications; - public int[] EightByteSizes; - public int[] EightByteOffsets; - - // Helper members to track state. - public bool InEmbeddedStruct; - public int CurrentUniqueOffsetField; // A virtual field that could encompass many overlapping fields. - public int LargestFieldOffset; - public SystemVClassificationType[] FieldClassifications; - public int[] FieldSizes; - public int[] FieldOffsets; - }; - - private class FieldEnumerator - { - internal static IEnumerable GetInstanceFields(TypeDesc typeDesc, bool isFixedBuffer, int numIntroducedFields) - { - foreach (FieldDesc field in typeDesc.GetFields()) - { - if (field.IsStatic) - continue; - - if (isFixedBuffer) - { - for (int i = 0; i < numIntroducedFields; i++) - { - yield return field; - } - break; - } - else - { - yield return field; - } - } - } - } - - public unsafe bool getSystemVAmd64PassStructInRegisterDescriptor(TypeDesc typeDesc, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) - { - structPassInRegDescPtr->passedInRegisters = false; - - int typeSize = typeDesc.GetElementSize().AsInt; - if (typeDesc.IsValueType && (typeSize <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)) - { - Debug.Assert((TypeDef2SystemVClassification(typeDesc) == SystemVClassificationTypeStruct) || - (TypeDef2SystemVClassification(typeDesc) == SystemVClassificationTypeTypedReference)); - - if (_classificationCache.TryGetValue(typeDesc, out SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR descriptor)) - { - *structPassInRegDescPtr = descriptor; - } - else - { - SystemVStructRegisterPassingHelper helper = new SystemVStructRegisterPassingHelper(typeSize); - bool canPassInRegisters = ClassifyEightBytes(typeDesc, ref helper, 0); - if (canPassInRegisters) - { - structPassInRegDescPtr->passedInRegisters = canPassInRegisters; - structPassInRegDescPtr->eightByteCount = (byte)helper.EightByteCount; - Debug.Assert(structPassInRegDescPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS); - - structPassInRegDescPtr->eightByteClassifications0 = helper.EightByteClassifications[0]; - structPassInRegDescPtr->eightByteSizes0 = (byte)helper.EightByteSizes[0]; - structPassInRegDescPtr->eightByteOffsets0 = (byte)helper.EightByteOffsets[0]; - - structPassInRegDescPtr->eightByteClassifications1 = helper.EightByteClassifications[1]; - structPassInRegDescPtr->eightByteSizes1 = (byte)helper.EightByteSizes[1]; - structPassInRegDescPtr->eightByteOffsets1 = (byte)helper.EightByteOffsets[1]; - } - - _classificationCache.Add(typeDesc, *structPassInRegDescPtr); - } - } - - return true; - } - - private static SystemVClassificationType TypeDef2SystemVClassification(TypeDesc typeDesc) - { - if (typeDesc.IsWellKnownType(WellKnownType.TypedReference)) - { - // There is no category representing typed reference - return SystemVClassificationTypeTypedReference; - } - - switch (typeDesc.Category) - { - case TypeFlags.Boolean: - case TypeFlags.Char: - case TypeFlags.SByte: - case TypeFlags.Byte: - case TypeFlags.Int16: - case TypeFlags.UInt16: - case TypeFlags.Int32: - case TypeFlags.UInt32: - case TypeFlags.Int64: - case TypeFlags.UInt64: - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - case TypeFlags.Enum: - case TypeFlags.Pointer: - case TypeFlags.FunctionPointer: - return SystemVClassificationTypeInteger; - case TypeFlags.Single: - case TypeFlags.Double: - return SystemVClassificationTypeSSE; - case TypeFlags.ValueType: - case TypeFlags.Nullable: - return SystemVClassificationTypeStruct; - case TypeFlags.Class: - case TypeFlags.Interface: - case TypeFlags.Array: - case TypeFlags.SzArray: - return SystemVClassificationTypeIntegerReference; - case TypeFlags.ByRef: - return SystemVClassificationTypeIntegerByRef; - case TypeFlags.GenericParameter: - case TypeFlags.SignatureTypeVariable: - case TypeFlags.SignatureMethodVariable: - Debug.Assert(false, $"Type {typeDesc} with unexpected category {typeDesc.Category}"); - return SystemVClassificationTypeUnknown; - default: - return SystemVClassificationTypeUnknown; - } - } - - // If we have a field classification already, but there is a union, we must merge the classification type of the field. Returns the - // new, merged classification type. - static SystemVClassificationType ReClassifyField(SystemVClassificationType originalClassification, SystemVClassificationType newFieldClassification) - { - Debug.Assert((newFieldClassification == SystemVClassificationTypeInteger) || - (newFieldClassification == SystemVClassificationTypeIntegerReference) || - (newFieldClassification == SystemVClassificationTypeIntegerByRef) || - (newFieldClassification == SystemVClassificationTypeSSE)); - - switch (newFieldClassification) - { - case SystemVClassificationTypeInteger: - // Integer overrides everything; the resulting classification is Integer. Can't merge Integer and IntegerReference. - Debug.Assert((originalClassification == SystemVClassificationTypeInteger) || - (originalClassification == SystemVClassificationTypeSSE)); - - return SystemVClassificationTypeInteger; - - case SystemVClassificationTypeSSE: - // If the old and new classifications are both SSE, then the merge is SSE, otherwise it will be integer. Can't merge SSE and IntegerReference. - Debug.Assert((originalClassification == SystemVClassificationTypeInteger) || - (originalClassification == SystemVClassificationTypeSSE)); - - if (originalClassification == SystemVClassificationTypeSSE) - { - return SystemVClassificationTypeSSE; - } - else - { - return SystemVClassificationTypeInteger; - } - - case SystemVClassificationTypeIntegerReference: - // IntegerReference can only merge with IntegerReference. - Debug.Assert(originalClassification == SystemVClassificationTypeIntegerReference); - return SystemVClassificationTypeIntegerReference; - - case SystemVClassificationTypeIntegerByRef: - // IntegerByReference can only merge with IntegerByReference. - Debug.Assert(originalClassification == SystemVClassificationTypeIntegerByRef); - return SystemVClassificationTypeIntegerByRef; - - default: - Debug.Assert(false); // Unexpected type. - return SystemVClassificationTypeUnknown; - } - } - - /// - /// Returns 'true' if the struct is passed in registers, 'false' otherwise. - /// - private static bool ClassifyEightBytes(TypeDesc typeDesc, - ref SystemVStructRegisterPassingHelper helper, - int startOffsetOfStruct) - { - FieldDesc firstField = null; - int numIntroducedFields = 0; - foreach (FieldDesc field in typeDesc.GetFields()) - { - if (!field.IsStatic) - { - if (firstField == null) - { - firstField = field; - } - numIntroducedFields++; - } - } - - if (numIntroducedFields == 0) - { - return false; - } - - // The SIMD Intrinsic types are meant to be handled specially and should not be passed as struct registers - if (typeDesc.IsIntrinsic) - { - InstantiatedType instantiatedType = typeDesc as InstantiatedType; - if (instantiatedType != null) - { - if (VectorFieldLayoutAlgorithm.IsVectorType(instantiatedType) || - VectorFieldLayoutAlgorithm.IsVectorOfTType(instantiatedType)) - { - return false; - } - } - } - - MetadataType mdType = typeDesc as MetadataType; - Debug.Assert(mdType != null); - - TypeDesc firstFieldElementType = firstField.FieldType; - int firstFieldSize = firstFieldElementType.GetElementSize().AsInt; - - // A fixed buffer type is always a value type that has exactly one value type field at offset 0 - // and who's size is an exact multiple of the size of the field. - // It is possible that we catch a false positive with this check, but that chance is extremely slim - // and the user can always change their structure to something more descriptive of what they want - // instead of adding additional padding at the end of a one-field structure. - // We do this check here to save looking up the FixedBufferAttribute when loading the field - // from metadata. - bool isFixedBuffer = numIntroducedFields == 1 - && firstFieldElementType.IsValueType - && firstField.Offset.AsInt == 0 - && mdType.HasLayout() - && ((typeDesc.GetElementSize().AsInt % firstFieldSize) == 0); - - if (isFixedBuffer) - { - numIntroducedFields = typeDesc.GetElementSize().AsInt / firstFieldSize; - } - - int fieldIndex = 0; - foreach (FieldDesc field in FieldEnumerator.GetInstanceFields(typeDesc, isFixedBuffer, numIntroducedFields)) - { - Debug.Assert(fieldIndex < numIntroducedFields); - - int fieldOffset = isFixedBuffer ? fieldIndex * firstFieldSize : field.Offset.AsInt; - int normalizedFieldOffset = fieldOffset + startOffsetOfStruct; - - int fieldSize = field.FieldType.GetElementSize().AsInt; - - // The field can't span past the end of the struct. - if ((normalizedFieldOffset + fieldSize) > helper.StructSize) - { - Debug.Assert(false, "Invalid struct size. The size of fields and overall size don't agree"); - return false; - } - - SystemVClassificationType fieldClassificationType; - if (typeDesc.IsByReferenceOfT) - { - // ByReference is a special type whose single IntPtr field holds a by-ref potentially interior pointer to GC - // memory, so classify its field as such - Debug.Assert(numIntroducedFields == 1); - Debug.Assert(field.FieldType.IsWellKnownType(WellKnownType.IntPtr)); - - fieldClassificationType = SystemVClassificationTypeIntegerByRef; - } - else - { - fieldClassificationType = TypeDef2SystemVClassification(field.FieldType); - } - - if (fieldClassificationType == SystemVClassificationTypeStruct) - { - bool inEmbeddedStructPrev = helper.InEmbeddedStruct; - helper.InEmbeddedStruct = true; - - bool structRet = false; - structRet = ClassifyEightBytes(field.FieldType, ref helper, normalizedFieldOffset); - - helper.InEmbeddedStruct = inEmbeddedStructPrev; - - if (!structRet) - { - // If the nested struct says not to enregister, there's no need to continue analyzing at this level. Just return do not enregister. - return false; - } - - continue; - } - - if (fieldClassificationType == SystemVClassificationTypeTypedReference || - TypeDef2SystemVClassification(typeDesc) == SystemVClassificationTypeTypedReference) - { - // The TypedReference is a very special type. - // In source/metadata it has two fields - Type and Value and both are defined of type IntPtr. - // When the VM creates a layout of the type it changes the type of the Value to ByRef type and the - // type of the Type field is left to IntPtr (TYPE_I internally - native int type.) - // This requires a special treatment of this type. The code below handles the both fields (and this entire type). - - for (int i = 0; i < 2; i++) - { - fieldSize = 8; - fieldOffset = (i == 0 ? 0 : 8); - normalizedFieldOffset = fieldOffset + startOffsetOfStruct; - fieldClassificationType = (i == 0 ? SystemVClassificationTypeIntegerByRef : SystemVClassificationTypeInteger); - if ((normalizedFieldOffset % fieldSize) != 0) - { - // The spec requires that struct values on the stack from register passed fields expects - // those fields to be at their natural alignment. - return false; - } - - helper.LargestFieldOffset = (int)normalizedFieldOffset; - - // Set the data for a new field. - - // The new field classification must not have been initialized yet. - Debug.Assert(helper.FieldClassifications[helper.CurrentUniqueOffsetField] == SystemVClassificationTypeNoClass); - - helper.FieldClassifications[helper.CurrentUniqueOffsetField] = fieldClassificationType; - helper.FieldSizes[helper.CurrentUniqueOffsetField] = fieldSize; - helper.FieldOffsets[helper.CurrentUniqueOffsetField] = normalizedFieldOffset; - - helper.CurrentUniqueOffsetField++; - } - - // Both fields of the special TypedReference struct are handled. - // Done classifying the System.TypedReference struct fields. - break; - } - - if ((normalizedFieldOffset % fieldSize) != 0) - { - // The spec requires that struct values on the stack from register passed fields expects - // those fields to be at their natural alignment. - return false; - } - - if (normalizedFieldOffset <= helper.LargestFieldOffset) - { - // Find the field corresponding to this offset and update the size if needed. - // If the offset matches a previously encountered offset, update the classification and field size. - int i; - for (i = helper.CurrentUniqueOffsetField - 1; i >= 0; i--) - { - if (helper.FieldOffsets[i] == normalizedFieldOffset) - { - if (fieldSize > helper.FieldSizes[i]) - { - helper.FieldSizes[i] = fieldSize; - } - - helper.FieldClassifications[i] = ReClassifyField(helper.FieldClassifications[i], fieldClassificationType); - - break; - } - } - - if (i >= 0) - { - // The proper size of the union set of fields has been set above; continue to the next field. - continue; - } - } - else - { - helper.LargestFieldOffset = (int)normalizedFieldOffset; - } - - // Set the data for a new field. - - // The new field classification must not have been initialized yet. - Debug.Assert(helper.FieldClassifications[helper.CurrentUniqueOffsetField] == SystemVClassificationTypeNoClass); - - // There are only a few field classifications that are allowed. - Debug.Assert((fieldClassificationType == SystemVClassificationTypeInteger) || - (fieldClassificationType == SystemVClassificationTypeIntegerReference) || - (fieldClassificationType == SystemVClassificationTypeIntegerByRef) || - (fieldClassificationType == SystemVClassificationTypeSSE)); - - helper.FieldClassifications[helper.CurrentUniqueOffsetField] = fieldClassificationType; - helper.FieldSizes[helper.CurrentUniqueOffsetField] = fieldSize; - helper.FieldOffsets[helper.CurrentUniqueOffsetField] = normalizedFieldOffset; - - Debug.Assert(helper.CurrentUniqueOffsetField < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT); - helper.CurrentUniqueOffsetField++; - - fieldIndex++; - } - - AssignClassifiedEightByteTypes(ref helper); - - return true; - } - - // Assigns the classification types to the array with eightbyte types. - private static void AssignClassifiedEightByteTypes(ref SystemVStructRegisterPassingHelper helper) - { - const int CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS = CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS * SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; - Debug.Assert(CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS == SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT); - - if (!helper.InEmbeddedStruct) - { - int largestFieldOffset = helper.LargestFieldOffset; - Debug.Assert(largestFieldOffset != -1); - - // We're at the top level of the recursion, and we're done looking at the fields. - // Now sort the fields by offset and set the output data. - - int[] sortedFieldOrder = new int[CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS]; - for (int i = 0; i < CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS; i++) - { - sortedFieldOrder[i] = -1; - } - - int numFields = helper.CurrentUniqueOffsetField; - for (int i = 0; i < numFields; i++) - { - Debug.Assert(helper.FieldOffsets[i] < CLR_SYSTEMV_MAX_BYTES_TO_PASS_IN_REGISTERS); - Debug.Assert(sortedFieldOrder[helper.FieldOffsets[i]] == -1); // we haven't seen this field offset yet. - sortedFieldOrder[helper.FieldOffsets[i]] = i; - } - - // Calculate the eightbytes and their types. - - int lastFieldOrdinal = sortedFieldOrder[largestFieldOffset]; - int offsetAfterLastFieldByte = largestFieldOffset + helper.FieldSizes[lastFieldOrdinal]; - SystemVClassificationType lastFieldClassification = helper.FieldClassifications[lastFieldOrdinal]; - - int usedEightBytes = 0; - int accumulatedSizeForEightBytes = 0; - bool foundFieldInEightByte = false; - for (int offset = 0; offset < helper.StructSize; offset++) - { - SystemVClassificationType fieldClassificationType; - int fieldSize = 0; - - int ordinal = sortedFieldOrder[offset]; - if (ordinal == -1) - { - if (offset < accumulatedSizeForEightBytes) - { - // We're within a field and there is not an overlapping field that starts here. - // There's no work we need to do, so go to the next loop iteration. - continue; - } - - // If there is no field that starts as this offset and we are not within another field, - // treat its contents as padding. - // Any padding that follows the last field receives the same classification as the - // last field; padding between fields receives the NO_CLASS classification as per - // the SysV ABI spec. - fieldSize = 1; - fieldClassificationType = offset < offsetAfterLastFieldByte ? SystemVClassificationTypeNoClass : lastFieldClassification; - } - else - { - foundFieldInEightByte = true; - fieldSize = helper.FieldSizes[ordinal]; - Debug.Assert(fieldSize > 0); - - fieldClassificationType = helper.FieldClassifications[ordinal]; - Debug.Assert(fieldClassificationType != SystemVClassificationTypeMemory && fieldClassificationType != SystemVClassificationTypeUnknown); - } - - int fieldStartEightByte = offset / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; - int fieldEndEightByte = (offset + fieldSize - 1) / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; - - Debug.Assert(fieldEndEightByte < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS); - - usedEightBytes = Math.Max(usedEightBytes, fieldEndEightByte + 1); - - for (int currentFieldEightByte = fieldStartEightByte; currentFieldEightByte <= fieldEndEightByte; currentFieldEightByte++) - { - if (helper.EightByteClassifications[currentFieldEightByte] == fieldClassificationType) - { - // Do nothing. The eight-byte already has this classification. - } - else if (helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeNoClass) - { - helper.EightByteClassifications[currentFieldEightByte] = fieldClassificationType; - } - else if ((helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeInteger) || - (fieldClassificationType == SystemVClassificationTypeInteger)) - { - Debug.Assert((fieldClassificationType != SystemVClassificationTypeIntegerReference) && - (fieldClassificationType != SystemVClassificationTypeIntegerByRef)); - - helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeInteger; - } - else if ((helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeIntegerReference) || - (fieldClassificationType == SystemVClassificationTypeIntegerReference)) - { - helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeIntegerReference; - } - else if ((helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeIntegerByRef) || - (fieldClassificationType == SystemVClassificationTypeIntegerByRef)) - { - helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeIntegerByRef; - } - else - { - helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeSSE; - } - } - - if ((offset + 1) % SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES == 0) // If we just finished checking the last byte of an eightbyte - { - if (!foundFieldInEightByte) - { - // If we didn't find a field in an eight-byte (i.e. there are no explicit offsets that start a field in this eightbyte) - // then the classification of this eightbyte might be NoClass. We can't hand a classification of NoClass to the JIT - // so set the class to Integer (as though the struct has a char[8] padding) if the class is NoClass. - if (helper.EightByteClassifications[offset / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES] == SystemVClassificationTypeNoClass) - { - helper.EightByteClassifications[offset / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES] = SystemVClassificationTypeInteger; - } - } - - foundFieldInEightByte = false; - } - - accumulatedSizeForEightBytes = Math.Max(accumulatedSizeForEightBytes, offset + fieldSize); - } - - for (int currentEightByte = 0; currentEightByte < usedEightBytes; currentEightByte++) - { - int eightByteSize = accumulatedSizeForEightBytes < (SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES * (currentEightByte + 1)) - ? accumulatedSizeForEightBytes % SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES - : SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; - - // Save data for this eightbyte. - helper.EightByteSizes[currentEightByte] = eightByteSize; - helper.EightByteOffsets[currentEightByte] = currentEightByte * SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES; - } - - helper.EightByteCount = usedEightBytes; - - Debug.Assert(helper.EightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS); - -#if DEBUG - for (int i = 0; i < helper.EightByteCount; i++) - { - Debug.Assert(helper.EightByteClassifications[i] != SystemVClassificationTypeNoClass); - } -#endif // DEBUG - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/Program.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/Program.cs deleted file mode 100644 index 499014b2337..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/Program.cs +++ /dev/null @@ -1,509 +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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.IO; -using System.Diagnostics; - -namespace Thunkerator -{ - // Parse type replacement section for normal types - // Parse type replacement section for return value types - - public static class StringExtensions - { - public static string Canonicalize(this string current) - { - string untrimmed = ""; - while (untrimmed != current) - { - untrimmed = current; - current = current.Replace(" *", "*"); - current = current.Replace("* ", "*"); - current = current.Replace(" ,", ","); - current = current.Replace(", ", ","); - current = current.Replace(" ", " "); - current = current.Replace("\t", " "); - } - - return current.Trim(); - } - } - - class TypeReplacement - { - public TypeReplacement(string line) - { - string[] typenames = line.Split(','); - if ((typenames.Length < 1) || (typenames.Length > 3)) - { - throw new Exception("Wrong number of type name entries"); - } - ThunkTypeName = typenames[0].Canonicalize(); - - if (typenames.Length > 1 && !string.IsNullOrWhiteSpace(typenames[1])) - { - ManagedTypeName = typenames[1].Canonicalize(); - } - else - { - ManagedTypeName = ThunkTypeName; - } - - if (typenames.Length > 2) - { - NativeTypeName = typenames[2].Canonicalize(); - } - else - { - NativeTypeName = ThunkTypeName; - } - } - public readonly string ThunkTypeName; - public readonly string NativeTypeName; - public readonly string ManagedTypeName; - } - - class Parameter - { - public Parameter(string name, TypeReplacement type) - { - Type = type; - Name = name; - if (name.StartsWith("*")) - throw new Exception("Names not allowed to start with *"); - } - - public readonly string Name; - public readonly TypeReplacement Type; - } - - class FunctionDecl - { - public FunctionDecl(string line, Dictionary ThunkReturnTypes, Dictionary ThunkTypes) - { - if (line.Contains("[ManualNativeWrapper]")) - { - ManualNativeWrapper = true; - line = line.Replace("[ManualNativeWrapper]", string.Empty); - } - - if (line.Contains("[ReturnAsParm]")) - { - ReturnAsParm = true; - line = line.Replace("[ReturnAsParm]", string.Empty); - } - - int indexOfOpenParen = line.IndexOf('('); - int indexOfCloseParen = line.IndexOf(')'); - string returnTypeAndFunctionName = line.Substring(0, indexOfOpenParen).Canonicalize(); - int indexOfLastWhitespaceInReturnTypeAndFunctionName = returnTypeAndFunctionName.LastIndexOfAny(new char[] { ' ', '*' }); - FunctionName = returnTypeAndFunctionName.Substring(indexOfLastWhitespaceInReturnTypeAndFunctionName + 1).Canonicalize(); - if (FunctionName.StartsWith("*")) - throw new Exception("Names not allowed to start with *"); - string returnType = returnTypeAndFunctionName.Substring(0, indexOfLastWhitespaceInReturnTypeAndFunctionName + 1).Canonicalize(); - - if (!ThunkReturnTypes.TryGetValue(returnType, out ReturnType)) - { - throw new Exception(String.Format("Type {0} unknown", returnType)); - } - - string parameterList = line.Substring(indexOfOpenParen + 1, indexOfCloseParen - indexOfOpenParen - 1).Canonicalize(); - string[] parametersString = parameterList.Length == 0 ? new string[0] : parameterList.Split(','); - List parameters = new List(); - - foreach (string parameterString in parametersString) - { - int indexOfLastWhitespaceInParameter = parameterString.LastIndexOfAny(new char[] { ' ', '*' }); - string paramName = parameterString.Substring(indexOfLastWhitespaceInParameter + 1).Canonicalize(); - string paramType = parameterString.Substring(0, indexOfLastWhitespaceInParameter + 1).Canonicalize(); - TypeReplacement tr; - if (!ThunkTypes.TryGetValue(paramType, out tr)) - { - throw new Exception(String.Format("Type {0} unknown", paramType)); - } - parameters.Add(new Parameter(paramName, tr)); - } - - Parameters = parameters.ToArray(); - } - - public readonly string FunctionName; - public readonly TypeReplacement ReturnType; - public readonly Parameter[] Parameters; - public readonly bool ManualNativeWrapper = false; - public readonly bool ReturnAsParm = false; - } - - class Program - { - enum ParseMode - { - RETURNTYPES, - NORMALTYPES, - FUNCTIONS, - IFDEFING - } - static IEnumerable ParseInput(TextReader tr) - { - Dictionary ThunkReturnTypes = new Dictionary(); - Dictionary ThunkTypes = new Dictionary(); - ParseMode currentParseMode = ParseMode.FUNCTIONS; - ParseMode oldParseMode = ParseMode.FUNCTIONS; - List functions = new List(); - int currentLineIndex = 1; - for (string currentLine = tr.ReadLine(); currentLine != null; currentLine = tr.ReadLine(), currentLineIndex++) - { - try - { - if (currentLine.Length == 0) - { - continue; // Its an empty line, ignore - } - - if (currentLine[0] == ';') - { - continue; // Its a comment - } - - if (currentLine == "RETURNTYPES") - { - currentParseMode = ParseMode.RETURNTYPES; - continue; - } - if (currentLine == "NORMALTYPES") - { - currentParseMode = ParseMode.NORMALTYPES; - continue; - } - if (currentLine == "FUNCTIONS") - { - currentParseMode = ParseMode.FUNCTIONS; - continue; - } - - if (currentLine == "#endif") - { - currentParseMode = oldParseMode; - continue; - } - - if (currentLine.StartsWith("#if")) - { - oldParseMode = currentParseMode; - currentParseMode = ParseMode.IFDEFING; - } - - if (currentParseMode == ParseMode.IFDEFING) - { - continue; - } - - switch (currentParseMode) - { - case ParseMode.NORMALTYPES: - case ParseMode.RETURNTYPES: - TypeReplacement t = new TypeReplacement(currentLine); - if (currentParseMode == ParseMode.NORMALTYPES) - { - ThunkTypes.Add(t.ThunkTypeName, t); - ThunkReturnTypes.Add(t.ThunkTypeName, t); - } - if (currentParseMode == ParseMode.RETURNTYPES) - { - ThunkReturnTypes[t.ThunkTypeName] = t; - } - break; - - case ParseMode.FUNCTIONS: - functions.Add(new FunctionDecl(currentLine, ThunkReturnTypes, ThunkTypes)); - break; - } - } - catch (Exception e) - { - Console.Error.WriteLine("Error parsing line {0} : {1}", currentLineIndex, e.Message); - } - } - - return functions.AsReadOnly(); - } - - static void WriteManagedThunkInterface(TextWriter tr, IEnumerable functionData) - { - // Write header - tr.Write(@" -// 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. - -// DO NOT EDIT THIS FILE! It IS AUTOGENERATED -using System; -using System.Runtime.InteropServices; - -namespace Internal.JitInterface -{ - unsafe partial class CorInfoImpl - { -"); - -#if false - foreach (FunctionDecl decl in functionData) - { - string returnType = decl.ReturnType.ManagedTypeName; - - tr.Write(" " + returnType + " " + decl.FunctionName + "("); - tr.Write("IntPtr thisHandle"); - foreach (Parameter param in decl.Parameters) - { - tr.Write(", "); - tr.Write(param.Type.ManagedTypeName + " " + param.Name); - } - tr.WriteLine(")"); - tr.WriteLine(" { throw new NotImplementedException(); }"); - } - tr.WriteLine(); -#endif - - foreach (FunctionDecl decl in functionData) - { - tr.WriteLine(" [UnmanagedFunctionPointerAttribute(default(CallingConvention))]"); - - string returnType = decl.ReturnAsParm ? "void" : decl.ReturnType.ManagedTypeName; - int marshalAs = returnType.LastIndexOf(']'); - string returnTypeWithDelegate = returnType.Insert((marshalAs != -1) ? (marshalAs + 1) : 0, "delegate "); - - tr.Write(" " + returnTypeWithDelegate + " " + "__" + decl.FunctionName + "("); - tr.Write("IntPtr _this"); - tr.Write(", IntPtr* ppException"); - if (decl.ReturnAsParm) - { - tr.Write(", out " + decl.ReturnType.ManagedTypeName + " _return"); - } - foreach (Parameter param in decl.Parameters) - { - tr.Write(", "); - tr.Write(param.Type.ManagedTypeName + " " + param.Name); - } - tr.WriteLine(");"); - } - tr.WriteLine(); - - foreach (FunctionDecl decl in functionData) - { - string returnType = decl.ReturnAsParm ? "void" : decl.ReturnType.ManagedTypeName; - int marshalAs = returnType.LastIndexOf(']'); - string returnTypeWithStatic = returnType.Insert((marshalAs != -1) ? (marshalAs + 1) : 0, "static "); - - tr.Write(" " + returnTypeWithStatic + " " + "_" + decl.FunctionName + "("); - tr.Write("IntPtr thisHandle"); - tr.Write(", IntPtr* ppException"); - if (decl.ReturnAsParm) - { - tr.Write(", out " + decl.ReturnType.ManagedTypeName + " _return"); - } - foreach (Parameter param in decl.Parameters) - { - tr.Write(", "); - tr.Write(param.Type.ManagedTypeName + " " + param.Name); - } - tr.Write(@") - { - var _this = GetThis(thisHandle); - try - { -"); - bool isVoid = decl.ReturnAsParm || decl.ReturnType.ManagedTypeName == "void"; - tr.Write(" " + (isVoid ? "" : "return ") + "_this." + decl.FunctionName + "("); - bool isFirst = true; - if (decl.ReturnAsParm) - { - tr.Write("out _return"); - isFirst = false; - } - foreach (Parameter param in decl.Parameters) - { - if (isFirst) - { - isFirst = false; - } - else - { - tr.Write(", "); - } - - if (param.Type.ManagedTypeName.Contains("ref ")) - { - tr.Write("ref "); - } - tr.Write(param.Name); - } - tr.Write(");"); - tr.Write(@" - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); -"); - if (!isVoid) - { - string retunTypeWithoutMarshalAs = marshalAs == -1 ? returnType : returnType.Substring(marshalAs + 1); - tr.WriteLine(" return default(" + retunTypeWithoutMarshalAs + ");"); - } - else if (decl.ReturnAsParm) - { - tr.WriteLine(" _return = default(" + decl.ReturnType.ManagedTypeName + ");"); - } - tr.WriteLine(@" }"); - tr.WriteLine(" }"); - tr.WriteLine(); - } - - int total = functionData.Count(); - tr.WriteLine(@" - static IntPtr GetUnmanagedCallbacks(out Object keepAlive) - { - IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * " + total + @"); - Object[] delegates = new Object[" + total + @"]; -"); - - int index = 0; - foreach (FunctionDecl decl in functionData) - { - tr.WriteLine(" var d" + index + " = new " + "__" + decl.FunctionName + "(" + "_" + decl.FunctionName + ");"); - tr.WriteLine(" callbacks[" + index + "] = Marshal.GetFunctionPointerForDelegate(d" + index + ");"); - tr.WriteLine(" delegates[" + index + "] = d" + index + ";"); - index++; - } - - tr.WriteLine(@" - keepAlive = delegates; - return (IntPtr)callbacks; - } - } -} -"); - } - - static void WriteNativeWrapperInterface(TextWriter tw, IEnumerable functionData) - { - tw.Write(@" -// 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. - -// DO NOT EDIT THIS FILE! It IS AUTOGENERATED -#include ""corinfoexception.h"" - -struct CORINFO_LOOKUP_KIND; - -struct JitInterfaceCallbacks -{ -"); - - foreach (FunctionDecl decl in functionData) - { - string returnType = decl.ReturnAsParm ? "void" : decl.ReturnType.NativeTypeName; - tw.Write(" " + returnType + " (* " + decl.FunctionName + ")("); - tw.Write("void * thisHandle"); - tw.Write(", CorInfoException** ppException"); - if (decl.ReturnAsParm) - { - tw.Write(", " + decl.ReturnType.NativeTypeName + "* _return"); - } - foreach (Parameter param in decl.Parameters) - { - tw.Write(", "); - tw.Write(param.Type.NativeTypeName + " " + param.Name); - } - tw.WriteLine(");"); - } - - tw.Write(@" -}; - -class JitInterfaceWrapper -{ - void * _thisHandle; - JitInterfaceCallbacks * _callbacks; - -public: - JitInterfaceWrapper(void * thisHandle, void ** callbacks) - : _thisHandle(thisHandle), _callbacks((JitInterfaceCallbacks *)callbacks) - { - } - -"); - - foreach (FunctionDecl decl in functionData) - { - tw.Write(" virtual " + decl.ReturnType.NativeTypeName + " " + decl.FunctionName + "("); - bool isFirst = true; - foreach (Parameter param in decl.Parameters) - { - if (isFirst) - { - isFirst = false; - } - else - { - tw.Write(", "); - } - tw.Write(param.Type.NativeTypeName + " " + param.Name); - } - tw.Write(')'); - - if (decl.ManualNativeWrapper) - { - tw.WriteLine(';'); - continue; - } - tw.Write(@" - { - CorInfoException* pException = nullptr; - "); - if (decl.ReturnType.NativeTypeName != "void") - { - tw.Write(decl.ReturnType.NativeTypeName + " _ret = "); - } - tw.Write("_callbacks->" + decl.FunctionName + "(_thisHandle, &pException"); - foreach (Parameter param in decl.Parameters) - { - tw.Write(", " + param.Name); - } - tw.Write(@"); - if (pException != nullptr) - throw pException; -"); - if (decl.ReturnType.NativeTypeName != "void") - { - tw.WriteLine(" return _ret;"); - } - tw.WriteLine(" }"); - tw.WriteLine(); - } - - tw.WriteLine("};"); - } - - static void Main(string[] args) - { - IEnumerable functions = ParseInput(new StreamReader(args[0])); - using (TextWriter tw = new StreamWriter(args[1])) - { - Console.WriteLine("Generating {0}", args[1]); - WriteManagedThunkInterface(tw, functions); - } - using (TextWriter tw = new StreamWriter(args[2])) - { - Console.WriteLine("Generating {0}", args[2]); - WriteNativeWrapperInterface(tw, functions); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj b/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj deleted file mode 100644 index 958d2f1daae..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/ThunkInput.txt deleted file mode 100644 index fffc0de16cd..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ /dev/null @@ -1,344 +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. -; -; Thunk generator input file for generating the thunks from the C++ version of the -; jit interface to COM, into managed, and from COM to C++. -; -; The format of this file is as follows. -; There are NORMALTYPES, RETURNTYPES, and FUNCTIONS regions -; In the NORMALTYPES/RETURNTYPES region, each type is described. If a type is -; described in the NORMALTYPES section, but isn't described in the RETURNTYPES section -; then the NORMALTYPES description can be used for a return value. -; -; TYPES have three fields -; ThunkDescriptionType,ManagedType,NativeType -; If either ManagedType or NativeType are missing, then that form is replaced with ThunkDescriptionType. -; This feature allows reduction in type for enums and other types where the same type can be used in managed an native -; -; Specification of a custom native type is done to allow multiple translations of the same native type to managed. -; i.e. -; REFIntPointer,ref int *,int** -; and -; PointerToIntPointer,int**,int** -; -; Following the TYPES sections, there is the FUNCTIONS section -; Each function that is to be part of the interface is written here. The format is basically the C++ format -; without support for inline comments or sal annotations. -; -; Also, note that an empty line is ignored, and a line that begins with a ; is ignored. -; -; If the boilerplate around the individual functions needs adjustment, edit the thunk generator source code, and -; rebuild with rebuildthunkgen.cmd in the the ThunkGenerator subdir, then rebuildthunks.cmd -; If this file is editted, rebuild with rebuildthunks.cmd -- DO NOT RUN from within a razzle window. -; -NORMALTYPES -void -IEEMemoryManager*,void*,void* -LPVOID,void*,void* -void* -const void *,void* -HRESULT,,int -SIZE_T*,void*,size_t* -int -INT,int,int -INT32,int,int -UINT32,uint,unsigned int -ULONG32,uint,unsigned int -ULONG,uint,unsigned int -DWORD,uint,unsigned int -unsigned,uint -unsigned int, uint -size_t,UIntPtr -SIZE_T,UIntPtr,size_t -WORD,ushort,unsigned short -BOOL,[MarshalAs(UnmanagedType.Bool)]bool,int -bool,[MarshalAs(UnmanagedType.I1)]bool -const char *,byte* -mdMethodDef,mdToken,unsigned int -mdToken,,unsigned int -BYTE*,byte*,unsigned char* -GSCookie*,IntPtr*,void* -GSCookie**,IntPtr**,void** - -BOOL*,[MarshalAs(UnmanagedType.Bool)] ref bool,int* -bool*,[MarshalAs(UnmanagedType.U1)] ref bool -BoolStar,byte*,bool* -UINT32*,ref uint,unsigned int* -ULONG*,ref uint,unsigned long* -void **,ref void* -VOIDSTARSTAR,void **,void ** -ULONG32*,ref uint,unsigned int* -LONG*,int*,long* -char*,byte* -const char**,byte** -WCHAR**,short**,wchar_t** -LPCSTR,byte*,const char* -LPWSTR,short*,wchar_t* -LPCWSTR,short*,const wchar_t* -wchar_t*,short* -const wchar_t*,String - -DWORD**,ref uint*,unsigned int** -unsigned*,ref uint -DWORD*,ref uint,unsigned int* -CORJIT_FLAGS*,ref CORJIT_FLAGS,void* -CORINFO_CONST_LOOKUP*,ref CORINFO_CONST_LOOKUP,void* -CORINFO_LOOKUP*,ref CORINFO_LOOKUP,void* -CORINFO_LOOKUP_KIND*,ref CORINFO_LOOKUP_KIND,void* -CORINFO_EH_CLAUSE*,ref CORINFO_EH_CLAUSE,void* -const CORINFO_EH_CLAUSE*,ref CORINFO_EH_CLAUSE,void* -CORINFO_SIG_INFO*,,void* -CORINFO_RESOLVED_TOKEN*,ref CORINFO_RESOLVED_TOKEN,void* -CORINFO_RESOLVED_TOKEN_PTR,CORINFO_RESOLVED_TOKEN*,void* -CORINFO_EE_INFO*,ref CORINFO_EE_INFO,void* -CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT,void* -CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO*,void* -CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO*,void* -CORINFO_CALL_INFO*,CORINFO_CALL_INFO*,void* -DelegateCtorArgs*,ref DelegateCtorArgs,void* -ICorDynamicInfo*,IntPtr,void* -va_list,IntPtr -CORINFO_HELPER_DESC*,ref CORINFO_HELPER_DESC,void* -const CORINFO_HELPER_DESC*,ref CORINFO_HELPER_DESC,const void* -int*,ref int -unsigned int*,ref uint - -CORINFO_JUST_MY_CODE_HANDLE**,ref CORINFO_JUST_MY_CODE_HANDLE_*,void** - -ICorJitInfo::BlockCounts**,ref BlockCounts*,void** - -; Enums -CorInfoCanSkipVerificationResult,,int -CorInfoClassId,,int -CorInfoHelperTailCallSpecialHandling,,int -CorInfoHelpFunc,,int -CorInfoInitClassResult,,int -CorInfoInlineTypeCheck,,int -CorInfoInlineTypeCheckSource,,int -CorInfoInline,,int -CorInfoInstantiationVerification,,int -CorInfoIntrinsics,,int -CorInfoIsAccessAllowedResult,,int -CorInfoMethodRuntimeFlags,,int -CorInfoTailCall,,int -CorInfoType,,int -CorInfoTypeWithMod,,int -CorInfoUnmanagedCallConv,,int -InfoAccessType,,int -CORINFO_LOOKUP_KIND -CORINFO_ACCESS_FLAGS,,int -CORINFO_CALLINFO_FLAGS,,int -CorJitAllocMemFlag,,int -CorJitFuncKind,,int -CorJitResult,,int -TypeCompareState,,int - -; Handle types -CORINFO_MODULE_HANDLE,CORINFO_MODULE_STRUCT_*,void* -CORINFO_METHOD_HANDLE,CORINFO_METHOD_STRUCT_*,void* -CORINFO_FIELD_HANDLE,CORINFO_FIELD_STRUCT_*,void* -CORINFO_CLASS_HANDLE,CORINFO_CLASS_STRUCT_*,void* -CORINFO_ASSEMBLY_HANDLE,CORINFO_ASSEMBLY_STRUCT_*,void* -CORINFO_JUST_MY_CODE_HANDLE,CORINFO_JUST_MY_CODE_HANDLE_*,void* -CORINFO_MODULE_HANDLE*,CORINFO_MODULE_STRUCT_**,void* -CORINFO_CLASS_HANDLE*,CORINFO_CLASS_STRUCT_**,void* -CORINFO_ARG_LIST_HANDLE,CORINFO_ARG_LIST_STRUCT_*,void* -CORINFO_VARARGS_HANDLE,IntPtr,void* -CORINFO_CONTEXT_HANDLE,CORINFO_CONTEXT_STRUCT*,void* -SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*,SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*,void* - -ICorDebugInfo::OffsetMapping*,OffsetMapping*,void* -ICorDebugInfo::ILVarInfo**,ILVarInfo**,void* -ICorDebugInfo::NativeVarInfo*,NativeVarInfo*,void* -ICorDebugInfo::BoundaryTypes*,BoundaryTypes*,void* - -struct _EXCEPTION_POINTERS*,_EXCEPTION_POINTERS*,void* - -RETURNTYPES -BOOL,[return: MarshalAs(UnmanagedType.Bool)]bool,int -bool,[return: MarshalAs(UnmanagedType.I1)]bool -LPCWSTR,[return: MarshalAs(UnmanagedType.LPWStr)]string,const wchar_t* -; NOTE in managed SIZE_T is an enum that is 64bits in size, and returning one of those causing mcg to do the wrong thing. -size_t,byte*,size_t - -FUNCTIONS - DWORD getMethodAttribs( CORINFO_METHOD_HANDLE ftn ); - void setMethodAttribs( CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs ); - void getMethodSig( CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO *sig, CORINFO_CLASS_HANDLE memberParent ); - bool getMethodInfo( CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info ); - CorInfoInline canInline( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd, DWORD* pRestrictions ); - void reportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, CorInfoInline inlineResult, const char * reason); - bool canTailCall( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE declaredCalleeHnd, CORINFO_METHOD_HANDLE exactCalleeHnd, bool fIsTailPrefix ); - void reportTailCallDecision(CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, const char * reason); - void getEHinfo( CORINFO_METHOD_HANDLE ftn, unsigned EHnumber, CORINFO_EH_CLAUSE* clause ); - CORINFO_CLASS_HANDLE getMethodClass( CORINFO_METHOD_HANDLE method ); - CORINFO_MODULE_HANDLE getMethodModule( CORINFO_METHOD_HANDLE method ); - void getMethodVTableOffset( CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, unsigned* offsetAfterIndirection, bool* isRelative); - CORINFO_METHOD_HANDLE resolveVirtualMethod( CORINFO_METHOD_HANDLE virtualMethod, CORINFO_CLASS_HANDLE implementingClass, CORINFO_CONTEXT_HANDLE ownerType); - CORINFO_METHOD_HANDLE getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, BoolStar requiresInstMethodTableArg); - CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType); - void expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_GENERICHANDLE_RESULT * pResult); - CorInfoIntrinsics getIntrinsicID( CORINFO_METHOD_HANDLE method , BoolStar pMustExpand); - bool isIntrinsicType( 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 ); - CorInfoInstantiationVerification isInstantiationOfVerifiedGeneric( CORINFO_METHOD_HANDLE method ); - void initConstraintsForVerification( CORINFO_METHOD_HANDLE method, BOOL *pfHasCircularClassConstraints, BOOL *pfHasCircularMethodConstraint ); - CorInfoCanSkipVerificationResult canSkipMethodVerification( CORINFO_METHOD_HANDLE ftnHandle ); - void methodMustBeLoadedBeforeCodeIsRun( CORINFO_METHOD_HANDLE method ); - CORINFO_METHOD_HANDLE mapMethodDeclToMethodImpl( CORINFO_METHOD_HANDLE method ); - void getGSCookie( GSCookie * pCookieVal, GSCookie ** ppCookieVal ); - void resolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken); - void tryResolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken); - void findSig( CORINFO_MODULE_HANDLE module, unsigned sigTOK, CORINFO_CONTEXT_HANDLE context, CORINFO_SIG_INFO *sig ); - void findCallSiteSig( CORINFO_MODULE_HANDLE module,unsigned methTOK, CORINFO_CONTEXT_HANDLE context, CORINFO_SIG_INFO *sig) - CORINFO_CLASS_HANDLE getTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken) - CorInfoCanSkipVerificationResult canSkipVerification(CORINFO_MODULE_HANDLE module) - BOOL isValidToken(CORINFO_MODULE_HANDLE module, unsigned metaTOK) - BOOL isValidStringRef(CORINFO_MODULE_HANDLE module, unsigned metaTOK) - BOOL shouldEnforceCallvirtRestriction(CORINFO_MODULE_HANDLE scope) - CorInfoType asCorInfoType(CORINFO_CLASS_HANDLE cls) - const char* getClassName(CORINFO_CLASS_HANDLE cls) - const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char **namespaceName) - CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) - int appendClassName(WCHAR** ppBuf, int* pnBufLen, CORINFO_CLASS_HANDLE cls, BOOL fNamespace, BOOL fFullInst, BOOL fAssembly) - BOOL isValueClass(CORINFO_CLASS_HANDLE cls) - CorInfoInlineTypeCheck canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source) - BOOL canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls) - DWORD getClassAttribs(CORINFO_CLASS_HANDLE cls) - BOOL isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE cls) - CORINFO_MODULE_HANDLE getClassModule(CORINFO_CLASS_HANDLE cls) - CORINFO_ASSEMBLY_HANDLE getModuleAssembly(CORINFO_MODULE_HANDLE mod) - const char* getAssemblyName(CORINFO_ASSEMBLY_HANDLE assem) - void* LongLifetimeMalloc(size_t sz) - void LongLifetimeFree(void* obj) - size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection) - unsigned getClassSize(CORINFO_CLASS_HANDLE cls) - unsigned getHeapClassSize(CORINFO_CLASS_HANDLE cls) - BOOL canAllocateOnStack(CORINFO_CLASS_HANDLE cls) - unsigned getClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, BOOL fDoubleAlignHint) - unsigned getClassGClayout(CORINFO_CLASS_HANDLE cls, BYTE* gcPtrs) - unsigned getClassNumInstanceFields(CORINFO_CLASS_HANDLE cls) - CORINFO_FIELD_HANDLE getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num) - BOOL checkMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, BOOL fOptional) - CorInfoHelpFunc getNewHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, BoolStar pHasSideEffects) - CorInfoHelpFunc getNewArrHelper(CORINFO_CLASS_HANDLE arrayCls) - CorInfoHelpFunc getCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing) - CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd) - CorInfoHelpFunc getSecurityPrologHelper(CORINFO_METHOD_HANDLE ftn) - CORINFO_CLASS_HANDLE getTypeForBox(CORINFO_CLASS_HANDLE cls) - CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_HANDLE cls) - CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_HANDLE cls) - bool getReadyToRunHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pGenericLookupKind, CorInfoHelpFunc id, CORINFO_CONST_LOOKUP *pLookup) - void getReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN * pTargetMethod, CORINFO_CLASS_HANDLE delegateType, CORINFO_LOOKUP *pLookup) - const char* getHelperName(CorInfoHelpFunc helpFunc) - CorInfoInitClassResult initClass(CORINFO_FIELD_HANDLE field, CORINFO_METHOD_HANDLE method, CORINFO_CONTEXT_HANDLE context, BOOL speculative) - void classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE cls) - CORINFO_CLASS_HANDLE getBuiltinClass(CorInfoClassId classId) - CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) - CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls) - BOOL canCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent) - BOOL areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) - TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) - TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) - CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) - BOOL isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) - CORINFO_CLASS_HANDLE getParentType(CORINFO_CLASS_HANDLE cls) - CorInfoType getChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet) - BOOL satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls) - BOOL isSDArray(CORINFO_CLASS_HANDLE cls) - unsigned getArrayRank(CORINFO_CLASS_HANDLE cls) - void* getArrayInitializationData(CORINFO_FIELD_HANDLE field, DWORD size) - CorInfoIsAccessAllowedResult canAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_HELPER_DESC* pAccessHelper) - const char* getFieldName(CORINFO_FIELD_HANDLE ftn, const char** moduleName) - CORINFO_CLASS_HANDLE getFieldClass(CORINFO_FIELD_HANDLE field) - CorInfoType getFieldType(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType, CORINFO_CLASS_HANDLE memberParent) - unsigned getFieldOffset(CORINFO_FIELD_HANDLE field) - bool isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field) - void getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) - bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) - void getBoundaries(CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, DWORD** pILOffsets, ICorDebugInfo::BoundaryTypes* implictBoundaries) - void setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping* pMap) - void getVars(CORINFO_METHOD_HANDLE ftn, ULONG32* cVars, ICorDebugInfo::ILVarInfo** vars, bool* extendOthers) - void setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars) - void*allocateArray(ULONG cBytes); - void freeArray(void*array); - CORINFO_ARG_LIST_HANDLE getArgNext(CORINFO_ARG_LIST_HANDLE args); - CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args, CORINFO_CLASS_HANDLE* vcTypeRet); - CORINFO_CLASS_HANDLE getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args); - CorInfoType getHFAType(CORINFO_CLASS_HANDLE hClass); - HRESULT GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers); - ULONG GetErrorMessage(LPWSTR buffer, ULONG bufferLength); - [ManualNativeWrapper] int FilterException(struct _EXCEPTION_POINTERS* pExceptionPointers); - [ManualNativeWrapper] void HandleException(struct _EXCEPTION_POINTERS* pExceptionPointers); - void ThrowExceptionForJitResult(HRESULT result); - void ThrowExceptionForHelper(const CORINFO_HELPER_DESC* throwHelper); - [ManualNativeWrapper] bool runWithErrorTrap(void* function, void* parameter); - void getEEInfo(CORINFO_EE_INFO* pEEInfoOut); - LPCWSTR getJitTimeLogFilename(); - mdMethodDef getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod); - const char* getMethodName(CORINFO_METHOD_HANDLE ftn, const char **moduleName); - const char* getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, const char **className, const char **namespaceName, const char **enclosingClassName); - unsigned getMethodHash(CORINFO_METHOD_HANDLE ftn); - size_t findNameOfToken(CORINFO_MODULE_HANDLE moduleHandle,mdToken token, char * szFQName,size_t FQNameCapacity); - bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); - DWORD getThreadTLSIndex(void **ppIndirection); - const void * getInlinedCallFrameVptr(void **ppIndirection); - LONG * getAddrOfCaptureThreadGlobal(void **ppIndirection); - 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); - void* getMethodSync(CORINFO_METHOD_HANDLE ftn, void **ppIndirection); - CorInfoHelpFunc getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle); - CORINFO_MODULE_HANDLE embedModuleHandle(CORINFO_MODULE_HANDLE handle, void **ppIndirection); - CORINFO_CLASS_HANDLE embedClassHandle(CORINFO_CLASS_HANDLE handle, void **ppIndirection); - CORINFO_METHOD_HANDLE embedMethodHandle(CORINFO_METHOD_HANDLE handle, void **ppIndirection); - CORINFO_FIELD_HANDLE embedFieldHandle(CORINFO_FIELD_HANDLE handle, void **ppIndirection); - void embedGenericHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, BOOL fEmbedParent, CORINFO_GENERICHANDLE_RESULT * pResult); - [ManualNativeWrapper] [ReturnAsParm] CORINFO_LOOKUP_KIND getLocationOfThisType(CORINFO_METHOD_HANDLE context); - void* getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method, void **ppIndirection); - void* getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method, void **ppIndirection); - void getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP *pLookup); - LPVOID GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void ** ppIndirection); - bool canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig); - CORINFO_JUST_MY_CODE_HANDLE getJustMyCodeHandle(CORINFO_METHOD_HANDLE method, CORINFO_JUST_MY_CODE_HANDLE**ppIndirection); - void GetProfilingHandle(BOOL *pbHookFunction, void **pProfilerHandle, BOOL *pbIndirectedHandles); - void getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_RESOLVED_TOKEN_PTR pConstrainedResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO *pResult); - BOOL canAccessFamily(CORINFO_METHOD_HANDLE hCaller, CORINFO_CLASS_HANDLE hInstanceType); - BOOL isRIDClassDomainID(CORINFO_CLASS_HANDLE cls); - unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection); - void* getFieldAddress(CORINFO_FIELD_HANDLE field, VOIDSTARSTAR ppIndirection); - CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, BoolStar pIsSpeculative); - CORINFO_VARARGS_HANDLE getVarArgsHandle(CORINFO_SIG_INFO *pSig, void **ppIndirection); - bool canGetVarArgsHandle(CORINFO_SIG_INFO *pSig); - InfoAccessType constructStringLiteral(CORINFO_MODULE_HANDLE module, mdToken metaTok, void **ppValue); - InfoAccessType emptyStringLiteral(void **ppValue); - DWORD getFieldThreadLocalStoreID (CORINFO_FIELD_HANDLE field, void **ppIndirection); - void setOverride(ICorDynamicInfo *pOverride, CORINFO_METHOD_HANDLE currentMethod); - void addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom, CORINFO_MODULE_HANDLE moduleTo); - CORINFO_METHOD_HANDLE GetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE targetMethodHnd, DelegateCtorArgs * pCtorData); - void MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd); - void* getTailCallCopyArgsThunk (CORINFO_SIG_INFO *pSig, CorInfoHelperTailCallSpecialHandling flags); - bool convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool mustConvert); - [ManualNativeWrapper] IEEMemoryManager* getMemoryManager(); - void allocMem( ULONG hotCodeSize, ULONG coldCodeSize, ULONG roDataSize, ULONG xcptnsCount, CorJitAllocMemFlag flag, void** hotCodeBlock, void** coldCodeBlock, void** roDataBlock ); - void reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize) - void allocUnwindInfo(BYTE* pHotCode, BYTE* pColdCode, ULONG startOffset, ULONG endOffset, ULONG unwindSize, BYTE* pUnwindBlock, CorJitFuncKind funcKind) - void* allocGCInfo(size_t size) - void yieldExecution() - void setEHcount(unsigned cEH) - void setEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause) - BOOL logMsg(unsigned level, const char* fmt, va_list args) - int doAssert(const char* szFile, int iLine, const char* szExpr) - void reportFatalError(CorJitResult result) - HRESULT allocMethodBlockCounts(UINT32 count, ICorJitInfo::BlockCounts** pBlockCounts) - HRESULT getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, UINT32* pCount, ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns) - void recordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle) - void recordRelocation(void* location, void* target, WORD fRelocType, WORD slotNum, INT32 addlDelta) - WORD getRelocTypeHint(void* target) - void getModuleNativeEntryPointRange(void** pStart, void** pEnd) - DWORD getExpectedTargetArchitecture() - DWORD getJitFlags(CORJIT_FLAGS* flags, DWORD sizeInBytes) diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/gen.bat b/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/gen.bat deleted file mode 100644 index 2fec5117581..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/gen.bat +++ /dev/null @@ -1,2 +0,0 @@ -cd /d %~dp0 -dotnet run -- ThunkInput.txt ..\CorInfoBase.cs ..\..\..\jitinterface\jitinterface.h \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/gen.sh b/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/gen.sh deleted file mode 100755 index 3eb458d6200..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/ThunkGenerator/gen.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -cd "$(dirname ${BASH_SOURCE[0]})" -dotnet run -- ThunkInput.txt ../CorInfoBase.cs ../../../jitinterface/jitinterface.h diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/TypeString.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/TypeString.cs deleted file mode 100644 index 52a9dcfb957..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/TypeString.cs +++ /dev/null @@ -1,113 +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.Text; - -using Internal.TypeSystem; - -namespace Internal.JitInterface -{ - // This is a very rough equivalent of typestring.cpp in the CLR. - // There's way more rules to capture. Hopefully, we'll only ever need this in the code to recognize SIMD intrisics - // and we won't need to replicate all the details around escaping and such. - internal class TypeString : TypeNameFormatter - { - public static TypeString Instance { get; } = new TypeString(); - - public override void AppendName(StringBuilder sb, PointerType type) - { - AppendName(sb, type.ParameterType); - sb.Append('*'); - } - - public override void AppendName(StringBuilder sb, GenericParameterDesc type) - { - string prefix = type.Kind == GenericParameterKind.Type ? "!" : "!!"; - sb.Append(prefix); - sb.Append(type.Name); - } - - public override void AppendName(StringBuilder sb, SignatureTypeVariable type) - { - sb.Append("!"); - sb.Append(type.Index); - } - - public override void AppendName(StringBuilder sb, SignatureMethodVariable type) - { - sb.Append("!!"); - sb.Append(type.Index); - } - - public override void AppendName(StringBuilder sb, FunctionPointerType type) - { - MethodSignature signature = type.Signature; - - AppendName(sb, signature.ReturnType); - - sb.Append(" ("); - for (int i = 0; i < signature.Length; i++) - { - if (i > 0) - sb.Append(", "); - AppendName(sb, signature[i]); - } - - sb.Append(')'); - } - - public override void AppendName(StringBuilder sb, ByRefType type) - { - AppendName(sb, type.ParameterType); - sb.Append("&"); - } - - public override void AppendName(StringBuilder sb, ArrayType type) - { - AppendName(sb, type.ElementType); - sb.Append('['); - - int rank = type.Rank; - if (rank == 1 && type.IsMdArray) - sb.Append('*'); - else - sb.Append(',', type.Rank - 1); - - sb.Append(']'); - } - - protected override void AppendNameForInstantiatedType(StringBuilder sb, DefType type) - { - AppendName(sb, type.GetTypeDefinition()); - sb.Append('['); - - for (int i = 0; i < type.Instantiation.Length; i++) - { - if (i > 0) - sb.Append(", "); - AppendName(sb, type.Instantiation[i]); - } - - sb.Append(']'); - } - - protected override void AppendNameForNamespaceType(StringBuilder sb, DefType type) - { - string ns = type.Namespace; - if (ns.Length > 0) - { - sb.Append(ns); - sb.Append('.'); - } - sb.Append(type.Name); - } - - protected override void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType) - { - AppendName(sb, containingType); - sb.Append('+'); - sb.Append(nestedType.Name); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/JitInterface/UnboxingMethodDesc.cs b/src/coreclr/src/tools/crossgen2/Common/JitInterface/UnboxingMethodDesc.cs deleted file mode 100644 index 2710f163b03..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/JitInterface/UnboxingMethodDesc.cs +++ /dev/null @@ -1,108 +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 System.Collections.Generic; -using System.Diagnostics; -using Internal.TypeSystem; - -namespace Internal.JitInterface -{ - /// - /// Represents the unboxing entrypoint of a valuetype instance method. - /// This class is for internal purposes within the JitInterface. It's not expected - /// for it to escape the JitInterface. - /// - internal class UnboxingMethodDesc : MethodDelegator - { - private readonly UnboxingMethodDescFactory _factory; - - public MethodDesc Target => _wrappedMethod; - - public UnboxingMethodDesc(MethodDesc wrappedMethod, UnboxingMethodDescFactory factory) - : base(wrappedMethod) - { - Debug.Assert(wrappedMethod.OwningType.IsValueType); - Debug.Assert(!wrappedMethod.Signature.IsStatic); - _factory = factory; - } - - public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) - { - MethodDesc realCanonTarget = _wrappedMethod.GetCanonMethodTarget(kind); - if (realCanonTarget != _wrappedMethod) - return _factory.GetUnboxingMethod(realCanonTarget); - - return this; - } - - public override MethodDesc GetMethodDefinition() - { - MethodDesc realMethodDefinition = _wrappedMethod.GetMethodDefinition(); - if (realMethodDefinition != _wrappedMethod) - return _factory.GetUnboxingMethod(realMethodDefinition); - - return this; - } - - public override MethodDesc GetTypicalMethodDefinition() - { - MethodDesc realTypicalMethodDefinition = _wrappedMethod.GetTypicalMethodDefinition(); - if (realTypicalMethodDefinition != _wrappedMethod) - return _factory.GetUnboxingMethod(realTypicalMethodDefinition); - - return this; - } - - public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - MethodDesc realInstantiateSignature = _wrappedMethod.InstantiateSignature(typeInstantiation, methodInstantiation); - if (realInstantiateSignature != _wrappedMethod) - return _factory.GetUnboxingMethod(realInstantiateSignature); - - return this; - } - - public override string ToString() - { - return "Unboxing MethodDesc: " + _wrappedMethod.ToString(); - } - -#if !SUPPORT_JIT - protected override int ClassCode => throw new NotImplementedException(); - - protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) - { - throw new NotImplementedException(); - } -#endif - } - - internal class UnboxingMethodDescFactory : Dictionary - { - public UnboxingMethodDesc GetUnboxingMethod(MethodDesc method) - { - if (!TryGetValue(method, out UnboxingMethodDesc result)) - { - result = new UnboxingMethodDesc(method, this); - Add(method, result); - } - - return result; - } - } - - internal static class UnboxingMethodDescExtensions - { - public static bool IsUnboxingThunk(this MethodDesc method) - { - return method is UnboxingMethodDesc; - } - - public static MethodDesc GetUnboxedMethod(this MethodDesc method) - { - return ((UnboxingMethodDesc)method).Target; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/System/Collections/Generic/ArrayBuilder.cs b/src/coreclr/src/tools/crossgen2/Common/System/Collections/Generic/ArrayBuilder.cs deleted file mode 100644 index 07548eff7ff..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/System/Collections/Generic/ArrayBuilder.cs +++ /dev/null @@ -1,109 +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 Debug = System.Diagnostics.Debug; - -namespace System.Collections.Generic -{ - /// - /// Helper class for building lists that avoids unnecessary allocation - /// - internal struct ArrayBuilder - { - private T[] _items; - private int _count; - - public T[] ToArray() - { - if (_items == null) - return Array.Empty(); - if (_count != _items.Length) - Array.Resize(ref _items, _count); - return _items; - } - - public void Add(T item) - { - if (_items == null || _count == _items.Length) - Array.Resize(ref _items, 2 * _count + 1); - _items[_count++] = item; - } - - public void Append(T[] newItems) - { - Append(newItems, 0, newItems.Length); - } - - public void Append(T[] newItems, int offset, int length) - { - if (length == 0) - return; - - Debug.Assert(length > 0); - Debug.Assert(newItems.Length >= offset + length); - - EnsureCapacity(_count + length); - Array.Copy(newItems, offset, _items, _count, length); - _count += length; - } - - public void Append(ArrayBuilder newItems) - { - if (newItems.Count == 0) - return; - EnsureCapacity(_count + newItems.Count); - Array.Copy(newItems._items, 0, _items, _count, newItems.Count); - _count += newItems.Count; - } - - public void ZeroExtend(int numItems) - { - Debug.Assert(numItems >= 0); - EnsureCapacity(_count + numItems); - _count += numItems; - } - - public void EnsureCapacity(int requestedCapacity) - { - if (requestedCapacity > ((_items != null) ? _items.Length : 0)) - { - int newCount = Math.Max(2 * _count + 1, requestedCapacity); - Array.Resize(ref _items, newCount); - } - } - - public int Count - { - get - { - return _count; - } - } - - public T this[int index] - { - get - { - return _items[index]; - } - set - { - _items[index] = value; - } - } - - public bool Contains(T t) - { - for (int i = 0; i < _count; i++) - { - if (_items[i].Equals(t)) - { - return true; - } - } - - return false; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/System/FormattingHelpers.cs b/src/coreclr/src/tools/crossgen2/Common/System/FormattingHelpers.cs deleted file mode 100644 index de7a6370a0a..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/System/FormattingHelpers.cs +++ /dev/null @@ -1,21 +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.Globalization; - -namespace System -{ - internal static class FormattingHelpers - { - public static string ToStringInvariant(this T value) where T : IConvertible - { - return value.ToString(CultureInfo.InvariantCulture); - } - - public static string ToStringInvariant(this T value, string format) where T : IFormattable - { - return value.ToString(format, CultureInfo.InvariantCulture); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ArrayType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ArrayType.Canon.cs deleted file mode 100644 index 04bd817fa7d..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ArrayType.Canon.cs +++ /dev/null @@ -1,41 +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. - -namespace Internal.TypeSystem -{ - // Implements canonicalization for arrays - partial class ArrayType - { - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - TypeDesc paramTypeConverted = Context.ConvertToCanon(ParameterType, kind); - if (paramTypeConverted != ParameterType) - { - // Note: don't use the Rank property here, as that hides the difference - // between a single dimensional MD array and an SZArray. - return Context.GetArrayType(paramTypeConverted, _rank); - } - - return this; - } - } - - // Implements canonicalization for array methods - partial class ArrayMethod - { - public override bool IsCanonicalMethod(CanonicalFormKind policy) - { - return _owningType.IsCanonicalSubtype(policy); - } - - public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) - { - TypeDesc canonicalizedTypeOfTargetMethod = _owningType.ConvertToCanonForm(kind); - if (canonicalizedTypeOfTargetMethod == _owningType) - return this; - - return ((ArrayType)canonicalizedTypeOfTargetMethod).GetArrayMethod(_kind); - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ByRefType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ByRefType.Canon.cs deleted file mode 100644 index 921eb901487..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ByRefType.Canon.cs +++ /dev/null @@ -1,19 +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. - -namespace Internal.TypeSystem -{ - // Implements canonicalizing ByRefs - partial class ByRefType - { - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - TypeDesc paramTypeConverted = Context.ConvertToCanon(ParameterType, kind); - if (paramTypeConverted != ParameterType) - return Context.GetByRefType(paramTypeConverted); - - return this; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs deleted file mode 100644 index 3c4098cb4d0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs +++ /dev/null @@ -1,49 +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 System.Collections.Generic; - -using Internal.NativeFormat; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - internal sealed partial class CanonType - { - public override string DiagnosticName - { - get - { - return _Name; - } - } - public override string DiagnosticNamespace - { - get - { - return _Namespace; - } - } - } - - internal sealed partial class UniversalCanonType - { - public override string DiagnosticName - { - get - { - return _Name; - } - } - public override string DiagnosticNamespace - { - get - { - return _Namespace; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Interop.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Interop.cs deleted file mode 100644 index cca6403d0c0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Interop.cs +++ /dev/null @@ -1,11 +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. - -namespace Internal.TypeSystem -{ - partial class CanonBaseType - { - public override PInvokeStringFormat PInvokeStringFormat => default(PInvokeStringFormat); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Sorting.cs deleted file mode 100644 index 0848de283ce..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Sorting.cs +++ /dev/null @@ -1,29 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class CanonBaseType - { - protected internal sealed override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - // These should be singletons - Debug.Assert(this == other); - return 0; - } - } - - partial class CanonType - { - protected internal override int ClassCode => 46114331; - } - - partial class UniversalCanonType - { - protected internal override int ClassCode => 1687626054; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.cs deleted file mode 100644 index d84341b1540..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.cs +++ /dev/null @@ -1,280 +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 System.Collections.Generic; - -using Internal.NativeFormat; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// Type of canonicalization applied to a type - /// - public enum CanonicalFormKind - { - /// - /// Optimized for a particular set of instantiations (such as reference types) - /// - Specific, - - /// - /// Canonicalization that works for any type - /// - Universal, - - /// - /// Value used for lookup for Specific or Universal. Must not be used for canonicalizing. - /// - Any, - } - - /// - /// Base class for specialized and universal canon types - /// - public abstract partial class CanonBaseType : MetadataType - { - private TypeSystemContext _context; - - public CanonBaseType(TypeSystemContext context) - { - _context = context; - } - - public sealed override TypeSystemContext Context - { - get - { - return _context; - } - } - - protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() - { - return Array.Empty(); - } - - public override MetadataType MetadataBaseType => (MetadataType)BaseType; - - public override DefType ContainingType => null; - - public override DefType[] ExplicitlyImplementedInterfaces => Array.Empty(); - - public override bool IsAbstract => false; - - public override bool IsBeforeFieldInit => false; - - public override bool IsSequentialLayout => false; - - public override bool IsExplicitLayout => false; - - public override ModuleDesc Module => _context.CanonTypesModule; - - public override bool IsModuleType => false; - - public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name) - { - return null; - } - - public override ClassLayoutMetadata GetClassLayout() - { - return default(ClassLayoutMetadata); - } - - public override MetadataType GetNestedType(string name) - { - return null; - } - - public override IEnumerable GetNestedTypes() - { - return Array.Empty(); - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return false; - } - } - - /// - /// Type used for specific canonicalization (e.g. for reference types) - /// - internal sealed partial class CanonType : CanonBaseType - { - private const string _Namespace = "System"; - private const string _Name = "__Canon"; - public const string FullName = _Namespace + "." + _Name; - - private int _hashcode; - - public override string Namespace - { - get - { - return _Namespace; - } - } - - public override string Name - { - get - { - return _Name; - } - } - - public override bool IsSealed => false; - - public CanonType(TypeSystemContext context) - : base(context) - { - Initialize(); - } - - // Provides an extensibility hook for type system consumers that need to perform - // consumer-specific initialization. - partial void Initialize(); - - public override DefType BaseType - { - get - { - return Context.GetWellKnownType(WellKnownType.Object); - } - } - - public override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - return policy == CanonicalFormKind.Specific || - policy == CanonicalFormKind.Any; - } - - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - Debug.Assert(kind == CanonicalFormKind.Specific); - return this; - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = 0; - - if ((mask & TypeFlags.CategoryMask) != 0) - { - flags |= TypeFlags.Class; - } - - if ((mask & TypeFlags.HasGenericVarianceComputed) != 0) - { - flags |= TypeFlags.HasGenericVarianceComputed; - } - - flags |= TypeFlags.HasFinalizerComputed; - flags |= TypeFlags.AttributeCacheComputed; - - return flags; - } - - public override int GetHashCode() - { - if (_hashcode == 0) - { - _hashcode = TypeHashingAlgorithms.ComputeNameHashCode(FullName); - } - - return _hashcode; - } - } - - /// - /// Type that can be used for canonicalization of any type (including value types of unknown size) - /// - internal sealed partial class UniversalCanonType : CanonBaseType - { - private const string _Namespace = "System"; - private const string _Name = "__UniversalCanon"; - public const string FullName = _Namespace + "." + _Name; - - private int _hashcode; - - public override string Namespace - { - get - { - return _Namespace; - } - } - - public override string Name - { - get - { - return _Name; - } - } - - public override bool IsSealed => true; - - public UniversalCanonType(TypeSystemContext context) - : base(context) - { - Initialize(); - } - - // Provides an extensibility hook for type system consumers that need to perform - // consumer-specific initialization. - partial void Initialize(); - - public override DefType BaseType - { - get - { - // UniversalCanon is "a struct of indeterminate size and GC layout" - return Context.GetWellKnownType(WellKnownType.ValueType); - } - } - - public override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - return policy == CanonicalFormKind.Universal || - policy == CanonicalFormKind.Any; - } - - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - return this; - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = 0; - - if ((mask & TypeFlags.CategoryMask) != 0) - { - // Universally canonical type is reported as a variable-sized struct. - // It's the closest logical thing and avoids special casing around it. - flags |= TypeFlags.ValueType; - } - - flags |= TypeFlags.HasFinalizerComputed; - flags |= TypeFlags.AttributeCacheComputed; - - return flags; - } - - public override int GetHashCode() - { - if (_hashcode == 0) - { - _hashcode = TypeHashingAlgorithms.ComputeNameHashCode(FullName); - } - - return _hashcode; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/DefType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/DefType.Canon.cs deleted file mode 100644 index 75c03bb4601..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/DefType.Canon.cs +++ /dev/null @@ -1,15 +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. - -namespace Internal.TypeSystem -{ - // Implements canonicalization handling for TypeDefs - partial class DefType - { - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - return this; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/FunctionPointerType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/FunctionPointerType.Canon.cs deleted file mode 100644 index 1a64efeb7b1..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/FunctionPointerType.Canon.cs +++ /dev/null @@ -1,38 +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; - -namespace Internal.TypeSystem -{ - // Holds code for canonicalizing a function pointer type - partial class FunctionPointerType - { - public override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - if (_signature.ReturnType.IsCanonicalSubtype(policy)) - return true; - - for (int i = 0; i < _signature.Length; i++) - if (_signature[i].IsCanonicalSubtype(policy)) - return true; - - return false; - } - - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - MethodSignatureBuilder sigBuilder = new MethodSignatureBuilder(_signature); - sigBuilder.ReturnType = Context.ConvertToCanon(_signature.ReturnType, kind); - for (int i = 0; i < _signature.Length; i++) - sigBuilder[i] = Context.ConvertToCanon(_signature[i], kind); - - MethodSignature canonSignature = sigBuilder.ToSignature(); - if (canonSignature != _signature) - return Context.GetFunctionPointerType(canonSignature); - - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/GenericParameterDesc.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/GenericParameterDesc.Canon.cs deleted file mode 100644 index 59f1c731147..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/GenericParameterDesc.Canon.cs +++ /dev/null @@ -1,24 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Implements canonicalization of generic parameters - public partial class GenericParameterDesc - { - public sealed override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - Debug.Fail("IsCanonicalSubtype of an indefinite type"); - return false; - } - - protected sealed override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - Debug.Fail("ConvertToCanonFormImpl for an indefinite type"); - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/InstantiatedMethod.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/InstantiatedMethod.Canon.cs deleted file mode 100644 index 4e3e0204e77..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/InstantiatedMethod.Canon.cs +++ /dev/null @@ -1,114 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Implements generic method canonicalization - partial class InstantiatedMethod - { - /// - /// Stores a cached version of the canonicalized form of this method since - /// calculating it is a recursive operation - /// - InstantiatedMethod _specificCanonCache = null; - InstantiatedMethod _universalCanonCache = null; - - /// - /// Returns the result of canonicalizing this method over the given kind of Canon - /// - public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) - { - InstantiatedMethod canonicalMethodResult = GetCachedCanonValue(kind); - if (canonicalMethodResult == null) - { - bool instantiationChanged; - Instantiation canonInstantiation = Context.ConvertInstantiationToCanonForm(Instantiation, kind, out instantiationChanged); - MethodDesc openMethodOnCanonicalizedType = _methodDef.GetCanonMethodTarget(kind); - - if (instantiationChanged || (openMethodOnCanonicalizedType != _methodDef)) - { - canonicalMethodResult = Context.GetInstantiatedMethod(openMethodOnCanonicalizedType, canonInstantiation); - } - else - { - canonicalMethodResult = this; - } - - // If the method instantiation is universal, we use a __UniversalCanon for all instantiation arguments for simplicity. - // This is to not end up having method instantiations like Foo<__UniversalCanon>.Method or Foo<__UniversalCanon>.Method - // or Foo<__UniversalCanon>.Method<__Canon> or Foo.Method<__UniversalCanon> - // It should just be Foo<__UniversalCanon>.Method<__UniversalCanon> - if ((kind == CanonicalFormKind.Specific) && - canonicalMethodResult.IsCanonicalMethod(CanonicalFormKind.Universal)) - { - canonicalMethodResult = (InstantiatedMethod)canonicalMethodResult.GetCanonMethodTarget(CanonicalFormKind.Universal); - } - - SetCachedCanonValue(kind, canonicalMethodResult); - } - - return canonicalMethodResult; - } - - InstantiatedMethod GetCachedCanonValue(CanonicalFormKind kind) - { - switch (kind) - { - case CanonicalFormKind.Specific: - return _specificCanonCache; - - case CanonicalFormKind.Universal: - return _universalCanonCache; - - default: - Debug.Fail("Invalid CanonicalFormKind: " + kind); - return null; - } - } - - void SetCachedCanonValue(CanonicalFormKind kind, InstantiatedMethod value) - { - switch(kind) - { - case CanonicalFormKind.Specific: - Debug.Assert(_specificCanonCache == null || _specificCanonCache == value); - _specificCanonCache = value; - break; - - case CanonicalFormKind.Universal: - Debug.Assert(_universalCanonCache == null || _universalCanonCache == value); - _universalCanonCache = value; - break; - - default: - Debug.Fail("Invalid CanonicalFormKind: " + kind); - break; - } - } - - /// - /// True if either the containing type instantiation or any of this method's generic arguments - /// are canonical - /// - public override bool IsCanonicalMethod(CanonicalFormKind policy) - { - if (OwningType.HasInstantiation && OwningType.IsCanonicalSubtype(policy)) - { - return true; - } - - foreach (TypeDesc type in Instantiation) - { - if (type.IsCanonicalSubtype(policy)) - { - return true; - } - } - - return false; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/InstantiatedType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/InstantiatedType.Canon.cs deleted file mode 100644 index 8ed86f39c2e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/InstantiatedType.Canon.cs +++ /dev/null @@ -1,36 +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. - -namespace Internal.TypeSystem -{ - // Implements canonicalization for generic instantiations - partial class InstantiatedType - { - public override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - foreach (TypeDesc t in Instantiation) - { - if (t.IsCanonicalSubtype(policy)) - { - return true; - } - } - - return false; - } - - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - bool needsChange; - Instantiation canonInstantiation = Context.ConvertInstantiationToCanonForm(Instantiation, kind, out needsChange); - if (needsChange) - { - MetadataType openType = (MetadataType)GetTypeDefinition(); - return Context.GetInstantiatedType(openType, canonInstantiation); - } - - return this; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MetadataType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MetadataType.Canon.cs deleted file mode 100644 index 97d2dba1985..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MetadataType.Canon.cs +++ /dev/null @@ -1,15 +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. - -namespace Internal.TypeSystem -{ - // Holds code for canonicalization of metadata types - partial class MetadataType - { - public override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - return false; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodDelegator.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodDelegator.Canon.cs deleted file mode 100644 index 9cc3a22040e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodDelegator.Canon.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem -{ - partial class MethodDelegator - { - public override bool IsCanonicalMethod(CanonicalFormKind policy) - { - return _wrappedMethod.IsCanonicalMethod(policy); - } - - // For this method, delegating to the wrapped MethodDesc would likely be the wrong thing. - public abstract override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodDesc.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodDesc.Canon.cs deleted file mode 100644 index ad9e3d6b7fc..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodDesc.Canon.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - // Implements method canonicalization - partial class MethodDesc - { - public virtual bool IsCanonicalMethod(CanonicalFormKind policy) - { - return false; - } - - /// - /// Returns the result of canonicalizing this method over the given kind of Canon - /// - public virtual MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) - { - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodForInstantiatedType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodForInstantiatedType.Canon.cs deleted file mode 100644 index abb49e6f5d7..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/MethodForInstantiatedType.Canon.cs +++ /dev/null @@ -1,24 +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. - -namespace Internal.TypeSystem -{ - // Implements canonicalization for methods on instantiated types - partial class MethodForInstantiatedType - { - public override bool IsCanonicalMethod(CanonicalFormKind policy) - { - return OwningType.IsCanonicalSubtype(policy); - } - - public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) - { - TypeDesc canonicalizedTypeOfTargetMethod = OwningType.ConvertToCanonForm(kind); - if (canonicalizedTypeOfTargetMethod == OwningType) - return this; - - return Context.GetMethodForInstantiatedType(GetTypicalMethodDefinition(), (InstantiatedType)canonicalizedTypeOfTargetMethod); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ParameterizedType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ParameterizedType.Canon.cs deleted file mode 100644 index 471022fc070..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/ParameterizedType.Canon.cs +++ /dev/null @@ -1,15 +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. - -namespace Internal.TypeSystem -{ - // Holds code for canonicalizing a parameterized type - partial class ParameterizedType - { - public sealed override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - return ParameterType.IsCanonicalSubtype(policy); - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/PointerType.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/PointerType.Canon.cs deleted file mode 100644 index ae189951217..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/PointerType.Canon.cs +++ /dev/null @@ -1,19 +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. - -namespace Internal.TypeSystem -{ - // Holds code for canonicalizing pointers - partial class PointerType - { - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - TypeDesc paramTypeConverted = Context.ConvertToCanon(ParameterType, kind); - if (paramTypeConverted != ParameterType) - return Context.GetPointerType(paramTypeConverted); - - return this; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/SignatureVariable.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/SignatureVariable.Canon.cs deleted file mode 100644 index a7da04a857c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/SignatureVariable.Canon.cs +++ /dev/null @@ -1,40 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Implements canonicalization of generic type parameters - partial class SignatureTypeVariable - { - public override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - Debug.Fail("IsCanonicalSubtype of an indefinite type"); - return false; - } - - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - Debug.Fail("ConvertToCanonFormImpl for an indefinite type"); - return this; - } - } - - // Implements canonicalization of generic method parameters - partial class SignatureMethodVariable - { - public override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - Debug.Fail("IsCanonicalSubtype of an indefinite type"); - return false; - } - - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - Debug.Fail("ConvertToCanonFormImpl for an indefinite type"); - return this; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/StandardCanonicalizationAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/StandardCanonicalizationAlgorithm.cs deleted file mode 100644 index 8cac891b311..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/StandardCanonicalizationAlgorithm.cs +++ /dev/null @@ -1,140 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// Contains utility functionality for canonicalization used by multiple types. - /// - public static class StandardCanonicalizationAlgorithm - { - /// - /// Returns a new instantiation that canonicalizes all types in - /// if possible under the policy of '' - /// - /// True if the returned instantiation is different from ''. - public static Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) - { - TypeDesc[] canonInstantiation = null; - - CanonicalFormKind currentKind = kind; - CanonicalFormKind startLoopKind; - - // This logic is wrapped in a loop because we might potentially need to restart canonicalization if the policy - // changes due to one of the instantiation arguments already being universally canonical. - do - { - startLoopKind = currentKind; - - for (int instantiationIndex = 0; instantiationIndex < instantiation.Length; instantiationIndex++) - { - TypeDesc typeToConvert = instantiation[instantiationIndex]; - TypeDesc canonForm = ConvertToCanon(typeToConvert, ref currentKind); - if (typeToConvert != canonForm || canonInstantiation != null) - { - if (canonInstantiation == null) - { - canonInstantiation = new TypeDesc[instantiation.Length]; - for (int i = 0; i < instantiationIndex; i++) - canonInstantiation[i] = instantiation[i]; - } - - canonInstantiation[instantiationIndex] = canonForm; - } - } - - // Optimization: even if canonical policy changed, we don't actually need to re-run the loop - // for instantiations that only have a single element. - if (instantiation.Length == 1) - { - break; - } - - } while (currentKind != startLoopKind); - - - changed = canonInstantiation != null; - if (changed) - { - return new Instantiation(canonInstantiation); - } - - return instantiation; - } - - /// - /// Helper API to convert a type to its canonical or universal canonical form. - /// Note that for now, there is no mixture between specific canonical and universal canonical forms, - /// meaning that the canonical form or Foo can either be Foo<__Canon, int> or - /// Foo<__UniversalCanon, __UniversalCanon>. It cannot be Foo<__Canon, __UniversalCanon> (yet) - /// for simplicity. We can always change that rule in the futue and add support for the mixture, but - /// for now we are keeping it simple. - /// - public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) - { - // Wrap the call to the version that potentially modifies the parameter. External - // callers are not interested in that. - return ConvertToCanon(typeToConvert, ref kind); - } - - private static TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) - { - TypeSystemContext context = typeToConvert.Context; - if (kind == CanonicalFormKind.Universal) - { - return context.UniversalCanonType; - } - else if (kind == CanonicalFormKind.Specific) - { - if (typeToConvert == context.UniversalCanonType) - { - kind = CanonicalFormKind.Universal; - return context.UniversalCanonType; - } - else if (typeToConvert.IsSignatureVariable) - { - return typeToConvert; - } - else if (typeToConvert.IsDefType) - { - if (!typeToConvert.IsValueType) - return context.CanonType; - else if (typeToConvert.HasInstantiation) - { - TypeDesc convertedType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); - if (convertedType.IsCanonicalSubtype(CanonicalFormKind.Universal)) - { - kind = CanonicalFormKind.Universal; - return context.UniversalCanonType; - } - return convertedType; - } - else - return typeToConvert; - } - else if (typeToConvert.IsArray) - { - return context.CanonType; - } - else - { - TypeDesc convertedType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); - if (convertedType.IsCanonicalSubtype(CanonicalFormKind.Universal)) - { - kind = CanonicalFormKind.Universal; - return context.UniversalCanonType; - } - return convertedType; - } - } - else - { - Debug.Assert(false); - return null; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/TypeDesc.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/TypeDesc.Canon.cs deleted file mode 100644 index c4c141c42a3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/TypeDesc.Canon.cs +++ /dev/null @@ -1,97 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Implements canonicalization for types - partial class TypeDesc - { - /// - /// Stores a cached version of the canonicalized form of this type since - /// calculating it is a recursive operation - /// - TypeDesc _specificCanonCache = null; - TypeDesc _universalCanonCache = null; - TypeDesc GetCachedCanonValue(CanonicalFormKind kind) - { - switch (kind) - { - case CanonicalFormKind.Specific: - return _specificCanonCache; - - case CanonicalFormKind.Universal: - return _universalCanonCache; - - default: - Debug.Fail("Invalid CanonicalFormKind: " + kind); - return null; - } - } - - void SetCachedCanonValue(CanonicalFormKind kind, TypeDesc value) - { - switch (kind) - { - case CanonicalFormKind.Specific: - Debug.Assert(_specificCanonCache == null || _specificCanonCache == value); - _specificCanonCache = value; - break; - - case CanonicalFormKind.Universal: - Debug.Assert(_universalCanonCache == null || _universalCanonCache == value); - _universalCanonCache = value; - break; - - default: - Debug.Fail("Invalid CanonicalFormKind: " + kind); - break; - } - } - - /// - /// Returns the canonical form of this type - /// - public TypeDesc ConvertToCanonForm(CanonicalFormKind kind) - { - TypeDesc canonForm = GetCachedCanonValue(kind); - if (canonForm == null) - { - canonForm = ConvertToCanonFormImpl(kind); - SetCachedCanonValue(kind, canonForm); - } - - return canonForm; - } - - /// - /// Derived types that override this should convert their generic parameters to canonical ones - /// - protected abstract TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind); - - /// - /// Returns true if this type matches the discovery policy or if it's parameterized over one that does. - /// - public abstract bool IsCanonicalSubtype(CanonicalFormKind policy); - - /// - /// Gets a value indicating whether this type is considered to be canonical type. - /// Note this will only return true if this is type is the actual __Canon/__UniversalCanon type, - /// or a struct instantiated over one of those. See also . - /// - internal bool IsCanonicalType - { - get - { - if (Context.IsCanonicalDefinitionType(this, CanonicalFormKind.Any)) - return true; - else if (this.IsValueType) - return this.IsCanonicalSubtype(CanonicalFormKind.Any); - else - return false; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs deleted file mode 100644 index 444f24b67a6..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs +++ /dev/null @@ -1,117 +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 Interlocked = System.Threading.Interlocked; -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Includes canonicalization objects local to a particular context - public partial class TypeSystemContext - { - private CanonType _canonType = null; - /// - /// Instance of System.__Canon for this context - /// - public CanonBaseType CanonType - { - get - { - if (_canonType == null) - { - Interlocked.CompareExchange(ref _canonType, new CanonType(this), null); - } - return _canonType; - } - } - - private UniversalCanonType _universalCanonType = null; - /// - /// Instance of System.__UniversalCanon for this context - /// - public CanonBaseType UniversalCanonType - { - get - { - if (_universalCanonType == null) - { - Interlocked.CompareExchange(ref _universalCanonType, new UniversalCanonType(this), null); - } - return _universalCanonType; - } - } - - protected internal virtual ModuleDesc CanonTypesModule - { - get { return SystemModule; } - } - - /// - /// Returns true if and only if the '' is __Canon or __UniversalCanon - /// that matches the parameter. - /// - public bool IsCanonicalDefinitionType(TypeDesc type, CanonicalFormKind kind) - { - if (kind == CanonicalFormKind.Any) - { - return type == CanonType || type == UniversalCanonType; - } - else if (kind == CanonicalFormKind.Specific) - { - return type == CanonType; - } - else - { - Debug.Assert(kind == CanonicalFormKind.Universal); - return type == UniversalCanonType; - } - } - - /// - /// Converts an instantiation into its canonical form. - /// - public Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind) - { - bool changed; - return ConvertInstantiationToCanonForm(instantiation, kind, out changed); - } - - /// - /// Converts an instantiation into its canonical form. Returns the canonical instantiation. The '' - /// parameter indicates whether the returned canonical instantiation is different from the specific instantiation - /// passed as the input. - /// - protected internal virtual Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) - { - throw new NotSupportedException(); - } - - /// - /// Converts a constituent of a constructed type to it's canonical form. Note this method is different - /// from . - /// - protected internal virtual TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) - { - throw new NotSupportedException(); - } - - public abstract bool SupportsCanon { get; } - public abstract bool SupportsUniversalCanon { get; } - - public MetadataType GetCanonType(string name) - { - switch (name) - { - case TypeSystem.CanonType.FullName: - return CanonType; - case TypeSystem.UniversalCanonType.FullName: - return UniversalCanonType; - } - - return null; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/FieldDesc.CodeGen.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/FieldDesc.CodeGen.cs deleted file mode 100644 index 1fd5ea231f0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/FieldDesc.CodeGen.cs +++ /dev/null @@ -1,33 +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. - -namespace Internal.TypeSystem -{ - // Additional members of FieldDesc related to code generation. - partial class FieldDesc - { - /// - /// Gets a value indicating whether this is a field that needs to be treated - /// specially. - /// - public virtual bool IsIntrinsic - { - get - { - return false; - } - } - } - - partial class FieldForInstantiatedType - { - public override bool IsIntrinsic - { - get - { - return _fieldDef.IsIntrinsic; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs deleted file mode 100644 index 7091ea8a955..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs +++ /dev/null @@ -1,105 +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. - -namespace Internal.TypeSystem -{ - partial class MethodDelegator - { - public override bool IsIntrinsic - { - get - { - return _wrappedMethod.IsIntrinsic; - } - } - - public override bool IsNoInlining - { - get - { - return _wrappedMethod.IsNoInlining; - } - } - - public override bool IsAggressiveInlining - { - get - { - return _wrappedMethod.IsAggressiveInlining; - } - } - - public override bool IsAggressiveOptimization - { - get - { - return _wrappedMethod.IsAggressiveOptimization; - } - } - - public override bool RequireSecObject - { - get - { - return _wrappedMethod.RequireSecObject; - } - } - - public override bool IsNoOptimization - { - get - { - return _wrappedMethod.IsNoOptimization; - } - } - - public override bool IsRuntimeImplemented - { - get - { - return _wrappedMethod.IsRuntimeImplemented; - } - } - - public override bool IsInternalCall - { - get - { - return _wrappedMethod.IsInternalCall; - } - } - - public override bool IsSynchronized - { - get - { - return _wrappedMethod.IsSynchronized; - } - } - - public override bool IsNativeCallable - { - get - { - return _wrappedMethod.IsNativeCallable; - } - } - - public override bool IsRuntimeExport - { - get - { - return _wrappedMethod.IsRuntimeExport; - } - } - - public override bool IsSpecialName - { - get - { - return _wrappedMethod.IsSpecialName; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs deleted file mode 100644 index 5884f1dcb4c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs +++ /dev/null @@ -1,373 +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. - -namespace Internal.TypeSystem -{ - // Additional members of MethodDesc related to code generation. - public abstract partial class MethodDesc - { - /// - /// Gets a value specifying whether this method is an intrinsic. - /// This can either be an intrinsic recognized by the compiler, - /// by the codegen backend, or some other component. - /// - public virtual bool IsIntrinsic - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether this method should not be included - /// into the code of any caller methods by the compiler (and should be kept - /// as a separate routine). - /// - public virtual bool IsNoInlining - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether this method should be included into - /// the code of the caller methods aggressively. - /// - public virtual bool IsAggressiveInlining - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether this method contains hot code and should - /// be aggressively optimized if possible. - /// - public virtual bool IsAggressiveOptimization - { - get - { - return false; - } - } - - /// - /// Gets a value indicating whether this method was marked with the - /// System.Security.DynamicSecurityMethod attribute. For such methods - /// runtime needs to be able to find their caller, their caller's caller - /// or the method itself on the call stack using stack walking. - /// - public virtual bool RequireSecObject - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether this method should not be optimized. - /// - public virtual bool IsNoOptimization - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether the implementation of this method - /// is provided by the runtime (i.e., through generated IL). - /// - public virtual bool IsRuntimeImplemented - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether the implementation of this method is - /// provided externally by calling out into the runtime. - /// - public virtual bool IsInternalCall - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether the implementation of this method is - /// implicitly synchronized - /// - public virtual bool IsSynchronized - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether this method is directly callable - /// by external unmanaged code. - /// - public virtual bool IsNativeCallable - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether this method is an exported managed - /// entrypoint. - /// - public virtual bool IsRuntimeExport - { - get - { - return false; - } - } - - /// - /// Gets a value specifying whether this method has special semantics. - /// The name indicates the semantics. - /// - public virtual bool IsSpecialName - { - get - { - return false; - } - } - } - - // Additional members of InstantiatedMethod related to code generation. - public partial class InstantiatedMethod - { - public override bool IsIntrinsic - { - get - { - return _methodDef.IsIntrinsic; - } - } - - public override bool IsNoInlining - { - get - { - return _methodDef.IsNoInlining; - } - } - - public override bool IsAggressiveOptimization - { - get - { - return _methodDef.IsAggressiveOptimization; - } - } - - public override bool RequireSecObject - { - get - { - return _methodDef.RequireSecObject; - } - } - - public override bool IsNoOptimization - { - get - { - return _methodDef.IsNoOptimization; - } - } - - public override bool IsAggressiveInlining - { - get - { - return _methodDef.IsAggressiveInlining; - } - } - - public override bool IsRuntimeImplemented - { - get - { - return _methodDef.IsRuntimeImplemented; - } - } - - public override bool IsInternalCall - { - get - { - return _methodDef.IsInternalCall; - } - } - - public override bool IsSynchronized - { - get - { - return _methodDef.IsSynchronized; - } - } - - public override bool IsNativeCallable - { - get - { - return _methodDef.IsNativeCallable; - } - } - - public override bool IsSpecialName - { - get - { - return _methodDef.IsSpecialName; - } - } - } - - // Additional members of MethodForInstantiatedType related to code generation. - public partial class MethodForInstantiatedType - { - public override bool IsIntrinsic - { - get - { - return _typicalMethodDef.IsIntrinsic; - } - } - - public override bool IsNoInlining - { - get - { - return _typicalMethodDef.IsNoInlining; - } - } - - public override bool IsAggressiveOptimization - { - get - { - return _typicalMethodDef.IsAggressiveOptimization; - } - } - - public override bool RequireSecObject - { - get - { - return _typicalMethodDef.RequireSecObject; - } - } - - public override bool IsNoOptimization - { - get - { - return _typicalMethodDef.IsNoOptimization; - } - } - - public override bool IsAggressiveInlining - { - get - { - return _typicalMethodDef.IsAggressiveInlining; - } - } - - public override bool IsRuntimeImplemented - { - get - { - return _typicalMethodDef.IsRuntimeImplemented; - } - } - - public override bool IsInternalCall - { - get - { - return _typicalMethodDef.IsInternalCall; - } - } - - public override bool IsSynchronized - { - get - { - return _typicalMethodDef.IsSynchronized; - } - } - - public override bool IsNativeCallable - { - get - { - return _typicalMethodDef.IsNativeCallable; - } - } - - public override bool IsSpecialName - { - get - { - return _typicalMethodDef.IsSpecialName; - } - } - } - - // Additional members of ArrayMethod related to code generation. - public partial class ArrayMethod - { - public override bool IsIntrinsic - { - get - { - return true; - } - } - - public override bool IsNoInlining - { - get - { - // Do not allow inlining the Address method. The method that actually gets called is - // the one that has a hidden argument with the expected array type. - return Kind == ArrayMethodKind.Address; - } - } - - public override bool IsInternalCall - { - get - { - // We consider Address method an internal call since this will end up calling a different - // method at runtime. - return Kind == ArrayMethodKind.Address; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/TargetDetails.CodeGen.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/TargetDetails.CodeGen.cs deleted file mode 100644 index 311f7488dd5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/TargetDetails.CodeGen.cs +++ /dev/null @@ -1,45 +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. - -namespace Internal.TypeSystem -{ - // Extension to TargetDetails related to code generation - partial class TargetDetails - { - public TargetDetails(TargetArchitecture architecture, TargetOS targetOS, TargetAbi abi, SimdVectorLength simdVectorLength) - : this(architecture, targetOS, abi) - { - MaximumSimdVectorLength = simdVectorLength; - } - - /// - /// Specifies the maximum size of native vectors on the target architecture. - /// - public SimdVectorLength MaximumSimdVectorLength - { - get; - } - } - - /// - /// Specifies the size of native vectors. - /// - public enum SimdVectorLength - { - /// - /// Specifies that native vectors are not supported. - /// - None, - - /// - /// Specifies that native vectors are 128 bit (e.g. SSE on x86). - /// - Vector128Bit, - - /// - /// Specifies that native vectors are 256 bit (e.g. AVX on x86). - /// - Vector256Bit, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/TypeDesc.CodeGen.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/TypeDesc.CodeGen.cs deleted file mode 100644 index 9a5a1c8b289..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/CodeGen/TypeDesc.CodeGen.cs +++ /dev/null @@ -1,30 +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. - -namespace Internal.TypeSystem -{ - partial class TypeDesc - { - /// - /// Gets a value indicating whether this is a type that needs to be treated - /// specially. - /// - public bool IsIntrinsic - { - get - { - return (GetTypeFlags(TypeFlags.IsIntrinsic | TypeFlags.AttributeCacheComputed) & TypeFlags.IsIntrinsic) != 0; - } - } - } - - partial class InstantiatedType - { - partial void AddComputedIntrinsicFlag(ref TypeFlags flags) - { - if (_typeDef.IsIntrinsic) - flags |= TypeFlags.IsIntrinsic; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/AlignmentHelper.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/AlignmentHelper.cs deleted file mode 100644 index 7678cd58b81..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/AlignmentHelper.cs +++ /dev/null @@ -1,23 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public static class AlignmentHelper - { - public static int AlignUp(this int val, int alignment) - { - Debug.Assert(val >= 0 && alignment >= 0); - - // alignment must be a power of 2 for this implementation to work (need modulo otherwise) - Debug.Assert(0 == (alignment & (alignment - 1))); - int result = (val + (alignment - 1)) & ~(alignment - 1); - Debug.Assert(result >= val); // check for overflow - - return result; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs deleted file mode 100644 index 4da118caeab..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs +++ /dev/null @@ -1,18 +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. - -namespace Internal.TypeSystem -{ - public partial class ArrayMethod - { - public override string DiagnosticName - { - get - { - // The ArrayMethod.Name property is gauranteed to not throw - return Name; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayType.cs deleted file mode 100644 index eaa4547863b..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayType.cs +++ /dev/null @@ -1,325 +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 System.Collections.Generic; -using System.Threading; - -namespace Internal.TypeSystem -{ - /// - /// Represents an array type - either a multidimensional array, or a vector - /// (a one-dimensional array with a zero lower bound). - /// - public sealed partial class ArrayType : ParameterizedType - { - private int _rank; // -1 for regular single dimensional arrays, > 0 for multidimensional arrays - - internal ArrayType(TypeDesc elementType, int rank) - : base(elementType) - { - _rank = rank; - } - - public override int GetHashCode() - { - // ComputeArrayTypeHashCode expects -1 for an SzArray - return Internal.NativeFormat.TypeHashingAlgorithms.ComputeArrayTypeHashCode(this.ElementType.GetHashCode(), _rank); - } - - public override DefType BaseType - { - get - { - return this.Context.GetWellKnownType(WellKnownType.Array); - } - } - - /// - /// Gets the type of the element of this array. - /// - public TypeDesc ElementType - { - get - { - return this.ParameterType; - } - } - - internal MethodDesc[] _methods; - - /// - /// Gets a value indicating whether this type is a vector. - /// - public new bool IsSzArray - { - get - { - return _rank < 0; - } - } - - /// - /// Gets a value indicating whether this type is an mdarray. - /// - public new bool IsMdArray - { - get - { - return _rank > 0; - } - } - - /// - /// Gets the rank of this array. Note this returns "1" for both vectors, and - /// for general arrays of rank 1. Use to disambiguate. - /// - public int Rank - { - get - { - return (_rank < 0) ? 1 : _rank; - } - } - - private void InitializeMethods() - { - int numCtors; - - if (IsSzArray) - { - numCtors = 1; - - // Jagged arrays have constructor for each possible depth - var t = this.ElementType; - while (t.IsSzArray) - { - t = ((ArrayType)t).ElementType; - numCtors++; - } - } - else - { - // Multidimensional arrays have two ctors, one with and one without lower bounds - numCtors = 2; - } - - MethodDesc[] methods = new MethodDesc[(int)ArrayMethodKind.Ctor + numCtors]; - - for (int i = 0; i < methods.Length; i++) - methods[i] = new ArrayMethod(this, (ArrayMethodKind)i); - - Interlocked.CompareExchange(ref _methods, methods, null); - } - - public override IEnumerable GetMethods() - { - if (_methods == null) - InitializeMethods(); - return _methods; - } - - public MethodDesc GetArrayMethod(ArrayMethodKind kind) - { - if (_methods == null) - InitializeMethods(); - return _methods[(int)kind]; - } - - public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc elementType = this.ElementType; - TypeDesc instantiatedElementType = elementType.InstantiateSignature(typeInstantiation, methodInstantiation); - if (instantiatedElementType != elementType) - return Context.GetArrayType(instantiatedElementType, _rank); - - return this; - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = _rank == -1 ? TypeFlags.SzArray : TypeFlags.Array; - - flags |= TypeFlags.HasGenericVarianceComputed; - - flags |= TypeFlags.HasFinalizerComputed; - - flags |= TypeFlags.AttributeCacheComputed; - - return flags; - } - } - - public enum ArrayMethodKind - { - Get, - Set, - Address, - AddressWithHiddenArg, - Ctor - } - - /// - /// Represents one of the methods on array types. While array types are not typical - /// classes backed by metadata, they do have methods that can be referenced from the IL - /// and the type system needs to provide a way to represent them. - /// - /// - /// There are two array Address methods ( and - /// ). One is used when referencing Address - /// method from IL, the other is used when *compiling* the method body. - /// The reason we need to do this is that the Address method is required to do a type check using a type - /// that is only known at the callsite. The trick we use is that we tell codegen that the - /// method requires a hidden instantiation parameter (even though it doesn't). - /// The instantiation parameter is where we capture the type at the callsite. - /// When we compile the method body, we compile it as that - /// has the hidden argument explicitly listed in it's signature and is available as a regular parameter. - /// - public sealed partial class ArrayMethod : MethodDesc - { - private ArrayType _owningType; - private ArrayMethodKind _kind; - - internal ArrayMethod(ArrayType owningType, ArrayMethodKind kind) - { - _owningType = owningType; - _kind = kind; - } - - public override TypeSystemContext Context - { - get - { - return _owningType.Context; - } - } - - public override TypeDesc OwningType - { - get - { - return _owningType; - } - } - - public ArrayType OwningArray - { - get - { - return _owningType; - } - } - - public ArrayMethodKind Kind - { - get - { - return _kind; - } - } - - private MethodSignature _signature; - - public override MethodSignature Signature - { - get - { - if (_signature == null) - { - switch (_kind) - { - case ArrayMethodKind.Get: - { - var parameters = new TypeDesc[_owningType.Rank]; - for (int i = 0; i < _owningType.Rank; i++) - parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); - _signature = new MethodSignature(0, 0, _owningType.ElementType, parameters); - break; - } - case ArrayMethodKind.Set: - { - var parameters = new TypeDesc[_owningType.Rank + 1]; - for (int i = 0; i < _owningType.Rank; i++) - parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); - parameters[_owningType.Rank] = _owningType.ElementType; - _signature = new MethodSignature(0, 0, this.Context.GetWellKnownType(WellKnownType.Void), parameters); - break; - } - case ArrayMethodKind.Address: - { - var parameters = new TypeDesc[_owningType.Rank]; - for (int i = 0; i < _owningType.Rank; i++) - parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); - _signature = new MethodSignature(0, 0, _owningType.ElementType.MakeByRefType(), parameters); - } - break; - case ArrayMethodKind.AddressWithHiddenArg: - { - var parameters = new TypeDesc[_owningType.Rank + 1]; - parameters[0] = Context.SystemModule.GetType("System", "EETypePtr"); - for (int i = 0; i < _owningType.Rank; i++) - parameters[i + 1] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); - _signature = new MethodSignature(0, 0, _owningType.ElementType.MakeByRefType(), parameters); - } - break; - default: - { - int numArgs; - if (_owningType.IsSzArray) - { - numArgs = 1 + (int)_kind - (int)ArrayMethodKind.Ctor; - } - else - { - numArgs = (_kind == ArrayMethodKind.Ctor) ? _owningType.Rank : 2 * _owningType.Rank; - } - - var argTypes = new TypeDesc[numArgs]; - for (int i = 0; i < argTypes.Length; i++) - argTypes[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); - _signature = new MethodSignature(0, 0, this.Context.GetWellKnownType(WellKnownType.Void), argTypes); - } - break; - } - } - return _signature; - } - } - - public override string Name - { - get - { - switch (_kind) - { - case ArrayMethodKind.Get: - return "Get"; - case ArrayMethodKind.Set: - return "Set"; - case ArrayMethodKind.Address: - case ArrayMethodKind.AddressWithHiddenArg: - return "Address"; - default: - return ".ctor"; - } - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return false; - } - - public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc owningType = this.OwningType; - TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); - - if (owningType != instantiatedOwningType) - return ((ArrayType)instantiatedOwningType).GetArrayMethod(_kind); - else - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/BaseTypeRuntimeInterfacesAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/BaseTypeRuntimeInterfacesAlgorithm.cs deleted file mode 100644 index 8f814cfb594..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/BaseTypeRuntimeInterfacesAlgorithm.cs +++ /dev/null @@ -1,33 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// RuntimeInterfaces algorithm for types known to have no explicitly defined interfaces - /// but which do have a base type. (For instance multidimensional arrays) - /// - public sealed class BaseTypeRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm - { - private static RuntimeInterfacesAlgorithm _singleton = new BaseTypeRuntimeInterfacesAlgorithm(); - - private BaseTypeRuntimeInterfacesAlgorithm() { } - - public static RuntimeInterfacesAlgorithm Instance - { - get - { - return _singleton; - } - } - - public override DefType[] ComputeRuntimeInterfaces(TypeDesc _type) - { - return _type.BaseType.RuntimeInterfaces; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ByRefType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ByRefType.cs deleted file mode 100644 index 6d198459452..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ByRefType.cs +++ /dev/null @@ -1,45 +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. - -namespace Internal.TypeSystem -{ - /// - /// Represents a managed pointer type. - /// - public sealed partial class ByRefType : ParameterizedType - { - internal ByRefType(TypeDesc parameter) - : base(parameter) - { - } - - public override int GetHashCode() - { - return Internal.NativeFormat.TypeHashingAlgorithms.ComputeByrefTypeHashCode(this.ParameterType.GetHashCode()); - } - - public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc parameterType = this.ParameterType; - TypeDesc instantiatedParameterType = parameterType.InstantiateSignature(typeInstantiation, methodInstantiation); - if (instantiatedParameterType != parameterType) - return Context.GetByRefType(instantiatedParameterType); - - return this; - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = TypeFlags.ByRef; - - flags |= TypeFlags.HasGenericVarianceComputed; - - flags |= TypeFlags.HasFinalizerComputed; - - flags |= TypeFlags.AttributeCacheComputed; - - return flags; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/CastingHelper.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/CastingHelper.cs deleted file mode 100644 index d850cc6b334..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/CastingHelper.cs +++ /dev/null @@ -1,426 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public static partial class CastingHelper - { - /// - /// Returns true if '' can be cast to ''. - /// Assumes '' is in it's boxed form if it's a value type (i.e. - /// [System.Int32].CanCastTo([System.Object]) will return true). - /// - public static bool CanCastTo(this TypeDesc thisType, TypeDesc otherType) - { - return thisType.CanCastToInternal(otherType, null); - } - - private static bool CanCastToInternal(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) - { - if (thisType == otherType) - { - return true; - } - - switch (thisType.Category) - { - case TypeFlags.GenericParameter: - return ((GenericParameterDesc)thisType).CanCastGenericParameterTo(otherType, protect); - - case TypeFlags.Array: - case TypeFlags.SzArray: - return ((ArrayType)thisType).CanCastArrayTo(otherType, protect); - - default: - Debug.Assert(thisType.IsDefType); - return thisType.CanCastToClassOrInterface(otherType, protect); - } - } - - private static bool CanCastGenericParameterTo(this GenericParameterDesc thisType, TypeDesc otherType, StackOverflowProtect protect) - { - // A boxed variable type can be cast to any of its constraints, or object, if none are specified - if (otherType.IsObject) - { - return true; - } - - if (thisType.HasNotNullableValueTypeConstraint && - otherType.IsWellKnownType(WellKnownType.ValueType)) - { - return true; - } - - foreach (var typeConstraint in thisType.TypeConstraints) - { - if (typeConstraint.CanCastToInternal(otherType, protect)) - { - return true; - } - } - - return false; - } - - private static bool CanCastArrayTo(this ArrayType thisType, TypeDesc otherType, StackOverflowProtect protect) - { - // Casting the array to one of the base types or interfaces? - if (otherType.IsDefType) - { - return thisType.CanCastToClassOrInterface(otherType, protect); - } - - // Casting array to something else (between SzArray and Array, for example)? - if (thisType.Category != otherType.Category) - { - // An SzArray is castable to MdArray rank 1. We follow the same casting rules as SzArray to SzArray. - if (thisType.Category == TypeFlags.SzArray - && otherType.Category == TypeFlags.Array - && ((ArrayType)otherType).Rank == 1) - { - return thisType.CanCastParamTo(((ArrayType)otherType).ParameterType, protect); - } - - return false; - } - - ArrayType otherArrayType = (ArrayType)otherType; - - // Check ranks if we're casting multidim arrays - if (!thisType.IsSzArray && thisType.Rank != otherArrayType.Rank) - { - return false; - } - - return thisType.CanCastParamTo(otherArrayType.ParameterType, protect); - } - - private static bool CanCastParamTo(this ParameterizedType thisType, TypeDesc paramType, StackOverflowProtect protect) - { - // While boxed value classes inherit from object their - // unboxed versions do not. Parameterized types have the - // unboxed version, thus, if the from type parameter is value - // class then only an exact match/equivalence works. - if (thisType.ParameterType == paramType) - { - return true; - } - - TypeDesc curTypesParm = thisType.ParameterType; - - // Object parameters don't need an exact match but only inheritance, check for that - TypeDesc fromParamUnderlyingType = curTypesParm.UnderlyingType; - if (fromParamUnderlyingType.IsGCPointer) - { - return curTypesParm.CanCastToInternal(paramType, protect); - } - else if (curTypesParm.IsGenericParameter) - { - var genericVariableFromParam = (GenericParameterDesc)curTypesParm; - if (genericVariableFromParam.HasReferenceTypeConstraint) - { - return genericVariableFromParam.CanCastToInternal(paramType, protect); - } - } - else if (fromParamUnderlyingType.IsPrimitive) - { - TypeDesc toParamUnderlyingType = paramType.UnderlyingType; - if (toParamUnderlyingType.IsPrimitive) - { - if (toParamUnderlyingType == fromParamUnderlyingType) - { - return true; - } - - if (ArePrimitveTypesEquivalentSize(fromParamUnderlyingType, toParamUnderlyingType)) - { - return true; - } - } - } - - // Anything else is not a match - return false; - } - - // Returns true of the two types are equivalent primitive types. Used by array casts. - private static bool ArePrimitveTypesEquivalentSize(TypeDesc type1, TypeDesc type2) - { - Debug.Assert(type1.IsPrimitive && type2.IsPrimitive); - - // Primitive types such as E_T_I4 and E_T_U4 are interchangeable - // Enums with interchangeable underlying types are interchangable - // BOOL is NOT interchangeable with I1/U1, neither CHAR -- with I2/U2 - // Float and double are not interchangable here. - - int sourcePrimitiveTypeEquivalenceSize = type1.GetIntegralTypeMatchSize(); - - // Quick check to see if the first type can be matched. - if (sourcePrimitiveTypeEquivalenceSize == 0) - { - return false; - } - - int targetPrimitiveTypeEquivalenceSize = type2.GetIntegralTypeMatchSize(); - - return sourcePrimitiveTypeEquivalenceSize == targetPrimitiveTypeEquivalenceSize; - } - - private static int GetIntegralTypeMatchSize(this TypeDesc type) - { - Debug.Assert(type.IsPrimitive); - - switch (type.Category) - { - case TypeFlags.SByte: - case TypeFlags.Byte: - return 1; - case TypeFlags.UInt16: - case TypeFlags.Int16: - return 2; - case TypeFlags.Int32: - case TypeFlags.UInt32: - return 4; - case TypeFlags.Int64: - case TypeFlags.UInt64: - return 8; - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - return type.Context.Target.PointerSize; - default: - return 0; - } - } - - public static bool IsArrayElementTypeCastableBySize(TypeDesc elementType) - { - TypeDesc underlyingType = elementType.UnderlyingType; - return underlyingType.IsPrimitive && GetIntegralTypeMatchSize(underlyingType) != 0; - } - - private static bool CanCastToClassOrInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) - { - if (otherType.IsInterface) - { - return thisType.CanCastToInterface(otherType, protect); - } - else - { - return thisType.CanCastToClass(otherType, protect); - } - } - - private static bool CanCastToInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) - { - if (!otherType.HasVariance) - { - return thisType.CanCastToNonVariantInterface(otherType,protect); - } - else - { - if (thisType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) - { - return true; - } - - foreach (var interfaceType in thisType.RuntimeInterfaces) - { - if (interfaceType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) - { - return true; - } - } - } - - return false; - } - - private static bool CanCastToNonVariantInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) - { - if (otherType == thisType) - { - return true; - } - - foreach (var interfaceType in thisType.RuntimeInterfaces) - { - if (interfaceType == otherType) - { - return true; - } - } - - return false; - } - - private static bool CanCastByVarianceToInterfaceOrDelegate(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protectInput) - { - if (!thisType.HasSameTypeDefinition(otherType)) - { - return false; - } - - var stackOverflowProtectKey = new CastingPair(thisType, otherType); - if (protectInput != null) - { - if (protectInput.Contains(stackOverflowProtectKey)) - return false; - } - - StackOverflowProtect protect = new StackOverflowProtect(stackOverflowProtectKey, protectInput); - - Instantiation instantiationThis = thisType.Instantiation; - Instantiation instantiationTarget = otherType.Instantiation; - Instantiation instantiationOpen = thisType.GetTypeDefinition().Instantiation; - - Debug.Assert(instantiationThis.Length == instantiationTarget.Length && - instantiationThis.Length == instantiationOpen.Length); - - for (int i = 0; i < instantiationThis.Length; i++) - { - TypeDesc arg = instantiationThis[i]; - TypeDesc targetArg = instantiationTarget[i]; - - if (arg != targetArg) - { - GenericParameterDesc openArgType = (GenericParameterDesc)instantiationOpen[i]; - - switch (openArgType.Variance) - { - case GenericVariance.Covariant: - if (!arg.IsBoxedAndCanCastTo(targetArg, protect)) - return false; - break; - - case GenericVariance.Contravariant: - if (!targetArg.IsBoxedAndCanCastTo(arg, protect)) - return false; - break; - - default: - // non-variant - Debug.Assert(openArgType.Variance == GenericVariance.None); - return false; - } - } - } - - return true; - } - - private static bool CanCastToClass(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) - { - TypeDesc curType = thisType; - - if (curType.IsInterface && otherType.IsObject) - { - return true; - } - - // If the target type has variant type parameters, we take a slower path - if (curType.HasVariance) - { - // First chase inheritance hierarchy until we hit a class that only differs in its instantiation - do - { - if (curType == otherType) - { - return true; - } - - if (curType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) - { - return true; - } - - curType = curType.BaseType; - } - while (curType != null); - } - else - { - // If there are no variant type parameters, just chase the hierarchy - - // Allow curType to be nullable, which means this method - // will additionally return true if curType is Nullable && ( - // currType == otherType - // OR otherType is System.ValueType or System.Object) - - // Always strip Nullable from the otherType, if present - if (otherType.IsNullable && !curType.IsNullable) - { - return thisType.CanCastTo(otherType.Instantiation[0]); - } - - do - { - if (curType == otherType) - return true; - - curType = curType.BaseType; - } while (curType != null); - } - - return false; - } - - private static bool IsBoxedAndCanCastTo(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) - { - TypeDesc fromUnderlyingType = thisType.UnderlyingType; - - if (fromUnderlyingType.IsGCPointer) - { - return thisType.CanCastToInternal(otherType, protect); - } - else if (thisType.IsGenericParameter) - { - var genericVariableFromParam = (GenericParameterDesc)thisType; - if (genericVariableFromParam.HasReferenceTypeConstraint) - { - return genericVariableFromParam.CanCastToInternal(otherType, protect); - } - } - - return false; - } - - private class StackOverflowProtect - { - private CastingPair _value; - private StackOverflowProtect _previous; - - public StackOverflowProtect(CastingPair value, StackOverflowProtect previous) - { - _value = value; - _previous = previous; - } - - public bool Contains(CastingPair value) - { - for (var current = this; current != null; current = current._previous) - if (current._value.Equals(value)) - return true; - return false; - } - } - - private struct CastingPair - { - public readonly TypeDesc FromType; - public readonly TypeDesc ToType; - - public CastingPair(TypeDesc fromType, TypeDesc toType) - { - FromType = fromType; - ToType = toType; - } - - public bool Equals(CastingPair other) => FromType == other.FromType && ToType == other.ToType; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.Diagnostic.cs deleted file mode 100644 index 8ef92715ab3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.Diagnostic.cs +++ /dev/null @@ -1,25 +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.Collections.Generic; - -namespace Internal.TypeSystem -{ - /// - /// Type with metadata available that is equivalent to a TypeDef record in an ECMA 335 metadata stream. - /// A class, an interface, or a value type. - /// - abstract partial class DefType - { - /// - /// Gets the Name of a type. This must not throw - /// - public abstract string DiagnosticName { get; } - - /// - /// Gets the Namespace of a type. This must not throw - /// - public abstract string DiagnosticNamespace { get; } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.FieldLayout.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.FieldLayout.cs deleted file mode 100644 index e1b1beee819..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.FieldLayout.cs +++ /dev/null @@ -1,411 +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 System.Diagnostics; - -namespace Internal.TypeSystem -{ - // This is the api surface necessary to query the field layout of a type - public abstract partial class DefType : TypeDesc - { - /// - /// Bit flags for layout - /// - private class FieldLayoutFlags - { - /// - /// True if ContainsGCPointers has been computed - /// - public const int ComputedContainsGCPointers = 1; - - /// - /// True if the type contains GC pointers - /// - public const int ContainsGCPointers = 2; - - /// - /// True if the instance type only layout is computed - /// - public const int ComputedInstanceTypeLayout = 4; - - /// - /// True if the static field layout for the static regions have been computed - /// - public const int ComputedStaticRegionLayout = 8; - - /// - /// True if the instance type layout is complete including fields - /// - public const int ComputedInstanceTypeFieldsLayout = 0x10; - - /// - /// True if the static field layout for the static fields have been computed - /// - public const int ComputedStaticFieldsLayout = 0x20; - - /// - /// True if information about the shape of value type has been computed. - /// - public const int ComputedValueTypeShapeCharacteristics = 0x40; - } - - private class StaticBlockInfo - { - public StaticsBlock NonGcStatics; - public StaticsBlock GcStatics; - public StaticsBlock ThreadNonGcStatics; - public StaticsBlock ThreadGcStatics; - } - - ThreadSafeFlags _fieldLayoutFlags; - - LayoutInt _instanceFieldSize; - LayoutInt _instanceFieldAlignment; - LayoutInt _instanceByteCountUnaligned; - LayoutInt _instanceByteAlignment; - - // Information about various static blocks is rare, so we keep it out of line. - StaticBlockInfo _staticBlockInfo; - - ValueTypeShapeCharacteristics _valueTypeShapeCharacteristics; - - /// - /// Does a type transitively have any fields which are GC object pointers - /// - public bool ContainsGCPointers - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedContainsGCPointers)) - { - ComputeTypeContainsGCPointers(); - } - return _fieldLayoutFlags.HasFlags(FieldLayoutFlags.ContainsGCPointers); - } - } - - /// - /// The number of bytes required to hold a field of this type - /// - public LayoutInt InstanceFieldSize - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) - { - ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); - } - return _instanceFieldSize; - } - } - - /// - /// What is the alignment requirement of the fields of this type - /// - public LayoutInt InstanceFieldAlignment - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) - { - ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); - } - return _instanceFieldAlignment; - } - } - - /// - /// The number of bytes required when allocating this type on this GC heap - /// - public LayoutInt InstanceByteCount - { - get - { - return LayoutInt.AlignUp(InstanceByteCountUnaligned, InstanceByteAlignment, Context.Target); - } - } - - /// - /// The number of bytes used by the instance fields of this type and its parent types without padding at the end for alignment/gc. - /// - public LayoutInt InstanceByteCountUnaligned - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) - { - ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); - } - return _instanceByteCountUnaligned; - } - } - - /// - /// The alignment required for instances of this type on the GC heap - /// - public LayoutInt InstanceByteAlignment - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) - { - ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); - } - return _instanceByteAlignment; - } - } - - /// - /// How many bytes must be allocated to represent the non GC visible static fields of this type. - /// - public LayoutInt NonGCStaticFieldSize - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) - { - ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); - } - return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.NonGcStatics.Size; - } - } - - /// - /// What is the alignment required for allocating the non GC visible static fields of this type. - /// - public LayoutInt NonGCStaticFieldAlignment - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) - { - ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); - } - return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.NonGcStatics.LargestAlignment; - } - } - - /// - /// How many bytes must be allocated to represent the GC visible static fields of this type. - /// - public LayoutInt GCStaticFieldSize - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) - { - ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); - } - return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.GcStatics.Size; - } - } - - /// - /// What is the alignment required for allocating the GC visible static fields of this type. - /// - public LayoutInt GCStaticFieldAlignment - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) - { - ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); - } - return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.GcStatics.LargestAlignment; - } - } - - /// - /// How many bytes must be allocated to represent the non GC visible thread static fields - /// of this type. - /// - public LayoutInt ThreadNonGcStaticFieldSize - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) - { - ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); - } - return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadNonGcStatics.Size; - } - } - - /// - /// What is the alignment required for allocating the non GC visible thread static fields - /// of this type. - /// - public LayoutInt ThreadNonGcStaticFieldAlignment - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) - { - ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); - } - return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadNonGcStatics.LargestAlignment; - } - } - - /// - /// How many bytes must be allocated to represent the (potentially GC visible) thread static - /// fields of this type. - /// - public LayoutInt ThreadGcStaticFieldSize - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) - { - ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); - } - return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadGcStatics.Size; - } - } - - /// - /// What is the alignment required for allocating the (potentially GC visible) thread static - /// fields of this type. - /// - public LayoutInt ThreadGcStaticFieldAlignment - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout)) - { - ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); - } - return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadGcStatics.LargestAlignment; - } - } - - /// - /// Gets a value indicating whether the fields of the type satisfy the Homogeneous Float Aggregate classification. - /// - public bool IsHfa - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics)) - { - ComputeValueTypeShapeCharacteristics(); - } - return (_valueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.HomogenousFloatAggregate) != 0; - } - } - - internal ValueTypeShapeCharacteristics ValueTypeShapeCharacteristics - { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics)) - { - ComputeValueTypeShapeCharacteristics(); - } - return _valueTypeShapeCharacteristics; - } - } - - /// - /// Get the Homogeneous Float Aggregate element type if this is a HFA type ( is true). - /// - public DefType HfaElementType - { - get - { - // We are not caching this because this is rare and not worth wasting space in DefType. - return this.Context.GetLayoutAlgorithmForType(this).ComputeHomogeneousFloatAggregateElementType(this); - } - } - - private void ComputeValueTypeShapeCharacteristics() - { - _valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this); - _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics); - } - - - public void ComputeInstanceLayout(InstanceLayoutKind layoutKind) - { - if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout | FieldLayoutFlags.ComputedInstanceTypeLayout)) - return; - - var computedLayout = this.Context.GetLayoutAlgorithmForType(this).ComputeInstanceLayout(this, layoutKind); - - _instanceFieldSize = computedLayout.FieldSize; - _instanceFieldAlignment = computedLayout.FieldAlignment; - _instanceByteCountUnaligned = computedLayout.ByteCountUnaligned; - _instanceByteAlignment = computedLayout.ByteCountAlignment; - - if (computedLayout.Offsets != null) - { - foreach (var fieldAndOffset in computedLayout.Offsets) - { - Debug.Assert(fieldAndOffset.Field.OwningType == this); - fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset); - } - _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout); - } - - _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedInstanceTypeLayout); - } - - public void ComputeStaticFieldLayout(StaticLayoutKind layoutKind) - { - if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticFieldsLayout | FieldLayoutFlags.ComputedStaticRegionLayout)) - return; - - var computedStaticLayout = this.Context.GetLayoutAlgorithmForType(this).ComputeStaticFieldLayout(this, layoutKind); - - if ((computedStaticLayout.NonGcStatics.Size != LayoutInt.Zero) || - (computedStaticLayout.GcStatics.Size != LayoutInt.Zero) || - (computedStaticLayout.ThreadNonGcStatics.Size != LayoutInt.Zero) || - (computedStaticLayout.ThreadGcStatics.Size != LayoutInt.Zero)) - { - var staticBlockInfo = new StaticBlockInfo - { - NonGcStatics = computedStaticLayout.NonGcStatics, - GcStatics = computedStaticLayout.GcStatics, - ThreadNonGcStatics = computedStaticLayout.ThreadNonGcStatics, - ThreadGcStatics = computedStaticLayout.ThreadGcStatics - }; - _staticBlockInfo = staticBlockInfo; - } - - if (computedStaticLayout.Offsets != null) - { - foreach (var fieldAndOffset in computedStaticLayout.Offsets) - { - Debug.Assert(fieldAndOffset.Field.OwningType == this); - fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset); - } - _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedStaticFieldsLayout); - } - - _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedStaticRegionLayout); - } - - public void ComputeTypeContainsGCPointers() - { - if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedContainsGCPointers)) - return; - - int flagsToAdd = FieldLayoutFlags.ComputedContainsGCPointers; - - if (!IsValueType && HasBaseType && BaseType.ContainsGCPointers) - { - _fieldLayoutFlags.AddFlags(flagsToAdd | FieldLayoutFlags.ContainsGCPointers); - return; - } - - if (this.Context.GetLayoutAlgorithmForType(this).ComputeContainsGCPointers(this)) - { - flagsToAdd |= FieldLayoutFlags.ContainsGCPointers; - } - - _fieldLayoutFlags.AddFlags(flagsToAdd); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.cs deleted file mode 100644 index fb1cf075c91..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.cs +++ /dev/null @@ -1,28 +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. - -namespace Internal.TypeSystem -{ - /// - /// Type that is logically equivalent to a type which is defined by a TypeDef - /// record in an ECMA 335 metadata stream - a class, an interface, or a value type. - /// - public abstract partial class DefType : TypeDesc - { - /// - /// Gets the namespace of the type. - /// - public virtual string Namespace => null; - - /// - /// Gets the name of the type as represented in the metadata. - /// - public virtual string Name => null; - - /// - /// Gets the containing type of this type or null if the type is not nested. - /// - public virtual DefType ContainingType => null; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ExceptionStringID.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ExceptionStringID.cs deleted file mode 100644 index 7de12aa4fe0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ExceptionStringID.cs +++ /dev/null @@ -1,41 +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. - -namespace Internal.TypeSystem -{ - /// - /// Represents an ID of a localized exception string. - /// - public enum ExceptionStringID - { - // TypeLoadException - ClassLoadGeneral, - ClassLoadExplicitGeneric, - ClassLoadBadFormat, - ClassLoadExplicitLayout, - ClassLoadValueClassTooLarge, - ClassLoadRankTooLarge, - - // MissingMethodException - MissingMethod, - - // MissingFieldException - MissingField, - - // FileNotFoundException - FileLoadErrorGeneric, - - // InvalidProgramException - InvalidProgramDefault, - InvalidProgramSpecific, - InvalidProgramVararg, - InvalidProgramCallVirtFinalize, - InvalidProgramNativeCallable, - InvalidProgramCallAbstractMethod, - InvalidProgramCallVirtStatic, - - // BadImageFormatException - BadImageFormatGeneric, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ExplicitLayoutValidator.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ExplicitLayoutValidator.cs deleted file mode 100644 index b1c4ae54a09..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ExplicitLayoutValidator.cs +++ /dev/null @@ -1,155 +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 System.Diagnostics; - -namespace Internal.TypeSystem -{ - public struct ExplicitLayoutValidator - { - private enum FieldLayoutTag : byte - { - Empty, - NonORef, - ORef, - } - - private readonly int _pointerSize; - - private readonly FieldLayoutTag[] _fieldLayout; - - private readonly MetadataType _typeBeingValidated; - - private ExplicitLayoutValidator(MetadataType type, int typeSizeInBytes) - { - _typeBeingValidated = type; - _pointerSize = type.Context.Target.PointerSize; - _fieldLayout = new FieldLayoutTag[typeSizeInBytes]; - } - - public static void Validate(MetadataType type, ComputedInstanceFieldLayout layout) - { - ExplicitLayoutValidator validator = new ExplicitLayoutValidator(type, layout.ByteCountUnaligned.AsInt); - foreach (FieldAndOffset fieldAndOffset in layout.Offsets) - { - validator.AddToFieldLayout(fieldAndOffset.Offset.AsInt, fieldAndOffset.Field.FieldType); - } - } - - private void AddToFieldLayout(int offset, TypeDesc fieldType) - { - if (fieldType.IsGCPointer) - { - if (offset % _pointerSize != 0) - { - // Misaligned ORef - ThrowFieldLayoutError(offset); - } - SetFieldLayout(offset, _pointerSize, FieldLayoutTag.ORef); - } - else if (fieldType.IsPointer || fieldType.IsFunctionPointer) - { - SetFieldLayout(offset, _pointerSize, FieldLayoutTag.NonORef); - } - else if (fieldType.IsValueType) - { - if (fieldType.IsByRefLike && offset % _pointerSize != 0) - { - // Misaligned ByRefLike - ThrowFieldLayoutError(offset); - } - - MetadataType mdType = (MetadataType)fieldType; - int fieldSize = mdType.InstanceByteCountUnaligned.AsInt; - if (!mdType.ContainsGCPointers) - { - // Plain value type, mark the entire range as NonORef - SetFieldLayout(offset, fieldSize, FieldLayoutTag.NonORef); - } - else - { - if (offset % _pointerSize != 0) - { - // Misaligned struct with GC pointers - ThrowFieldLayoutError(offset); - } - - bool[] fieldORefMap = new bool[fieldSize]; - MarkORefLocations(mdType, fieldORefMap, offset: 0); - for (int index = 0; index < fieldSize; index++) - { - SetFieldLayout(offset + index, fieldORefMap[index] ? FieldLayoutTag.ORef : FieldLayoutTag.NonORef); - } - } - } - else if (fieldType.IsByRef) - { - if (offset % _pointerSize != 0) - { - // Misaligned pointer field - ThrowFieldLayoutError(offset); - } - SetFieldLayout(offset, _pointerSize, FieldLayoutTag.NonORef); - } - else - { - Debug.Assert(false, fieldType.ToString()); - } - } - - private void MarkORefLocations(MetadataType type, bool[] orefMap, int offset) - { - // Recurse into struct fields - foreach (FieldDesc field in type.GetFields()) - { - if (!field.IsStatic) - { - int fieldOffset = offset + field.Offset.AsInt; - if (field.FieldType.IsGCPointer) - { - for (int index = 0; index < _pointerSize; index++) - { - orefMap[fieldOffset + index] = true; - } - } - else if (field.FieldType.IsValueType) - { - MetadataType mdFieldType = (MetadataType)field.FieldType; - if (mdFieldType.ContainsGCPointers) - { - MarkORefLocations(mdFieldType, orefMap, fieldOffset); - } - } - } - } - } - - private void SetFieldLayout(int offset, int count, FieldLayoutTag tag) - { - for (int index = 0; index < count; index++) - { - SetFieldLayout(offset + index, tag); - } - } - - private void SetFieldLayout(int offset, FieldLayoutTag tag) - { - FieldLayoutTag existingTag = _fieldLayout[offset]; - if (existingTag != tag) - { - if (existingTag != FieldLayoutTag.Empty) - { - ThrowFieldLayoutError(offset); - } - _fieldLayout[offset] = tag; - } - } - - private void ThrowFieldLayoutError(int offset) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadExplicitLayout, _typeBeingValidated, offset.ToStringInvariant()); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.FieldLayout.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.FieldLayout.cs deleted file mode 100644 index 4452e8d6ee7..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.FieldLayout.cs +++ /dev/null @@ -1,53 +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 System.Diagnostics; - -namespace Internal.TypeSystem -{ - // Api extensions for fields that allow keeping track of field layout - - public partial class FieldDesc - { - private LayoutInt _offset = FieldAndOffset.InvalidOffset; - - public LayoutInt Offset - { - get - { - if (_offset == FieldAndOffset.InvalidOffset) - { - if (IsStatic) - OwningType.ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizesAndFields); - else - OwningType.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields); - - // If the offset still wasn't computed, this must be a field that doesn't participate in layout - // (either literal or RVA mapped). We shouldn't be asking for the offset. - Debug.Assert(_offset != FieldAndOffset.InvalidOffset); - } - return _offset; - } - } - - /// - /// For static fields, represents whether or not the field is held in the GC or non GC statics region. - /// - public bool HasGCStaticBase - { - get - { - Debug.Assert(IsStatic); - return Context.ComputeHasGCStaticBase(this); - } - } - - internal void InitializeOffset(LayoutInt offset) - { - Debug.Assert(_offset == FieldAndOffset.InvalidOffset || _offset == offset); - _offset = offset; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.ToString.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.ToString.cs deleted file mode 100644 index 29cea11d53e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.ToString.cs +++ /dev/null @@ -1,14 +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. - -namespace Internal.TypeSystem -{ - partial class FieldDesc - { - public override string ToString() - { - return $"{OwningType}.{Name}"; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.cs deleted file mode 100644 index be2d81bd563..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldDesc.cs +++ /dev/null @@ -1,99 +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 System.Runtime.CompilerServices; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public abstract partial class FieldDesc : TypeSystemEntity - { - public static readonly FieldDesc[] EmptyFields = new FieldDesc[0]; - - public override int GetHashCode() - { - // Inherited types are expected to override - return RuntimeHelpers.GetHashCode(this); - } - - public override bool Equals(Object o) - { - // Its only valid to compare two FieldDescs in the same context - Debug.Assert(Object.ReferenceEquals(o, null) || !(o is FieldDesc) || Object.ReferenceEquals(((FieldDesc)o).Context, this.Context)); - return Object.ReferenceEquals(this, o); - } - - public virtual string Name - { - get - { - return null; - } - } - - public abstract DefType OwningType - { - get; - } - - public abstract TypeDesc FieldType - { - get; - } - - public abstract bool IsStatic - { - get; - } - - public abstract bool IsInitOnly - { - get; - } - - public abstract bool IsThreadStatic - { - get; - } - - public abstract bool HasRva - { - get; - } - - public abstract bool IsLiteral - { - get; - } - - public abstract bool HasCustomAttribute(string attributeNamespace, string attributeName); - - public virtual FieldDesc GetTypicalFieldDefinition() - { - return this; - } - - public bool IsTypicalFieldDefinition - { - get - { - return GetTypicalFieldDefinition() == this; - } - } - - public virtual FieldDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - FieldDesc field = this; - - TypeDesc owningType = field.OwningType; - TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); - if (owningType != instantiatedOwningType) - field = instantiatedOwningType.Context.GetFieldForInstantiatedType(field.GetTypicalFieldDefinition(), (InstantiatedType)instantiatedOwningType); - - return field; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldForInstantiatedType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldForInstantiatedType.cs deleted file mode 100644 index 5fac1161448..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldForInstantiatedType.cs +++ /dev/null @@ -1,105 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public sealed partial class FieldForInstantiatedType : FieldDesc - { - private readonly FieldDesc _fieldDef; - private readonly InstantiatedType _instantiatedType; - - internal FieldForInstantiatedType(FieldDesc fieldDef, InstantiatedType instantiatedType) - { - Debug.Assert(fieldDef.GetTypicalFieldDefinition() == fieldDef); - _fieldDef = fieldDef; - _instantiatedType = instantiatedType; - } - - public override TypeSystemContext Context - { - get - { - return _fieldDef.Context; - } - } - - public override DefType OwningType - { - get - { - return _instantiatedType; - } - } - - public override string Name - { - get - { - return _fieldDef.Name; - } - } - - public override TypeDesc FieldType - { - get - { - return _fieldDef.FieldType.InstantiateSignature(_instantiatedType.Instantiation, new Instantiation()); - } - } - - public override bool IsStatic - { - get - { - return _fieldDef.IsStatic; - } - } - - public override bool IsInitOnly - { - get - { - return _fieldDef.IsInitOnly; - } - } - - public override bool IsThreadStatic - { - get - { - return _fieldDef.IsThreadStatic; - } - } - - public override bool HasRva - { - get - { - return _fieldDef.HasRva; - } - } - - public override bool IsLiteral - { - get - { - return _fieldDef.IsLiteral; - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return _fieldDef.HasCustomAttribute(attributeNamespace, attributeName); - } - - public override FieldDesc GetTypicalFieldDefinition() - { - return _fieldDef; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs deleted file mode 100644 index 720c80a6597..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs +++ /dev/null @@ -1,126 +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. - -namespace Internal.TypeSystem -{ - /// - /// Pluggable field layout algorithm. Provides means to compute static/instance sizes for types, - /// offsets for their fields and other type information that depends on type's fields. - /// The information computed by this algorithm is exposed on various properties of - /// and . - /// - /// - /// The algorithms are expected to be directly used by derivatives - /// only. The most obvious implementation of this algorithm that uses type's metadata to - /// compute the answers is in . - /// - public abstract class FieldLayoutAlgorithm - { - /// - /// Compute the instance field layout for a DefType. Must not depend on static field layout for any other type. - /// - public abstract ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind); - - /// - /// Compute the static field layout for a DefType. Must not depend on static field layout for any other type. - /// - public abstract ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, StaticLayoutKind layoutKind); - - /// - /// Compute whether the fields of the specified type contain a GC pointer. - /// - public abstract bool ComputeContainsGCPointers(DefType type); - - /// - /// Compute the shape of a valuetype. The shape information is used to control code generation and allocation - /// (such as vectorization, passing the valuetype by value across method calls, or boxing alignment). - /// - public abstract ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type); - - /// - /// If the type has characteristic, returns - /// the element type of the homogenous float aggregate. This will either be System.Double or System.Float. - /// - public abstract DefType ComputeHomogeneousFloatAggregateElementType(DefType type); - } - - /// - /// Specifies the level to which to compute the instance field layout. - /// - public enum InstanceLayoutKind - { - /// - /// Compute instance sizes and alignments. - /// - TypeOnly, - - /// - /// Compute instance sizes, alignments and field offsets. - /// - TypeAndFields - } - - /// - /// Specifies the level to which to compute static field layout. - /// - public enum StaticLayoutKind - { - /// - /// Compute static region sizes. - /// - StaticRegionSizes, - - /// - /// Compute static region sizes and static field offsets. - /// - StaticRegionSizesAndFields - } - - public struct ComputedInstanceFieldLayout - { - public LayoutInt FieldSize; - public LayoutInt FieldAlignment; - public LayoutInt ByteCountUnaligned; - public LayoutInt ByteCountAlignment; - - /// - /// If Offsets is non-null, then all field based layout is complete. - /// Otherwise, only the non-field based data is considered to be complete - /// - public FieldAndOffset[] Offsets; - } - - public struct StaticsBlock - { - public LayoutInt Size; - public LayoutInt LargestAlignment; - } - - public struct ComputedStaticFieldLayout - { - public StaticsBlock NonGcStatics; - public StaticsBlock GcStatics; - public StaticsBlock ThreadNonGcStatics; - public StaticsBlock ThreadGcStatics; - - /// - /// If Offsets is non-null, then all field based layout is complete. - /// Otherwise, only the non-field based data is considered to be complete - /// - public FieldAndOffset[] Offsets; - } - - /// - /// Describes shape of a value type for code generation and allocation purposes. - /// - public enum ValueTypeShapeCharacteristics - { - None = 0x00, - - /// - /// The structure is an aggregate of floating point values of the same type. - /// - HomogenousFloatAggregate = 0x01, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FunctionPointerType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FunctionPointerType.cs deleted file mode 100644 index 523b105d0fa..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/FunctionPointerType.cs +++ /dev/null @@ -1,75 +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.Text; - -namespace Internal.TypeSystem -{ - /// - /// Represents an unmanaged pointer to a method with a signature compatible with the signature of the pointer. - /// - public sealed partial class FunctionPointerType : TypeDesc - { - private MethodSignature _signature; - private int _hashCode; - - internal FunctionPointerType(MethodSignature signature) - { - _signature = signature; - } - - /// - /// Gets the signature of the method this pointer points to. - /// - public MethodSignature Signature - { - get - { - return _signature; - } - } - - public override TypeSystemContext Context - { - get - { - return _signature.ReturnType.Context; - } - } - - public override int GetHashCode() - { - if (_hashCode == 0) - _hashCode = _signature.GetHashCode(); - return _hashCode; - } - - public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - MethodSignatureBuilder sigBuilder = new MethodSignatureBuilder(_signature); - sigBuilder.ReturnType = _signature.ReturnType.InstantiateSignature(typeInstantiation, methodInstantiation); - for (int i = 0; i < _signature.Length; i++) - sigBuilder[i] = _signature[i].InstantiateSignature(typeInstantiation, methodInstantiation); - - MethodSignature instantiatedSignature = sigBuilder.ToSignature(); - if (instantiatedSignature != _signature) - return Context.GetFunctionPointerType(instantiatedSignature); - - return this; - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = TypeFlags.FunctionPointer; - - flags |= TypeFlags.HasGenericVarianceComputed; - - flags |= TypeFlags.HasFinalizerComputed; - - flags |= TypeFlags.AttributeCacheComputed; - - return flags; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs deleted file mode 100644 index f78dc80fa6a..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs +++ /dev/null @@ -1,17 +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 System.Collections.Generic; - -namespace Internal.TypeSystem -{ - public abstract partial class GenericParameterDesc - { - /// - /// Gets the name of the generic parameter as defined in the metadata. This must not throw - /// - public abstract string DiagnosticName { get; } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.cs deleted file mode 100644 index 4eff6c6cbc5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.cs +++ /dev/null @@ -1,179 +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 System.Collections.Generic; - -namespace Internal.TypeSystem -{ - public enum GenericParameterKind - { - Type, - Method, - } - - /// - /// Describes the variance on a generic type parameter of a generic type or method. - /// - public enum GenericVariance - { - None = 0, - - /// - /// The generic type parameter is covariant. A covariant type parameter can appear - /// as the result type of a method, the type of a read-only field, a declared base - /// type, or an implemented interface. - /// - Covariant = 1, - - /// - /// The generic type parameter is contravariant. A contravariant type parameter can - /// appear as a parameter type in method signatures. - /// - Contravariant = 2 - } - - /// - /// Describes the constraints on a generic type parameter of a generic type or method. - /// - [Flags] - public enum GenericConstraints - { - None = 0, - - /// - /// A type can be substituted for the generic type parameter only if it is a reference type. - /// - ReferenceTypeConstraint = 0x04, - - /// - // A type can be substituted for the generic type parameter only if it is a value - // type and is not nullable. - /// - NotNullableValueTypeConstraint = 0x08, - - /// - /// A type can be substituted for the generic type parameter only if it has a parameterless - /// constructor. - /// - DefaultConstructorConstraint = 0x10, - } - - public abstract partial class GenericParameterDesc : TypeDesc - { - /// - /// Gets the name of the generic parameter as defined in the metadata. - /// - public virtual string Name - { - get - { - return String.Concat("T", Index.ToStringInvariant()); - } - } - - /// - /// Gets a value indicating whether this is a type or method generic parameter. - /// - public abstract GenericParameterKind Kind { get; } - - /// - /// Gets the zero based index of the generic parameter within the declaring type or method. - /// - public abstract int Index { get; } - - /// - /// Gets a value indicating the variance of this generic parameter. - /// - public virtual GenericVariance Variance - { - get - { - return GenericVariance.None; - } - } - - /// - /// Gets a value indicating generic constraints of this generic parameter. - /// - public virtual GenericConstraints Constraints - { - get - { - return GenericConstraints.None; - } - } - - /// - /// Gets type constraints imposed on substitutions. - /// - public virtual IEnumerable TypeConstraints - { - get - { - return TypeDesc.EmptyTypes; - } - } - - public bool HasNotNullableValueTypeConstraint - { - get - { - return (Constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0; - } - } - - public bool HasReferenceTypeConstraint - { - get - { - return (Constraints & GenericConstraints.ReferenceTypeConstraint) != 0; - } - } - - public bool HasDefaultConstructorConstraint - { - get - { - return (Constraints & GenericConstraints.DefaultConstructorConstraint) != 0; - } - } - - public bool IsCovariant - { - get - { - return (Variance & GenericVariance.Covariant) != 0; - } - } - - public bool IsContravariant - { - get - { - return (Variance & GenericVariance.Contravariant) != 0; - } - } - - protected sealed override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = 0; - - flags |= TypeFlags.GenericParameter; - - flags |= TypeFlags.HasGenericVarianceComputed; - - flags |= TypeFlags.AttributeCacheComputed; - - return flags; - } - - public sealed override int GetHashCode() - { - // TODO: Determine what a the right hash function should be. Use stable hashcode based on the type name? - // For now, use the same hash as a SignatureVariable type. - return Internal.NativeFormat.TypeHashingAlgorithms.ComputeSignatureVariableHashCode(Index, Kind == GenericParameterKind.Method); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/IAssemblyDesc.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/IAssemblyDesc.cs deleted file mode 100644 index e9db5b76e92..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/IAssemblyDesc.cs +++ /dev/null @@ -1,19 +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.Reflection; - -namespace Internal.TypeSystem -{ - /// - /// Optional interface a should implement if it represents an assembly. - /// - public interface IAssemblyDesc - { - /// - /// Gets the assembly name. - /// - AssemblyName GetName(); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs deleted file mode 100644 index c33020e88e1..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem -{ - public sealed partial class InstantiatedMethod - { - public override string DiagnosticName - { - get - { - return _methodDef.DiagnosticName; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.cs deleted file mode 100644 index f73366c0a54..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.cs +++ /dev/null @@ -1,154 +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 System.Diagnostics; -using System.Text; -using Internal.NativeFormat; - -namespace Internal.TypeSystem -{ - public sealed partial class InstantiatedMethod : MethodDesc - { - private MethodDesc _methodDef; - private Instantiation _instantiation; - - private MethodSignature _signature; - - internal InstantiatedMethod(MethodDesc methodDef, Instantiation instantiation) - { - Debug.Assert(!(methodDef is InstantiatedMethod)); - _methodDef = methodDef; - - Debug.Assert(instantiation.Length > 0); - _instantiation = instantiation; - } - - // This constructor is a performance optimization - it allows supplying the hash code if it has already - // been computed prior to the allocation of this type. The supplied hash code still has to match the - // hash code this type would compute on it's own (and we assert to enforce that). - internal InstantiatedMethod(MethodDesc methodDef, Instantiation instantiation, int hashcode) - : this(methodDef, instantiation) - { - SetHashCode(hashcode); - } - - protected override int ComputeHashCode() - { - return TypeHashingAlgorithms.ComputeMethodHashCode(OwningType.GetHashCode(), Instantiation.ComputeGenericInstanceHashCode(TypeHashingAlgorithms.ComputeNameHashCode(Name))); - } - - public override TypeSystemContext Context - { - get - { - return _methodDef.Context; - } - } - - public override TypeDesc OwningType - { - get - { - return _methodDef.OwningType; - } - } - - private TypeDesc Instantiate(TypeDesc type) - { - return type.InstantiateSignature(new Instantiation(), _instantiation); - } - - public override MethodSignature Signature - { - get - { - if (_signature == null) - { - MethodSignature template = _methodDef.Signature; - MethodSignatureBuilder builder = new MethodSignatureBuilder(template); - - builder.ReturnType = Instantiate(template.ReturnType); - for (int i = 0; i < template.Length; i++) - builder[i] = Instantiate(template[i]); - - _signature = builder.ToSignature(); - } - - return _signature; - } - } - - public override Instantiation Instantiation - { - get - { - return _instantiation; - } - } - - public override bool IsVirtual - { - get - { - return _methodDef.IsVirtual; - } - } - - public override bool IsNewSlot - { - get - { - return _methodDef.IsNewSlot; - } - } - - public override bool IsAbstract - { - get - { - return _methodDef.IsAbstract; - } - } - - public override bool IsFinal - { - get - { - return _methodDef.IsFinal; - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return _methodDef.HasCustomAttribute(attributeNamespace, attributeName); - } - - public override bool IsDefaultConstructor - { - get - { - return false; - } - } - - public override MethodDesc GetMethodDefinition() - { - return _methodDef; - } - - public override MethodDesc GetTypicalMethodDefinition() - { - return _methodDef.GetTypicalMethodDefinition(); - } - - public override string Name - { - get - { - return _methodDef.Name; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs deleted file mode 100644 index 5490cf1dc62..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs +++ /dev/null @@ -1,25 +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. - -namespace Internal.TypeSystem -{ - public sealed partial class InstantiatedType - { - public override string DiagnosticName - { - get - { - return _typeDef.DiagnosticName; - } - } - - public override string DiagnosticNamespace - { - get - { - return _typeDef.DiagnosticNamespace; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Interfaces.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Interfaces.cs deleted file mode 100644 index a51056923fe..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Interfaces.cs +++ /dev/null @@ -1,36 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Implementation for Instantiated type specific interface logic - - public sealed partial class InstantiatedType : MetadataType - { - private DefType[] _implementedInterfaces = null; - - private DefType[] InitializeImplementedInterfaces() - { - return InstantiateTypeArray(_typeDef.ExplicitlyImplementedInterfaces, _instantiation, new Instantiation()); - - // TODO Add duplicate detection - } - - /// - /// The interfaces explicitly declared as implemented by this InstantiatedType. Duplicates are not permitted - /// - public override DefType[] ExplicitlyImplementedInterfaces - { - get - { - if (_implementedInterfaces == null) - return InitializeImplementedInterfaces(); - return _implementedInterfaces; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.MethodImpls.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.MethodImpls.cs deleted file mode 100644 index 474ac1a6ae3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.MethodImpls.cs +++ /dev/null @@ -1,57 +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; - -namespace Internal.TypeSystem -{ - // Implementation of MethodImpl api surface implemented without metadata access. - public partial class InstantiatedType - { - /// - /// Instantiate a MethodImplRecord from uninstantiated form to instantiated form - /// - /// - /// - private MethodImplRecord[] InstantiateMethodImpls(MethodImplRecord[] uninstMethodImpls) - { - if (uninstMethodImpls == null || uninstMethodImpls.Length == 0) - return uninstMethodImpls; - - MethodImplRecord[] instMethodImpls = new MethodImplRecord[uninstMethodImpls.Length]; - - for (int i = 0; i < uninstMethodImpls.Length; i++) - { - MethodDesc decl; - - var implTypeInstantiated = uninstMethodImpls[i].Decl.OwningType.InstantiateSignature(this.Instantiation, new Instantiation()); - if (implTypeInstantiated is InstantiatedType) - { - decl = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Decl.GetTypicalMethodDefinition(), (InstantiatedType)implTypeInstantiated); - } - else - { - decl = uninstMethodImpls[i].Decl; - } - - MethodDesc body = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Body, this); - instMethodImpls[i] = new MethodImplRecord(decl, body); - } - - return instMethodImpls; - } - - protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() - { - MethodImplRecord[] uninstMethodImpls = _typeDef.VirtualMethodImplsForType; - return InstantiateMethodImpls(uninstMethodImpls); - } - - public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name) - { - MethodImplRecord[] uninstMethodImpls = _typeDef.FindMethodsImplWithMatchingDeclName(name); - return InstantiateMethodImpls(uninstMethodImpls); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.cs deleted file mode 100644 index a777f223f09..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.cs +++ /dev/null @@ -1,367 +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 System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace Internal.TypeSystem -{ - public sealed partial class InstantiatedType : MetadataType - { - private MetadataType _typeDef; - private Instantiation _instantiation; - - internal InstantiatedType(MetadataType typeDef, Instantiation instantiation) - { - Debug.Assert(!(typeDef is InstantiatedType)); - _typeDef = typeDef; - - Debug.Assert(instantiation.Length > 0); - _instantiation = instantiation; - - _baseType = this; // Not yet initialized flag - } - - private int _hashCode; - - public override int GetHashCode() - { - if (_hashCode == 0) - _hashCode = _instantiation.ComputeGenericInstanceHashCode(_typeDef.GetHashCode()); - return _hashCode; - } - - public override TypeSystemContext Context - { - get - { - return _typeDef.Context; - } - } - - public override Instantiation Instantiation - { - get - { - return _instantiation; - } - } - - private MetadataType _baseType /* = this */; - - private MetadataType InitializeBaseType() - { - var uninst = _typeDef.MetadataBaseType; - - return (_baseType = (uninst != null) ? (MetadataType)uninst.InstantiateSignature(_instantiation, new Instantiation()) : null); - } - - public override DefType BaseType - { - get - { - if (_baseType == this) - return InitializeBaseType(); - return _baseType; - } - } - - public override MetadataType MetadataBaseType - { - get - { - if (_baseType == this) - return InitializeBaseType(); - return _baseType; - } - } - - // Type system implementations that support the notion of intrinsic types - // will provide an implementation that adds the flag if necessary. - partial void AddComputedIntrinsicFlag(ref TypeFlags flags); - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = 0; - - if ((mask & TypeFlags.CategoryMask) != 0) - { - flags |= _typeDef.Category; - } - - if ((mask & TypeFlags.HasGenericVarianceComputed) != 0) - { - flags |= TypeFlags.HasGenericVarianceComputed; - - if (_typeDef.HasVariance) - flags |= TypeFlags.HasGenericVariance; - } - - if ((mask & TypeFlags.HasFinalizerComputed) != 0) - { - flags |= TypeFlags.HasFinalizerComputed; - - if (_typeDef.HasFinalizer) - flags |= TypeFlags.HasFinalizer; - } - - if ((mask & TypeFlags.AttributeCacheComputed) != 0) - { - flags |= TypeFlags.AttributeCacheComputed; - - if (_typeDef.IsByRefLike) - flags |= TypeFlags.IsByRefLike; - - AddComputedIntrinsicFlag(ref flags); - } - - return flags; - } - - public override string Name - { - get - { - return _typeDef.Name; - } - } - - public override string Namespace - { - get - { - return _typeDef.Namespace; - } - } - - public override IEnumerable GetMethods() - { - foreach (var typicalMethodDef in _typeDef.GetMethods()) - { - yield return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this); - } - } - - // TODO: Substitutions, generics, modopts, ... - public override MethodDesc GetMethod(string name, MethodSignature signature) - { - MethodDesc typicalMethodDef = _typeDef.GetMethod(name, signature); - if (typicalMethodDef == null) - return null; - return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this); - } - - public override MethodDesc GetStaticConstructor() - { - MethodDesc typicalCctor = _typeDef.GetStaticConstructor(); - if (typicalCctor == null) - return null; - return _typeDef.Context.GetMethodForInstantiatedType(typicalCctor, this); - } - - public override MethodDesc GetDefaultConstructor() - { - MethodDesc typicalCtor = _typeDef.GetDefaultConstructor(); - if (typicalCtor == null) - return null; - return _typeDef.Context.GetMethodForInstantiatedType(typicalCtor, this); - } - - public override MethodDesc GetFinalizer() - { - MethodDesc typicalFinalizer = _typeDef.GetFinalizer(); - if (typicalFinalizer == null) - return null; - - MetadataType typeInHierarchy = this; - - // Note, we go back to the type definition/typical method definition in this code. - // If the finalizer is implemented on a base type that is also a generic, then the - // typicalFinalizer in that case is a MethodForInstantiatedType for an instantiated type - // which is instantiated over the open type variables of the derived type. - - while (typicalFinalizer.OwningType.GetTypeDefinition() != typeInHierarchy.GetTypeDefinition()) - { - typeInHierarchy = typeInHierarchy.MetadataBaseType; - } - - if (typeInHierarchy == typicalFinalizer.OwningType) - { - return typicalFinalizer; - } - else - { - Debug.Assert(typeInHierarchy is InstantiatedType); - return _typeDef.Context.GetMethodForInstantiatedType(typicalFinalizer.GetTypicalMethodDefinition(), (InstantiatedType)typeInHierarchy); - } - } - - public override IEnumerable GetFields() - { - foreach (var fieldDef in _typeDef.GetFields()) - { - yield return _typeDef.Context.GetFieldForInstantiatedType(fieldDef, this); - } - } - - // TODO: Substitutions, generics, modopts, ... - public override FieldDesc GetField(string name) - { - FieldDesc fieldDef = _typeDef.GetField(name); - if (fieldDef == null) - return null; - return _typeDef.Context.GetFieldForInstantiatedType(fieldDef, this); - } - - public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc[] clone = null; - - for (int i = 0; i < _instantiation.Length; i++) - { - TypeDesc uninst = _instantiation[i]; - TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); - if (inst != uninst) - { - if (clone == null) - { - clone = new TypeDesc[_instantiation.Length]; - for (int j = 0; j < clone.Length; j++) - { - clone[j] = _instantiation[j]; - } - } - clone[i] = inst; - } - } - - return (clone == null) ? this : _typeDef.Context.GetInstantiatedType(_typeDef, new Instantiation(clone)); - } - - /// - /// Instantiate an array of TypeDescs over typeInstantiation and methodInstantiation - /// - public static T[] InstantiateTypeArray(T[] uninstantiatedTypes, Instantiation typeInstantiation, Instantiation methodInstantiation) where T : TypeDesc - { - T[] clone = null; - - for (int i = 0; i < uninstantiatedTypes.Length; i++) - { - T uninst = uninstantiatedTypes[i]; - TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); - if (inst != uninst) - { - if (clone == null) - { - clone = new T[uninstantiatedTypes.Length]; - for (int j = 0; j < clone.Length; j++) - { - clone[j] = uninstantiatedTypes[j]; - } - } - clone[i] = (T)inst; - } - } - - return clone != null ? clone : uninstantiatedTypes; - } - - // Strips instantiation. E.g C -> C - public override TypeDesc GetTypeDefinition() - { - return _typeDef; - } - - // Properties that are passed through from the type definition - public override ClassLayoutMetadata GetClassLayout() - { - return _typeDef.GetClassLayout(); - } - - public override bool IsExplicitLayout - { - get - { - return _typeDef.IsExplicitLayout; - } - } - - public override bool IsSequentialLayout - { - get - { - return _typeDef.IsSequentialLayout; - } - } - - public override bool IsBeforeFieldInit - { - get - { - return _typeDef.IsBeforeFieldInit; - } - } - - public override bool IsModuleType - { - get - { - // The global module type cannot be generic. - return false; - } - } - - public override bool IsSealed - { - get - { - return _typeDef.IsSealed; - } - } - - public override bool IsAbstract - { - get - { - return _typeDef.IsAbstract; - } - } - - public override ModuleDesc Module - { - get - { - return _typeDef.Module; - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return _typeDef.HasCustomAttribute(attributeNamespace, attributeName); - } - - public override DefType ContainingType - { - get - { - // Return the result from the typical type definition. - return _typeDef.ContainingType; - } - } - - public override MetadataType GetNestedType(string name) - { - // Return the result from the typical type definition. - return _typeDef.GetNestedType(name); - } - - public override IEnumerable GetNestedTypes() - { - // Return the result from the typical type definition. - return _typeDef.GetNestedTypes(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Instantiation.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Instantiation.cs deleted file mode 100644 index d403f0c9bdb..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Instantiation.cs +++ /dev/null @@ -1,113 +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 System.Runtime.CompilerServices; -using System.Text; - -namespace Internal.TypeSystem -{ - /// - /// Represents a generic instantiation - a collection of generic parameters - /// or arguments of a generic type or a generic method. - /// - public struct Instantiation - { - private TypeDesc[] _genericParameters; - - public Instantiation(params TypeDesc[] genericParameters) - { - _genericParameters = genericParameters; - } - - [IndexerName("GenericParameters")] - public TypeDesc this[int index] - { - get - { - return _genericParameters[index]; - } - } - - public int Length - { - get - { - return _genericParameters.Length; - } - } - - public bool IsNull - { - get - { - return _genericParameters == null; - } - } - - /// - /// Combines the given generic definition's hash code with the hashes - /// of the generic parameters in this instantiation - /// - public int ComputeGenericInstanceHashCode(int genericDefinitionHashCode) - { - return Internal.NativeFormat.TypeHashingAlgorithms.ComputeGenericInstanceHashCode(genericDefinitionHashCode, _genericParameters); - } - - public static readonly Instantiation Empty = new Instantiation(TypeDesc.EmptyTypes); - - public Enumerator GetEnumerator() - { - return new Enumerator(_genericParameters); - } - - public override string ToString() - { - if (_genericParameters == null) - return String.Empty; - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < _genericParameters.Length; i++) - { - if (i > 0) - sb.Append(", "); - sb.Append(_genericParameters[i]); - } - return sb.ToString(); - } - - /// - /// Enumerator for iterating over the types in an instantiation - /// - public struct Enumerator - { - private TypeDesc[] _collection; - private int _currentIndex; - - public Enumerator(TypeDesc[] collection) - { - _collection = collection; - _currentIndex = -1; - } - - public TypeDesc Current - { - get - { - return _collection[_currentIndex]; - } - } - - public bool MoveNext() - { - _currentIndex++; - if (_currentIndex >= _collection.Length) - { - return false; - } - return true; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/LayoutInt.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/LayoutInt.cs deleted file mode 100644 index 331bdec0f4f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/LayoutInt.cs +++ /dev/null @@ -1,136 +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 System.Diagnostics; - -namespace Internal.TypeSystem -{ - /// - /// A integer type used for layout calculations. Supports addition, max, min, comparison and alignup operations - /// A custom type is used to allow the concept of an indeterminate value. (Some types representable in the - /// type system do not have a known size. This type is used to make such sizes viral through the type layout - /// computations) - /// - public struct LayoutInt - { - private int _value; - - public static LayoutInt Indeterminate = CreateIndeterminateLayoutInt(); - public static LayoutInt Zero = new LayoutInt(0); - public static LayoutInt One = new LayoutInt(1); - - public LayoutInt(int input) - { - if (input < 0) - { - throw new ArgumentException(); - } - else - { - _value = input; - } - } - - private static LayoutInt CreateIndeterminateLayoutInt() - { - LayoutInt output = default(LayoutInt); - output._value = -1; - Debug.Assert(output.IsIndeterminate); - return output; - } - - public bool IsIndeterminate => _value == -1; - public int AsInt - { - get - { - if (IsIndeterminate) - throw new InvalidOperationException(); - return _value; - } - } - - public override string ToString() - { - return ToStringInvariant(); - } - - public string ToStringInvariant() - { - if (IsIndeterminate) - return "Indeterminate"; - else - return _value.ToStringInvariant(); - } - - public static bool operator ==(LayoutInt left, LayoutInt right) - { - return left._value == right._value; - } - - public static bool operator !=(LayoutInt left, LayoutInt right) - { - return left._value != right._value; - } - - public static LayoutInt operator+(LayoutInt left, LayoutInt right) - { - if (left.IsIndeterminate || right.IsIndeterminate) - return Indeterminate; - - return new LayoutInt(checked(left._value + right._value)); - } - - public override bool Equals(object obj) - { - if (obj is LayoutInt) - { - return this == (LayoutInt)obj; - } - return false; - } - - public override int GetHashCode() - { - return _value.GetHashCode(); - } - - public static LayoutInt Max(LayoutInt left, LayoutInt right) - { - if (left.IsIndeterminate || right.IsIndeterminate) - return Indeterminate; - - return new LayoutInt(Math.Max(left._value, right._value)); - } - - public static LayoutInt Min(LayoutInt left, LayoutInt right) - { - if (left.IsIndeterminate || right.IsIndeterminate) - return Indeterminate; - - return new LayoutInt(Math.Min(left._value, right._value)); - } - - public static LayoutInt AlignUp(LayoutInt value, LayoutInt alignment, TargetDetails target) - { - if (value.IsIndeterminate || alignment.IsIndeterminate) - { - // If value is already aligned to maximum possible alignment, then whatever - // alignment is can't change value - if (!value.IsIndeterminate) - { - if (value.AsInt.AlignUp(target.MaximumAlignment) == value.AsInt) - return value; - } - return Indeterminate; - } - - Debug.Assert(alignment._value <= target.MaximumAlignment); // Assert that the alignment handling for indeterminate types is safe - Debug.Assert(alignment._value >= 1 || ((value._value == 0) && (alignment._value == 0))); // Alignment to less than one doesn't make sense, except for 0 to 0 alignment - - return new LayoutInt(AlignmentHelper.AlignUp(value._value, alignment._value)); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/LocalVariableDefinition.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/LocalVariableDefinition.cs deleted file mode 100644 index 95f978a49d9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/LocalVariableDefinition.cs +++ /dev/null @@ -1,31 +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. - -namespace Internal.TypeSystem -{ - public struct LocalVariableDefinition - { - /// - /// Gets a value indicating whether the stored target should be pinned in the runtime - /// heap and shouldn't be moved by the actions of the garbage collector. - /// - public readonly bool IsPinned; - - /// - /// Gets the type of the local variable. - /// - public readonly TypeDesc Type; - - public LocalVariableDefinition(TypeDesc type, bool isPinned) - { - IsPinned = isPinned; - Type = type; - } - - public override string ToString() - { - return IsPinned ? "pinned " + Type.ToString() : Type.ToString(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs deleted file mode 100644 index b998f6dce93..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ /dev/null @@ -1,957 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// MetadataFieldLayout algorithm which can be used to compute field layout - /// for any MetadataType where all fields are available by calling GetFields. - /// - public class MetadataFieldLayoutAlgorithm : FieldLayoutAlgorithm - { - public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind) - { - MetadataType type = (MetadataType)defType; - // CLI - Partition 1, section 9.5 - Generic types shall not be marked explicitlayout. - if (type.HasInstantiation && type.IsExplicitLayout) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadExplicitGeneric, type.GetTypeDefinition()); - } - - // Count the number of instance fields in advance for convenience - int numInstanceFields = 0; - foreach (var field in type.GetFields()) - { - if (field.IsStatic) - continue; - - TypeDesc fieldType = field.FieldType; - - // ByRef instance fields are not allowed. - if (fieldType.IsByRef) - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - - // ByRef-like instance fields on non-byref-like types are not allowed. - if (fieldType.IsByRefLike && !type.IsByRefLike) - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - - numInstanceFields++; - } - - if (type.IsModuleType) - { - // This is a global type, it must not have instance fields. - if (numInstanceFields > 0) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - // Global types do not do the rest of instance field layout. - ComputedInstanceFieldLayout result = new ComputedInstanceFieldLayout(); - result.Offsets = Array.Empty(); - return result; - } - - // CLI - Partition 2, section 22.8 - // A type has layout if it is marked SequentialLayout or ExplicitLayout. If any type within an inheritance chain has layout, - // then so shall all its base classes, up to the one that descends immediately from System.ValueType (if it exists in the type’s - // hierarchy); otherwise, from System.Object - // Note: While the CLI isn't clearly worded, the layout needs to be the same for the entire chain. - // If the current type isn't ValueType or System.Object and has a layout and the parent type isn't - // ValueType or System.Object then the layout type attributes need to match - if ((!type.IsValueType && !type.IsObject) && - (type.IsSequentialLayout || type.IsExplicitLayout) && - (!type.BaseType.IsValueType && !type.BaseType.IsObject)) - { - MetadataType baseType = type.MetadataBaseType; - - if (type.IsSequentialLayout != baseType.IsSequentialLayout || - type.IsExplicitLayout != baseType.IsExplicitLayout) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type); - } - } - - // Enum types must have a single instance field - if (type.IsEnum && numInstanceFields != 1) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - if (type.IsPrimitive) - { - // Primitive types are special - they may have a single field of the same type - // as the type itself. They do not do the rest of instance field layout. - if (numInstanceFields > 1) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - SizeAndAlignment instanceByteSizeAndAlignment; - var sizeAndAlignment = ComputeInstanceSize( - type, - type.Context.Target.GetWellKnownTypeSize(type), - type.Context.Target.GetWellKnownTypeAlignment(type), - out instanceByteSizeAndAlignment - ); - - ComputedInstanceFieldLayout result = new ComputedInstanceFieldLayout - { - ByteCountUnaligned = instanceByteSizeAndAlignment.Size, - ByteCountAlignment = instanceByteSizeAndAlignment.Alignment, - FieldAlignment = sizeAndAlignment.Alignment, - FieldSize = sizeAndAlignment.Size, - }; - - if (numInstanceFields > 0) - { - FieldDesc instanceField = null; - foreach (FieldDesc field in type.GetFields()) - { - if (!field.IsStatic) - { - Debug.Assert(instanceField == null, "Unexpected extra instance field"); - instanceField = field; - } - } - - Debug.Assert(instanceField != null, "Null instance field"); - - result.Offsets = new FieldAndOffset[] { - new FieldAndOffset(instanceField, LayoutInt.Zero) - }; - } - else - { - result.Offsets = Array.Empty(); - } - - return result; - } - - // If the type has layout, read its packing and size info - // If the type has explicit layout, also read the field offset info - if (type.IsExplicitLayout || type.IsSequentialLayout) - { - if (type.IsEnum) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type); - } - - var layoutMetadata = type.GetClassLayout(); - - // If packing is out of range or not a power of two, throw that the size is invalid - int packing = layoutMetadata.PackingSize; - if (packing < 0 || packing > 128 || ((packing & (packing - 1)) != 0)) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type); - } - - Debug.Assert(layoutMetadata.Offsets == null || layoutMetadata.Offsets.Length == numInstanceFields); - } - - // At this point all special cases are handled and all inputs validated - return ComputeInstanceFieldLayout(type, numInstanceFields); - } - - protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(MetadataType type, int numInstanceFields) - { - if (type.IsExplicitLayout) - { - return ComputeExplicitFieldLayout(type, numInstanceFields); - } - else if (type.IsSequentialLayout || type.Context.Target.Abi == TargetAbi.CppCodegen) - { - return ComputeSequentialFieldLayout(type, numInstanceFields); - } - else - { - return ComputeAutoFieldLayout(type, numInstanceFields); - } - } - - public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind) - { - MetadataType type = (MetadataType)defType; - int numStaticFields = 0; - - foreach (var field in type.GetFields()) - { - if (!field.IsStatic || field.HasRva || field.IsLiteral) - continue; - - numStaticFields++; - } - - ComputedStaticFieldLayout result; - result.GcStatics = new StaticsBlock(); - result.NonGcStatics = new StaticsBlock(); - result.ThreadGcStatics = new StaticsBlock(); - result.ThreadNonGcStatics = new StaticsBlock(); - - if (numStaticFields == 0) - { - result.Offsets = Array.Empty(); - return result; - } - - result.Offsets = new FieldAndOffset[numStaticFields]; - - TypeSystemContext context = type.Context; - - PrepareRuntimeSpecificStaticFieldLayout(context, ref result); - - int index = 0; - - foreach (var field in type.GetFields()) - { - // Nonstatic fields, literal fields, and RVA mapped fields don't participate in layout - if (!field.IsStatic || field.HasRva || field.IsLiteral) - continue; - - TypeDesc fieldType = field.FieldType; - if (fieldType.IsByRef || (fieldType.IsValueType && ((DefType)fieldType).IsByRefLike)) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type); - } - - ref StaticsBlock block = ref GetStaticsBlockForField(ref result, field); - SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, context.Target.DefaultPackingSize); - - block.Size = LayoutInt.AlignUp(block.Size, sizeAndAlignment.Alignment, context.Target); - result.Offsets[index] = new FieldAndOffset(field, block.Size); - block.Size = block.Size + sizeAndAlignment.Size; - - block.LargestAlignment = LayoutInt.Max(block.LargestAlignment, sizeAndAlignment.Alignment); - - index++; - } - - FinalizeRuntimeSpecificStaticFieldLayout(context, ref result); - - return result; - } - - private ref StaticsBlock GetStaticsBlockForField(ref ComputedStaticFieldLayout layout, FieldDesc field) - { - if (field.IsThreadStatic) - { - if (field.HasGCStaticBase) - return ref layout.ThreadGcStatics; - else - return ref layout.ThreadNonGcStatics; - } - else if (field.HasGCStaticBase) - return ref layout.GcStatics; - else - return ref layout.NonGcStatics; - } - - public override bool ComputeContainsGCPointers(DefType type) - { - bool someFieldContainsPointers = false; - - foreach (var field in type.GetFields()) - { - if (field.IsStatic) - continue; - - TypeDesc fieldType = field.FieldType; - if (fieldType.IsValueType) - { - if (fieldType.IsPrimitive) - continue; - - if (((DefType)fieldType).ContainsGCPointers) - { - someFieldContainsPointers = true; - break; - } - } - else if (fieldType.IsGCPointer) - { - someFieldContainsPointers = true; - break; - } - } - - return someFieldContainsPointers; - } - - /// - /// Called during static field layout to setup initial contents of statics blocks - /// - protected virtual void PrepareRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout) - { - } - - /// - /// Called during static field layout to finish static block layout - /// - protected virtual void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout) - { - } - - protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields) - { - // Instance slice size is the total size of instance not including the base type. - // It is calculated as the field whose offset and size add to the greatest value. - LayoutInt cumulativeInstanceFieldPos = - type.HasBaseType && !type.IsValueType ? type.BaseType.InstanceByteCount : LayoutInt.Zero; - LayoutInt instanceSize = cumulativeInstanceFieldPos; - - var layoutMetadata = type.GetClassLayout(); - - int packingSize = ComputePackingSize(type, layoutMetadata); - LayoutInt largestAlignmentRequired = LayoutInt.One; - - var offsets = new FieldAndOffset[numInstanceFields]; - int fieldOrdinal = 0; - - foreach (var fieldAndOffset in layoutMetadata.Offsets) - { - TypeDesc fieldType = fieldAndOffset.Field.FieldType; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize); - - largestAlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequired); - - if (fieldAndOffset.Offset == FieldAndOffset.InvalidOffset) - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type); - - LayoutInt computedOffset = fieldAndOffset.Offset + cumulativeInstanceFieldPos; - - // GC pointers MUST be aligned. - // We treat byref-like structs as GC pointers too. - bool needsToBeAligned = - !computedOffset.IsIndeterminate - && - ( - fieldType.IsGCPointer - || fieldType.IsByRefLike - || (fieldType.IsValueType && ((DefType)fieldType).ContainsGCPointers) - ); - if (needsToBeAligned) - { - int offsetModulo = computedOffset.AsInt % type.Context.Target.PointerSize; - if (offsetModulo != 0) - { - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadExplicitLayout, type, fieldAndOffset.Offset.ToStringInvariant()); - } - } - - offsets[fieldOrdinal] = new FieldAndOffset(fieldAndOffset.Field, computedOffset); - - LayoutInt fieldExtent = computedOffset + fieldSizeAndAlignment.Size; - instanceSize = LayoutInt.Max(fieldExtent, instanceSize); - - fieldOrdinal++; - } - - if (type.IsValueType) - { - instanceSize = LayoutInt.Max(new LayoutInt(layoutMetadata.Size), instanceSize); - } - - SizeAndAlignment instanceByteSizeAndAlignment; - var instanceSizeAndAlignment = ComputeInstanceSize(type, instanceSize, largestAlignmentRequired, out instanceByteSizeAndAlignment); - - ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); - computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; - computedLayout.FieldSize = instanceSizeAndAlignment.Size; - computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; - computedLayout.ByteCountAlignment = instanceByteSizeAndAlignment.Alignment; - computedLayout.Offsets = offsets; - - ExplicitLayoutValidator.Validate(type, computedLayout); - - return computedLayout; - } - - protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType type, int numInstanceFields) - { - var offsets = new FieldAndOffset[numInstanceFields]; - - // For types inheriting from another type, field offsets continue on from where they left off - LayoutInt cumulativeInstanceFieldPos = ComputeBytesUsedInParentType(type); - - var layoutMetadata = type.GetClassLayout(); - - LayoutInt largestAlignmentRequirement = LayoutInt.One; - int fieldOrdinal = 0; - int packingSize = ComputePackingSize(type, layoutMetadata); - - foreach (var field in type.GetFields()) - { - if (field.IsStatic) - continue; - - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize); - - largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement); - - cumulativeInstanceFieldPos = LayoutInt.AlignUp(cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, type.Context.Target); - offsets[fieldOrdinal] = new FieldAndOffset(field, cumulativeInstanceFieldPos); - cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + fieldSizeAndAlignment.Size); - - fieldOrdinal++; - } - - if (type.IsValueType) - { - cumulativeInstanceFieldPos = LayoutInt.Max(cumulativeInstanceFieldPos, new LayoutInt(layoutMetadata.Size)); - } - - SizeAndAlignment instanceByteSizeAndAlignment; - var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, largestAlignmentRequirement, out instanceByteSizeAndAlignment); - - ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); - computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; - computedLayout.FieldSize = instanceSizeAndAlignment.Size; - computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; - computedLayout.ByteCountAlignment = instanceByteSizeAndAlignment.Alignment; - computedLayout.Offsets = offsets; - - return computedLayout; - } - - protected virtual void AlignBaseOffsetIfNecessary(MetadataType type, ref LayoutInt baseOffset) - { - } - - protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, int numInstanceFields) - { - // For types inheriting from another type, field offsets continue on from where they left off - LayoutInt cumulativeInstanceFieldPos = ComputeBytesUsedInParentType(type); - - AlignBaseOffsetIfNecessary(type, ref cumulativeInstanceFieldPos); - - var layoutMetadata = type.GetClassLayout(); - - int packingSize = ComputePackingSize(type, layoutMetadata); - - var offsets = new FieldAndOffset[numInstanceFields]; - int fieldOrdinal = 0; - - TypeSystemContext context = type.Context; - - // Iterate over the instance fields and keep track of the number of fields of each category - // For the non-GC Pointer fields, we will keep track of the number of fields by log2(size) - int maxLog2Size = CalculateLog2(TargetDetails.MaximumPrimitiveSize); - int log2PointerSize = CalculateLog2(context.Target.PointerSize); - int instanceValueClassFieldCount = 0; - int instanceGCPointerFieldsCount = 0; - int[] instanceNonGCPointerFieldsCount = new int[maxLog2Size + 1]; - - foreach (var field in type.GetFields()) - { - if (field.IsStatic) - continue; - - TypeDesc fieldType = field.FieldType; - if (IsByValueClass(fieldType)) - { - instanceValueClassFieldCount++; - } - else if (fieldType.IsGCPointer) - { - instanceGCPointerFieldsCount++; - } - else - { - Debug.Assert(fieldType.IsPrimitive || fieldType.IsPointer || fieldType.IsFunctionPointer || fieldType.IsEnum); - - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize); - instanceNonGCPointerFieldsCount[CalculateLog2(fieldSizeAndAlignment.Size.AsInt)]++; - } - } - - // Initialize three different sets of lists to hold the instance fields - // 1. Array of value class fields - // 2. Array of GC Pointer fields - // 3. Jagged array of remaining fields. To access the fields of size n, you must index the first array at index log2(n) - FieldDesc[] instanceValueClassFieldsArr = new FieldDesc[instanceValueClassFieldCount]; - FieldDesc[] instanceGCPointerFieldsArr = new FieldDesc[instanceGCPointerFieldsCount]; - FieldDesc[][] instanceNonGCPointerFieldsArr = new FieldDesc[maxLog2Size + 1][]; - - for (int i = 0; i <= maxLog2Size; i++) - { - instanceNonGCPointerFieldsArr[i] = new FieldDesc[instanceNonGCPointerFieldsCount[i]]; - - // Reset the counters to be used later as the index to insert into the arrays - instanceNonGCPointerFieldsCount[i] = 0; - } - - // Reset the counters to be used later as the index to insert into the array - instanceGCPointerFieldsCount = 0; - instanceValueClassFieldCount = 0; - - // Iterate over all fields and do the following - // - Add instance fields to the appropriate array (while maintaining the enumerated order) - // - Save the largest alignment we've seen - foreach (var field in type.GetFields()) - { - if (field.IsStatic) - continue; - - TypeDesc fieldType = field.FieldType; - - if (IsByValueClass(fieldType)) - { - instanceValueClassFieldsArr[instanceValueClassFieldCount++] = field; - } - else if (fieldType.IsGCPointer) - { - instanceGCPointerFieldsArr[instanceGCPointerFieldsCount++] = field; - } - else - { - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize); - int log2size = CalculateLog2(fieldSizeAndAlignment.Size.AsInt); - instanceNonGCPointerFieldsArr[log2size][instanceNonGCPointerFieldsCount[log2size]++] = field; - } - } - - // We've finished placing the fields into their appropriate arrays - // The next optimization may place non-GC Pointers, so repurpose our - // counter to keep track of the next non-GC Pointer that must be placed - // for a given field size - Array.Clear(instanceNonGCPointerFieldsCount, 0, instanceNonGCPointerFieldsCount.Length); - - // If the position is Indeterminate, proceed immediately to placing the fields - // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments - if (!cumulativeInstanceFieldPos.IsIndeterminate) - { - // First, place small fields immediately after the parent field bytes if there are a number of field bytes that are not aligned - // GC pointer fields and value class fields are not considered for this optimization - int parentByteOffsetModulo = cumulativeInstanceFieldPos.AsInt % context.Target.PointerSize; - if (parentByteOffsetModulo != 0) - { - for (int i = 0; i < maxLog2Size; i++) - { - int j; - - // Check if the position is aligned such that we could place a larger type - int offsetModulo = cumulativeInstanceFieldPos.AsInt % (1 << (i+1)); - if (offsetModulo == 0) - { - continue; - } - - // Check whether there are any bigger fields - // We must consider both GC Pointers and non-GC Pointers - for (j = i + 1; j <= maxLog2Size; j++) - { - // Check if there are any elements left to place of the given size - if (instanceNonGCPointerFieldsCount[j] < instanceNonGCPointerFieldsArr[j].Length - || (j == log2PointerSize && instanceGCPointerFieldsArr.Length > 0)) - break; - } - - // Nothing to gain if there are no bigger fields - // (the subsequent loop will place fields from large to small fields) - if (j > maxLog2Size) - break; - - // Check whether there are any small enough fields - // We must consider both GC Pointers and non-GC Pointers - for (j = i; j >= 0; j--) - { - if (instanceNonGCPointerFieldsCount[j] < instanceNonGCPointerFieldsArr[j].Length - || (j == log2PointerSize && instanceGCPointerFieldsArr.Length > 0)) - break; - } - - // Nothing to do if there are no smaller fields - if (j < 0) - break; - - // Go back and use the smaller field as filling - i = j; - - // Assert that we have at least one field of this size - Debug.Assert(instanceNonGCPointerFieldsCount[i] < instanceNonGCPointerFieldsArr[i].Length - || (i == log2PointerSize && instanceGCPointerFieldsArr.Length > 0)); - - // Avoid reordering of gc fields - // Exit if there are no more non-GC fields of this size (pointer size) to place - if (i == log2PointerSize) - { - if (instanceNonGCPointerFieldsCount[i] >= instanceNonGCPointerFieldsArr[i].Length) - break; - } - - // Place the field - j = instanceNonGCPointerFieldsCount[i]; - FieldDesc field = instanceNonGCPointerFieldsArr[i][j]; - PlaceInstanceField(field, packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal); - - instanceNonGCPointerFieldsCount[i]++; - } - } - } - - // Next, place GC pointer fields and non-GC pointer fields - // Starting with the largest-sized fields, place the GC pointer fields in order then place the non-GC pointer fields in order. - // Once the largest-sized fields are placed, repeat with the next-largest-sized group of fields and continue. - for (int i = maxLog2Size; i >= 0; i--) - { - // First, if we're placing the size that also corresponds to the pointer size, place GC pointer fields in order - if (i == log2PointerSize) - { - for (int j = 0; j < instanceGCPointerFieldsArr.Length; j++) - { - PlaceInstanceField(instanceGCPointerFieldsArr[j], packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal); - } - } - - // The start index will be the index that may have been increased in the previous optimization - for (int j = instanceNonGCPointerFieldsCount[i]; j < instanceNonGCPointerFieldsArr[i].Length; j++) - { - PlaceInstanceField(instanceNonGCPointerFieldsArr[i][j], packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal); - } - } - - // Place value class fields last - for (int i = 0; i < instanceValueClassFieldsArr.Length; i++) - { - // If the field has an indeterminate alignment, align the cumulative field offset to the indeterminate value - // Otherwise, align the cumulative field offset to the PointerSize - // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(instanceValueClassFieldsArr[i].FieldType, packingSize); - - if (fieldSizeAndAlignment.Alignment.IsIndeterminate) - { - cumulativeInstanceFieldPos = LayoutInt.AlignUp(cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, context.Target); - } - else - { - cumulativeInstanceFieldPos = LayoutInt.AlignUp(cumulativeInstanceFieldPos, context.Target.LayoutPointerSize, context.Target); - } - offsets[fieldOrdinal] = new FieldAndOffset(instanceValueClassFieldsArr[i], cumulativeInstanceFieldPos); - - // If the field has an indeterminate size, align the cumulative field offset to the indeterminate value - // Otherwise, align the cumulative field offset to the aligned-instance field size - // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments - LayoutInt alignedInstanceFieldBytes = fieldSizeAndAlignment.Size.IsIndeterminate ? fieldSizeAndAlignment.Size : GetAlignedNumInstanceFieldBytes(fieldSizeAndAlignment.Size); - cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + alignedInstanceFieldBytes); - - fieldOrdinal++; - } - - if (type.IsValueType) - { - cumulativeInstanceFieldPos = LayoutInt.Max(cumulativeInstanceFieldPos, new LayoutInt(layoutMetadata.Size)); - } - - // The JITs like to copy full machine words, - // so if the size is bigger than a void* round it up to minAlign - // and if the size is smaller than void* round it up to next power of two - LayoutInt minAlign; - if (cumulativeInstanceFieldPos.IsIndeterminate) - { - minAlign = LayoutInt.Indeterminate; - } - else if (cumulativeInstanceFieldPos.AsInt > type.Context.Target.PointerSize) - { - minAlign = type.Context.Target.LayoutPointerSize; - } - else - { - minAlign = new LayoutInt(1); - while (minAlign.AsInt < cumulativeInstanceFieldPos.AsInt) - minAlign = new LayoutInt(minAlign.AsInt * 2); - } - - SizeAndAlignment instanceByteSizeAndAlignment; - var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, minAlign, out instanceByteSizeAndAlignment); - - ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); - computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; - computedLayout.FieldSize = instanceSizeAndAlignment.Size; - computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; - computedLayout.ByteCountAlignment = instanceByteSizeAndAlignment.Alignment; - computedLayout.Offsets = offsets; - - return computedLayout; - } - - private static void PlaceInstanceField(FieldDesc field, int packingSize, FieldAndOffset[] offsets, ref LayoutInt instanceFieldPos, ref int fieldOrdinal) - { - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize); - - instanceFieldPos = LayoutInt.AlignUp(instanceFieldPos, fieldSizeAndAlignment.Alignment, field.Context.Target); - offsets[fieldOrdinal] = new FieldAndOffset(field, instanceFieldPos); - instanceFieldPos = checked(instanceFieldPos + fieldSizeAndAlignment.Size); - - fieldOrdinal++; - } - - // The aligned instance field bytes calculation here matches the calculation of CoreCLR MethodTable::GetAlignedNumInstanceFieldBytes - // This will calculate the next multiple of 4 that is greater than or equal to the instance size - private static LayoutInt GetAlignedNumInstanceFieldBytes(LayoutInt instanceSize) - { - uint inputSize = (uint) instanceSize.AsInt; - uint result = (uint)(((inputSize + 3) & (~3))); - return new LayoutInt((int) result); - } - - private static int CalculateLog2(int size) - { - // Size must be a positive number - Debug.Assert(size > 0); - - // Size must be a power of 2 - Debug.Assert( 0 == (size & (size - 1))); - - int log2size; - for (log2size = 0; size > 1; log2size++) - { - size = size >> 1; - } - - return log2size; - } - - private static bool IsByValueClass(TypeDesc type) - { - return type.IsValueType && !type.IsPrimitive && !type.IsEnum; - } - - private static LayoutInt ComputeBytesUsedInParentType(DefType type) - { - LayoutInt cumulativeInstanceFieldPos = LayoutInt.Zero; - - if (!type.IsValueType && type.HasBaseType) - { - cumulativeInstanceFieldPos = type.BaseType.InstanceByteCountUnaligned; - } - - return cumulativeInstanceFieldPos; - } - - private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, int packingSize) - { - SizeAndAlignment result; - - if (fieldType.IsDefType) - { - if (fieldType.IsValueType) - { - DefType metadataType = (DefType)fieldType; - result.Size = metadataType.InstanceFieldSize; - result.Alignment = metadataType.InstanceFieldAlignment; - } - else - { - result.Size = fieldType.Context.Target.LayoutPointerSize; - result.Alignment = fieldType.Context.Target.LayoutPointerSize; - } - } - else if (fieldType.IsArray) - { - // This could use InstanceFieldSize/Alignment (and those results should match what's here) - // but, its more efficient to just assume pointer size instead of fulling processing - // the instance field layout of fieldType here. - result.Size = fieldType.Context.Target.LayoutPointerSize; - result.Alignment = fieldType.Context.Target.LayoutPointerSize; - } - else - { - Debug.Assert(fieldType.IsPointer || fieldType.IsFunctionPointer); - result.Size = fieldType.Context.Target.LayoutPointerSize; - result.Alignment = fieldType.Context.Target.LayoutPointerSize; - } - - result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize)); - - return result; - } - - private static int ComputePackingSize(MetadataType type, ClassLayoutMetadata layoutMetadata) - { - // If a type contains pointers then the metadata specified packing size is ignored (On desktop this is disqualification from ManagedSequential) - if (layoutMetadata.PackingSize == 0 || type.ContainsGCPointers) - return type.Context.Target.DefaultPackingSize; - else - return layoutMetadata.PackingSize; - } - - private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, out SizeAndAlignment byteCount) - { - SizeAndAlignment result; - - TargetDetails target = type.Context.Target; - - // Pad the length of structs to be 1 if they are empty so we have no zero-length structures - if (type.IsValueType && instanceSize == LayoutInt.Zero) - { - instanceSize = LayoutInt.One; - } - - if (type.IsValueType) - { - instanceSize = LayoutInt.AlignUp(instanceSize, alignment, target); - result.Size = instanceSize; - result.Alignment = alignment; - } - else - { - result.Size = target.LayoutPointerSize; - result.Alignment = target.LayoutPointerSize; - if (type.HasBaseType) - alignment = LayoutInt.Max(alignment, type.BaseType.InstanceByteAlignment); - } - - // Determine the alignment needed by the type when allocated - // This is target specific, and not just pointer sized due to - // 8 byte alignment requirements on ARM for longs and doubles - alignment = target.GetObjectAlignment(alignment); - - byteCount.Size = instanceSize; - byteCount.Alignment = alignment; - - return result; - } - - public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) - { - if (!type.IsValueType) - return ValueTypeShapeCharacteristics.None; - - ValueTypeShapeCharacteristics result = ComputeHomogeneousFloatAggregateCharacteristic(type); - - // TODO: System V AMD64 characteristics (https://github.com/dotnet/corert/issues/158) - - return result; - } - - private ValueTypeShapeCharacteristics ComputeHomogeneousFloatAggregateCharacteristic(DefType type) - { - Debug.Assert(type.IsValueType); - - MetadataType metadataType = (MetadataType)type; - - // No HFAs with explicit layout. There may be cases where explicit layout may be still - // eligible for HFA, but it is hard to tell the real intent. Make it simple and just - // unconditionally disable HFAs for explicit layout. - if (metadataType.IsExplicitLayout) - return ValueTypeShapeCharacteristics.None; - - switch (metadataType.Category) - { - case TypeFlags.Single: - case TypeFlags.Double: - // These are the primitive types that constitute a HFA type. - return ValueTypeShapeCharacteristics.HomogenousFloatAggregate; - - case TypeFlags.ValueType: - DefType expectedElementType = null; - - foreach (FieldDesc field in metadataType.GetFields()) - { - if (field.IsStatic) - continue; - - // If a field isn't a DefType, then this type cannot be an HFA type - // If a field isn't a HFA type, then this type cannot be an HFA type - DefType fieldType = field.FieldType as DefType; - if (fieldType == null || !fieldType.IsHfa) - return ValueTypeShapeCharacteristics.None; - - if (expectedElementType == null) - { - // If we hadn't yet figured out what form of HFA this type might be, we've - // now found one case. - expectedElementType = fieldType.HfaElementType; - Debug.Assert(expectedElementType != null); - } - else if (expectedElementType != fieldType.HfaElementType) - { - // If we had already determined the possible HFA type of the current type, but - // the field we've encountered is not of that type, then the current type cannot - // be an HFA type. - return ValueTypeShapeCharacteristics.None; - } - } - - // No fields means this is not HFA. - if (expectedElementType == null) - return ValueTypeShapeCharacteristics.None; - - // Types which are indeterminate in field size are not considered to be HFA - if (expectedElementType.InstanceFieldSize.IsIndeterminate) - return ValueTypeShapeCharacteristics.None; - - // Types which are indeterminate in field size are not considered to be HFA - if (type.InstanceFieldSize.IsIndeterminate) - return ValueTypeShapeCharacteristics.None; - - // Note that we check the total size, but do not perform any checks on number of fields: - // - Type of fields can be HFA valuetype itself - // - Managed C++ HFA valuetypes have just one of type float to signal that - // the valuetype is HFA and explicitly specified size - int maxSize = expectedElementType.InstanceFieldSize.AsInt * expectedElementType.Context.Target.MaximumHfaElementCount; - if (type.InstanceFieldSize.AsInt > maxSize) - return ValueTypeShapeCharacteristics.None; - - // All the tests passed. This is an HFA type. - return ValueTypeShapeCharacteristics.HomogenousFloatAggregate; - } - - return ValueTypeShapeCharacteristics.None; - } - - public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) - { - if (!type.IsHfa) - return null; - - if (type.IsWellKnownType(WellKnownType.Double) || type.IsWellKnownType(WellKnownType.Single)) - return type; - - for (; ; ) - { - Debug.Assert(type.IsValueType); - - // All HFA fields have to be of the same HFA type, so we can just return the type of the first field - TypeDesc firstFieldType = null; - foreach (var field in type.GetFields()) - { - if (field.IsStatic) - continue; - - firstFieldType = field.FieldType; - break; - } - Debug.Assert(firstFieldType != null, "Why is IsHfa true on this type?"); - - switch (firstFieldType.Category) - { - case TypeFlags.Single: - case TypeFlags.Double: - return (DefType)firstFieldType; - - case TypeFlags.ValueType: - // Drill into the struct and find the type of its first field - type = (DefType)firstFieldType; - break; - - default: - Debug.Fail("Why is IsHfa true on this type?"); - return null; - } - } - } - - private struct SizeAndAlignment - { - public LayoutInt Size; - public LayoutInt Alignment; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataRuntimeInterfacesAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataRuntimeInterfacesAlgorithm.cs deleted file mode 100644 index 4b71985bfbe..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataRuntimeInterfacesAlgorithm.cs +++ /dev/null @@ -1,98 +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 System.Collections.Generic; -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// Metadata based RuntimeInterfaces algorithm which can be used to compute the - /// RuntimeInterfaces for any MetadataType based on the base types RuntimeInterfaces - /// and the MetadataTypes explicit interfaces. - /// - public sealed class MetadataRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm - { - public override DefType[] ComputeRuntimeInterfaces(TypeDesc _type) - { - MetadataType type = (MetadataType)_type; - - // TODO: need to implement deduplication - // https://github.com/dotnet/corert/issues/208 - - if (type.IsInterface) - { - // For interfaces, the set of interfaces implemented directly matches the - // explicitly implemented interface list - return type.ExplicitlyImplementedInterfaces; - } - else if (type is InstantiatedType) - { - return ComputeRuntimeInterfacesForInstantiatedType((InstantiatedType)type); - } - else - { - return ComputeRuntimeInterfacesForNonInstantiatedMetadataType(type); - } - } - - /// - /// Instantiated type computation for runtime interfaces. Instantiated types - /// must have the same count of interfaces across all possible instantiations - /// so the algorithm works by computing the uninstantiated form, and then - /// specializing each interface as needed. - /// - private DefType[] ComputeRuntimeInterfacesForInstantiatedType(InstantiatedType instantiatedType) - { - MetadataType uninstantiatedType = (MetadataType)instantiatedType.GetTypeDefinition(); - - DefType[] genericTypeDefinitionInterfaces = uninstantiatedType.RuntimeInterfaces; - - return InstantiatedType.InstantiateTypeArray(uninstantiatedType.RuntimeInterfaces, instantiatedType.Instantiation, new Instantiation()); - } - - /// - /// Metadata based computation of interfaces. - /// - private DefType[] ComputeRuntimeInterfacesForNonInstantiatedMetadataType(MetadataType type) - { - DefType[] explicitInterfaces = type.ExplicitlyImplementedInterfaces; - DefType[] baseTypeInterfaces = (type.BaseType != null) ? (type.BaseType.RuntimeInterfaces) : Array.Empty(); - - // Optimized case for no interfaces newly defined. - if (explicitInterfaces.Length == 0) - return baseTypeInterfaces; - - ArrayBuilder interfacesArray = new ArrayBuilder(); - interfacesArray.Append(baseTypeInterfaces); - - foreach (DefType iface in explicitInterfaces) - { - BuildPostOrderInterfaceList(iface, ref interfacesArray); - } - - return interfacesArray.ToArray(); - } - - /// - /// Add an interface and its required interfaces to the interfacesArray - /// - private void BuildPostOrderInterfaceList(DefType iface, ref ArrayBuilder interfacesArray) - { - if (interfacesArray.Contains(iface)) - return; - - foreach (DefType implementedInterface in iface.RuntimeInterfaces) - { - BuildPostOrderInterfaceList(implementedInterface, ref interfacesArray); - } - - if (interfacesArray.Contains(iface)) - return; - - interfacesArray.Add(iface); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.Interfaces.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.Interfaces.cs deleted file mode 100644 index e6fd004d932..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.Interfaces.cs +++ /dev/null @@ -1,23 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Api surface definition for interfaces that all MetadataTypes must implement - - public abstract partial class MetadataType : DefType - { - /// - /// The interfaces explicitly declared as implemented by this MetadataType in the type's metadata. - /// These correspond to the InterfaceImpls of a type in metadata - /// - public abstract DefType[] ExplicitlyImplementedInterfaces - { - get; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.MethodImpls.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.MethodImpls.cs deleted file mode 100644 index b41133e36fa..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.MethodImpls.cs +++ /dev/null @@ -1,55 +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; - -namespace Internal.TypeSystem -{ - public struct MethodImplRecord - { - public readonly MethodDesc Decl; - public readonly MethodDesc Body; - - public MethodImplRecord(MethodDesc decl, MethodDesc body) - { - Decl = decl; - Body = body; - } - } - - // MethodImpl api surface for types. - public partial class MetadataType - { - /// - /// Compute an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type. - /// May be expensive. - /// - protected abstract MethodImplRecord[] ComputeVirtualMethodImplsForType(); - - private MethodImplRecord[] _allVirtualMethodImplsForType; - /// - /// Get an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type. - /// Expected to cache results so this api can be used repeatedly. - /// - public MethodImplRecord[] VirtualMethodImplsForType - { - get - { - if (_allVirtualMethodImplsForType == null) - { - _allVirtualMethodImplsForType = ComputeVirtualMethodImplsForType(); - } - - return _allVirtualMethodImplsForType; - } - } - - /// - /// Get an array of MethodImpls where the Decl method matches by name with the specified name. - /// - /// - /// - public abstract MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.cs deleted file mode 100644 index 9fe484c9a01..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataType.cs +++ /dev/null @@ -1,114 +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.Collections.Generic; - -namespace Internal.TypeSystem -{ - /// - /// Type with metadata available that is equivalent to a TypeDef record in an ECMA 335 metadata stream. - /// A class, an interface, or a value type. - /// - public abstract partial class MetadataType : DefType - { - public abstract override string Name { get; } - - public abstract override string Namespace { get; } - - /// - /// Gets metadata that controls instance layout of this type. - /// - public abstract ClassLayoutMetadata GetClassLayout(); - - /// - /// If true, the type layout is dictated by the explicit layout rules provided. - /// Corresponds to the definition of explicitlayout semantic defined in the ECMA-335 specification. - /// - public abstract bool IsExplicitLayout { get; } - - /// - /// If true, the order of the fields needs to be preserved. Corresponds to the definition - /// of sequentiallayout semantic defined in the ECMA-335 specification. - /// - public abstract bool IsSequentialLayout { get; } - - /// - /// If true, the type initializer of this type has a relaxed semantic. Corresponds - /// to the definition of beforefieldinit semantic defined in the ECMA-335 specification. - /// - public abstract bool IsBeforeFieldInit { get; } - - /// - /// If true, this is the special <Module> type that contains the definitions - /// of global fields and methods in the module. - /// - public virtual bool IsModuleType - { - get - { - return Module.GetGlobalModuleType() == this; - } - } - - /// - /// Gets the module that defines this type. - /// - public abstract ModuleDesc Module { get; } - - /// - /// Same as , but the result is a MetadataType (avoids casting). - /// - public abstract MetadataType MetadataBaseType { get; } - - /// - /// If true, the type cannot be used as a base type of any other type. - /// - public abstract bool IsSealed { get; } - - /// - /// Gets a value indicating whether the type is abstract and cannot be allocated. - /// - public abstract bool IsAbstract { get; } - - /// - /// Returns true if the type has given custom attribute. - /// - public abstract bool HasCustomAttribute(string attributeNamespace, string attributeName); - - public abstract override DefType ContainingType { get; } - - /// - /// Get all of the types nested in this type. - /// - public abstract IEnumerable GetNestedTypes(); - - /// - /// Get a specific type nested in this type. Returns null if the type - /// doesn't exist. - /// - public abstract MetadataType GetNestedType(string name); - } - - public struct ClassLayoutMetadata - { - public int PackingSize; - public int Size; - public FieldAndOffset[] Offsets; - } - - public struct FieldAndOffset - { - public static readonly LayoutInt InvalidOffset = new LayoutInt(int.MaxValue); - - public readonly FieldDesc Field; - - public readonly LayoutInt Offset; - - public FieldAndOffset(FieldDesc field, LayoutInt offset) - { - Field = field; - Offset = offset; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataTypeSystemContext.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataTypeSystemContext.cs deleted file mode 100644 index 2d8a9378cc5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataTypeSystemContext.cs +++ /dev/null @@ -1,104 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public abstract partial class MetadataTypeSystemContext : TypeSystemContext - { - private static readonly string[] s_wellKnownTypeNames = new string[] { - "Void", - - "Boolean", - "Char", - "SByte", - "Byte", - "Int16", - "UInt16", - "Int32", - "UInt32", - "Int64", - "UInt64", - "IntPtr", - "UIntPtr", - "Single", - "Double", - - "ValueType", - "Enum", - "Nullable`1", - - "Object", - "String", - "Array", - "MulticastDelegate", - - "RuntimeTypeHandle", - "RuntimeMethodHandle", - "RuntimeFieldHandle", - - "Exception", - - "TypedReference", - "ByReference`1", - }; - - private MetadataType[] _wellKnownTypes; - - public MetadataTypeSystemContext() - { - } - - public MetadataTypeSystemContext(TargetDetails details) - : base(details) - { - } - - public virtual void SetSystemModule(ModuleDesc systemModule) - { - InitializeSystemModule(systemModule); - - // Sanity check the name table - Debug.Assert(s_wellKnownTypeNames[(int)WellKnownType.MulticastDelegate - 1] == "MulticastDelegate"); - - _wellKnownTypes = new MetadataType[s_wellKnownTypeNames.Length]; - - // Initialize all well known types - it will save us from checking the name for each loaded type - for (int typeIndex = 0; typeIndex < _wellKnownTypes.Length; typeIndex++) - { - // Require System.Object to be present as a minimal sanity check. - // The set of required well-known types is not strictly defined since different .NET profiles implement different subsets. - MetadataType type = systemModule.GetType("System", s_wellKnownTypeNames[typeIndex], typeIndex == (int)WellKnownType.Object); - if (type != null) - { - type.SetWellKnownType((WellKnownType)(typeIndex + 1)); - _wellKnownTypes[typeIndex] = type; - } - } - } - - public override DefType GetWellKnownType(WellKnownType wellKnownType, bool throwIfNotFound = true) - { - Debug.Assert(_wellKnownTypes != null, "Forgot to call SetSystemModule?"); - - int typeIndex = (int)wellKnownType - 1; - DefType type = _wellKnownTypes[typeIndex]; - if (type == null && throwIfNotFound) - ThrowHelper.ThrowTypeLoadException("System", s_wellKnownTypeNames[typeIndex], SystemModule); - - return type; - } - - protected sealed internal override bool ComputeHasStaticConstructor(TypeDesc type) - { - if (type is MetadataType) - { - return ((MetadataType)type).GetStaticConstructor() != null; - } - return false; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs deleted file mode 100644 index d27fbf6b480..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs +++ /dev/null @@ -1,677 +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 System.Collections.Generic; -using System.Diagnostics; - -namespace Internal.TypeSystem -{ - public class MetadataVirtualMethodAlgorithm : VirtualMethodAlgorithm - { - private class MethodDescHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(MethodDesc key) - { - return key.GetHashCode(); - } - - protected override int GetValueHashCode(MethodDesc value) - { - return value.GetHashCode(); - } - - protected override bool CompareKeyToValue(MethodDesc key, MethodDesc value) - { - Debug.Assert(key.Context == value.Context); - return Object.ReferenceEquals(key, value); - } - - protected override bool CompareValueToValue(MethodDesc value1, MethodDesc value2) - { - Debug.Assert(value1.Context == value2.Context); - return Object.ReferenceEquals(value1, value2); - } - - protected override MethodDesc CreateValueFromKey(MethodDesc key) - { - return key; - } - } - - private class UnificationGroup - { - private MethodDesc[] _members = MethodDesc.EmptyMethods; - private int _memberCount = 0; - - /// - /// Custom enumerator struct for Unification group. Makes enumeration require 0 allocations. - /// - public struct Enumerator - { - private MethodDesc[] _arrayToEnumerate; - private int _index; - private MethodDesc _current; - - internal Enumerator(MethodDesc[] arrayToEnumerate) - { - _arrayToEnumerate = arrayToEnumerate; - _index = 0; - _current = default(MethodDesc); - } - - public bool MoveNext() - { - for (; _index < _arrayToEnumerate.Length; _index++) - { - if (_arrayToEnumerate[_index] != null) - { - _current = _arrayToEnumerate[_index]; - _index++; - return true; - } - } - - _current = default(MethodDesc); - return false; - } - - public MethodDesc Current - { - get - { - return _current; - } - } - } - - public UnificationGroup(MethodDesc definingMethod) - { - DefiningMethod = definingMethod; - // TODO! Add assertion that DefiningMethod is a slot defining method - } - - public MethodDesc DefiningMethod; - - public Enumerator GetEnumerator() - { - return new Enumerator(_members); - } - - public void SetDefiningMethod(MethodDesc newDefiningMethod) - { - // Do not change the defining method if its the same as - // one of the members, or it isn't a change at all - if (!IsInGroup(newDefiningMethod) && - DefiningMethod != newDefiningMethod) - { - // When we set the defining method, ensure that the old defining method isn't removed from the group - MethodDesc oldDefiningMethod = DefiningMethod; - DefiningMethod = newDefiningMethod; - AddToGroup(oldDefiningMethod); - - // TODO! Add assertion that DefiningMethod is a slot defining method - } - } - - public void AddToGroup(MethodDesc method) - { - if (method == DefiningMethod) - return; - - if (!IsInGroup(method)) - { - _memberCount++; - if (_memberCount >= _members.Length) - { - Array.Resize(ref _members, Math.Max(_members.Length * 2, 2)); - } - for (int i = 0; i < _members.Length; i++) - { - if (_members[i] == null) - { - _members[i] = method; - break; - } - } - } - } - - public void RemoveFromGroup(MethodDesc method) - { - if (method == DefiningMethod) - throw new BadImageFormatException(); - - for (int i = 0; i < _members.Length; i++) - { - if (_members[i] == method) - { - _memberCount--; - _members[i] = null; - return; - } - } - } - - public bool IsInGroupOrIsDefiningSlot(MethodDesc method) - { - if (DefiningMethod == method) - return true; - - return IsInGroup(method); - } - - public bool IsInGroup(MethodDesc method) - { - for (int i = 0; i < _members.Length; i++) - { - if (_members[i] == method) - return true; - } - - return false; - } - } - - public override MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, TypeDesc objectType) - { - return FindVirtualFunctionTargetMethodOnObjectType(targetMethod, (MetadataType)objectType); - } - - /// - /// Resolve a virtual function call (to a virtual method, not an interface method) - /// - /// - /// - /// The override of the virtual method that should be called - private static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, MetadataType objectType) - { - // Step 1, convert objectType to uninstantiated form - MetadataType uninstantiatedType = objectType; - MethodDesc initialTargetMethod = targetMethod; - InstantiatedType initialInstantiatedType = objectType as InstantiatedType; - if (initialInstantiatedType != null) - { - uninstantiatedType = (MetadataType)initialInstantiatedType.GetTypeDefinition(); - } - - // Step 2, convert targetMethod to method in type hierarchy of uninstantiated form - targetMethod = targetMethod.GetMethodDefinition(); - if (uninstantiatedType != objectType) - { - targetMethod = uninstantiatedType.FindMethodOnTypeWithMatchingTypicalMethod(targetMethod); - } - - // Step 3, find unification group of target method - UnificationGroup group = new UnificationGroup(FindSlotDefiningMethodForVirtualMethod(targetMethod)); - FindBaseUnificationGroup(uninstantiatedType, group); - - // Step 4, name/sig match virtual function resolve - MethodDesc resolutionTarget = FindNameSigOverrideForVirtualMethod(group.DefiningMethod, uninstantiatedType); - if (resolutionTarget == null) - return null; - - // Step 5, convert resolution target from uninstantiated form target to objecttype target, - // and instantiate as appropriate - if (uninstantiatedType != objectType) - { - resolutionTarget = objectType.FindMethodOnTypeWithMatchingTypicalMethod(resolutionTarget); - } - if (initialTargetMethod.HasInstantiation) - { - resolutionTarget = resolutionTarget.MakeInstantiatedMethod(initialTargetMethod.Instantiation); - } - - return resolutionTarget; - } - - private static bool IsInterfaceImplementedOnType(MetadataType type, MetadataType interfaceType) - { - foreach (TypeDesc iface in type.RuntimeInterfaces) - { - if (iface == interfaceType) - return true; - } - return false; - } - - private static MethodDesc FindImplFromDeclFromMethodImpls(MetadataType type, MethodDesc decl) - { - MethodImplRecord[] foundMethodImpls = type.FindMethodsImplWithMatchingDeclName(decl.Name); - - if (foundMethodImpls == null) - return null; - - bool interfaceDecl = decl.OwningType.IsInterface; - - foreach (MethodImplRecord record in foundMethodImpls) - { - MethodDesc recordDecl = record.Decl; - - if (interfaceDecl != recordDecl.OwningType.IsInterface) - continue; - - if (!interfaceDecl) - recordDecl = FindSlotDefiningMethodForVirtualMethod(recordDecl); - - if (recordDecl == decl) - { - return FindSlotDefiningMethodForVirtualMethod(record.Body); - } - } - - return null; - } - - private static bool IsInterfaceExplicitlyImplementedOnType(MetadataType type, MetadataType interfaceType) - { - foreach (TypeDesc iface in type.ExplicitlyImplementedInterfaces) - { - if (iface == interfaceType) - return true; - } - return false; - } - - /// - /// Find matching a matching method by name and sig on a type. (Restricted to virtual methods only) - /// - /// - /// - /// Used to control the order of the search. For historical purposes to - /// match .NET Framework behavior, this is typically true, but not always. There is no particular rationale - /// for the particular orders other than to attempt to be consistent in virtual method override behavior - /// betweeen runtimes. - /// - /// - private static MethodDesc FindMatchingVirtualMethodOnTypeByNameAndSig(MethodDesc targetMethod, DefType currentType, bool reverseMethodSearch, Func nameSigMatchMethodIsValidCandidate) - { - string name = targetMethod.Name; - MethodSignature sig = targetMethod.Signature; - - MethodDesc implMethod = null; - foreach (MethodDesc candidate in currentType.GetAllMethods()) - { - if (!candidate.IsVirtual) - continue; - - if (candidate.Name == name) - { - if (candidate.Signature.Equals(sig)) - { - if (nameSigMatchMethodIsValidCandidate == null || nameSigMatchMethodIsValidCandidate(targetMethod, candidate)) - { - implMethod = candidate; - - // If reverseMethodSearch is enabled, we want to find the last match on this type, not the first - // (reverseMethodSearch is used for most matches except for searches for name/sig method matches for interface methods on the most derived type) - if (!reverseMethodSearch) - return implMethod; - } - } - } - } - - return implMethod; - } - - // This function is used to find the name/sig based override for a given method. This method ignores all - // method impl's as it assumes they have been resolved. The algorithm is simple. Walk to the base type looking - // for overrides by name and signature. If one is found, return it as long as the newslot defining method - // for the found method matches that of the target method. - private static MethodDesc FindNameSigOverrideForVirtualMethod(MethodDesc targetMethod, MetadataType currentType) - { - while (currentType != null) - { - MethodDesc nameSigOverride = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(targetMethod, currentType, reverseMethodSearch:true); - - if (nameSigOverride != null) - { - return nameSigOverride; - } - - currentType = currentType.MetadataBaseType; - } - - return null; - } - - // This function looks for the base type method that defines the slot for a method - // This is either the newslot method most derived that is in the parent hierarchy of method - // or the least derived method that isn't newslot that matches by name and sig. - public static MethodDesc FindSlotDefiningMethodForVirtualMethod(MethodDesc method) - { - if (method == null) - return method; - - DefType currentType = method.OwningType.BaseType; - - // Loop until a newslot method is found - while ((currentType != null) && !method.IsNewSlot) - { - MethodDesc foundMethod = FindMatchingVirtualMethodOnTypeByNameAndSig(method, currentType, reverseMethodSearch: true, nameSigMatchMethodIsValidCandidate:null); - if (foundMethod != null) - { - method = foundMethod; - } - - currentType = currentType.BaseType; - } - - // Newslot method found, or if not the least derived method that matches by name and - // sig is to be returned. - return method; - } - - /// - /// Find matching a matching method by name and sig on a type. (Restricted to virtual methods only) Only search amongst methods with the same vtable slot. - /// - /// - /// - /// Used to control the order of the search. For historical purposes to - /// match .NET Framework behavior, this is typically true, but not always. There is no particular rationale - /// for the particular orders other than to attempt to be consistent in virtual method override behavior - /// betweeen runtimes. - /// - private static MethodDesc FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(MethodDesc method, DefType currentType, bool reverseMethodSearch) - { - return FindMatchingVirtualMethodOnTypeByNameAndSig(method, currentType, reverseMethodSearch, nameSigMatchMethodIsValidCandidate: s_VerifyMethodsHaveTheSameVirtualSlot); - } - - private static Func s_VerifyMethodsHaveTheSameVirtualSlot = VerifyMethodsHaveTheSameVirtualSlot; - - // Return true if the slot that defines methodToVerify matches slotDefiningMethod - private static bool VerifyMethodsHaveTheSameVirtualSlot(MethodDesc slotDefiningMethod, MethodDesc methodToVerify) - { - MethodDesc slotDefiningMethodOfMethodToVerify = FindSlotDefiningMethodForVirtualMethod(methodToVerify); - return slotDefiningMethodOfMethodToVerify == slotDefiningMethod; - } - - private static void FindBaseUnificationGroup(MetadataType currentType, UnificationGroup unificationGroup) - { - MethodDesc originalDefiningMethod = unificationGroup.DefiningMethod; - - MethodDesc methodImpl = FindImplFromDeclFromMethodImpls(currentType, unificationGroup.DefiningMethod); - if (methodImpl != null) - { - unificationGroup.SetDefiningMethod(methodImpl); - } - - MethodDesc nameSigMatchMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(unificationGroup.DefiningMethod, currentType, reverseMethodSearch: true); - MetadataType baseType = currentType.MetadataBaseType; - - // Unless the current type has a name/sig match for the group, look to the base type to define the unification group further - if ((nameSigMatchMethod == null) && (baseType != null)) - { - FindBaseUnificationGroup(baseType, unificationGroup); - } - - Debug.Assert(unificationGroup.IsInGroupOrIsDefiningSlot(originalDefiningMethod)); - - // Now, we have the unification group from the type, or have discovered its defined on the current type. - // Adjust the group to contain all of the elements that are added to it on this type, remove the components that - // have seperated themselves from the group - - // Start with removing methods that seperated themselves from the group via name/sig matches - MethodDescHashtable separatedMethods = null; - - foreach (MethodDesc memberMethod in unificationGroup) - { - MethodDesc nameSigMatchMemberMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(memberMethod, currentType, reverseMethodSearch: true); - if (nameSigMatchMemberMethod != null) - { - if (separatedMethods == null) - separatedMethods = new MethodDescHashtable(); - separatedMethods.AddOrGetExisting(memberMethod); - } - } - - if (separatedMethods != null) - { - foreach (MethodDesc seperatedMethod in MethodDescHashtable.Enumerator.Get(separatedMethods)) - { - unificationGroup.RemoveFromGroup(seperatedMethod); - } - } - - // Next find members which have seperated or added themselves to the group via MethodImpls - foreach (MethodImplRecord methodImplRecord in currentType.VirtualMethodImplsForType) - { - MethodDesc declSlot = FindSlotDefiningMethodForVirtualMethod(methodImplRecord.Decl); - MethodDesc implSlot = FindSlotDefiningMethodForVirtualMethod(methodImplRecord.Body); - - if (unificationGroup.IsInGroup(declSlot) && !unificationGroup.IsInGroupOrIsDefiningSlot(implSlot)) - { - unificationGroup.RemoveFromGroup(declSlot); - - if (separatedMethods == null) - separatedMethods = new MethodDescHashtable(); - separatedMethods.AddOrGetExisting(declSlot); - continue; - } - if (!unificationGroup.IsInGroupOrIsDefiningSlot(declSlot) && unificationGroup.IsInGroupOrIsDefiningSlot(implSlot)) - { - // Add decl to group. - - // To do so, we need to have the Unification Group of the decl slot, as it may have multiple members itself - UnificationGroup addDeclGroup = new UnificationGroup(declSlot); - FindBaseUnificationGroup(baseType, addDeclGroup); - Debug.Assert(addDeclGroup.IsInGroupOrIsDefiningSlot(declSlot)); - - // Add all members from the decl's unification group except for ones that have been seperated by name/sig matches - // or previously processed methodimpls. NOTE: This implies that method impls are order dependent. - if (separatedMethods == null || !separatedMethods.Contains(addDeclGroup.DefiningMethod)) - { - unificationGroup.AddToGroup(addDeclGroup.DefiningMethod); - } - - foreach (MethodDesc addDeclGroupMemberMethod in addDeclGroup) - { - if (separatedMethods == null || !separatedMethods.Contains(addDeclGroupMemberMethod)) - { - unificationGroup.AddToGroup(addDeclGroupMemberMethod); - } - } - } - } - } - - public override MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType) - { - return ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, (MetadataType)currentType); - } - - public override MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType) - { - return ResolveVariantInterfaceMethodToVirtualMethodOnType(interfaceMethod, (MetadataType)currentType); - } - - //////////////////////// INTERFACE RESOLUTION - //Interface function resolution - // Interface function resolution follows the following rules - // 1. Apply any method impl that may exist, if once of these exists, resolve to target immediately. - // 2. If an interface is explicitly defined on a type, then attempt to perform a namesig match on the - // current type to resolve.If the interface isn’t resolved, if it isn’t implemented on a base type, - // scan all base types for name / sig matches. - // 3. If implicitly defined, attempt to perform a namesig match if the interface method implementation - // has not been found on some base type. - // The above will resolve an interface to a virtual method slot. From there perform virtual resolution - // to find out the actual target.Note, to preserve correct behavior in the presence of variance, this - // function returns null if the interface method implementation is not defined by the current type in - // the hierarchy.For variance to work correctly, this requires that interfaces be queried in correct order. - // See current interface call resolution for details on how that happens. - private static MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, MetadataType currentType) - { - if (currentType.IsInterface) - return null; - - MethodDesc methodImpl = FindImplFromDeclFromMethodImpls(currentType, interfaceMethod); - if (methodImpl != null) - return methodImpl; - - MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; - - // If interface is explicitly defined on a type, search for a name/sig match. - bool foundExplicitInterface = IsInterfaceExplicitlyImplementedOnType(currentType, interfaceType); - MetadataType baseType = currentType.MetadataBaseType; - - if (foundExplicitInterface) - { - MethodDesc foundOnCurrentType = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType - , reverseMethodSearch: false /* When searching for name/sig overrides on a type that explicitly defines an interface, search through the type in the forward direction*/ - , nameSigMatchMethodIsValidCandidate :null); - foundOnCurrentType = FindSlotDefiningMethodForVirtualMethod(foundOnCurrentType); - - if (baseType == null) - return foundOnCurrentType; - - if (foundOnCurrentType == null && (ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, baseType) == null)) - { - // TODO! Does this handle the case where the base type explicitly implements the interface, but is abstract - // and doesn't actually have an implementation? - if (!IsInterfaceImplementedOnType(baseType, interfaceType)) - { - return FindNameSigOverrideForInterfaceMethodRecursive(interfaceMethod, baseType); - } - } - return foundOnCurrentType; - } - else - { - // Implicit interface case - if (!IsInterfaceImplementedOnType(currentType, interfaceType)) - { - // If the interface isn't implemented on this type at all, don't go searching - return null; - } - - // This is an implicitly implemented interface method. Only return a vlaue if this is the first type in the class - // hierarchy that implements the interface. NOTE: If we pay attention to whether or not the parent type is - // abstract or not, we may be able to be more efficient here, but let's skip that for now - MethodDesc baseClassImplementationOfInterfaceMethod = ResolveInterfaceMethodToVirtualMethodOnTypeRecursive(interfaceMethod, baseType); - if (baseClassImplementationOfInterfaceMethod != null) - { - return null; - } - else - { - MethodDesc foundOnCurrentType = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType - , reverseMethodSearch: false /* When searching for name/sig overrides on a type that is the first type in the hierarchy to require the interface, search through the type in the forward direction*/ - , nameSigMatchMethodIsValidCandidate: null); - - foundOnCurrentType = FindSlotDefiningMethodForVirtualMethod(foundOnCurrentType); - - if (foundOnCurrentType != null) - return foundOnCurrentType; - - return FindNameSigOverrideForInterfaceMethodRecursive(interfaceMethod, baseType); - } - } - } - - public static MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, MetadataType currentType) - { - MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; - bool foundInterface = IsInterfaceImplementedOnType(currentType, interfaceType); - MethodDesc implMethod; - - if (foundInterface) - { - implMethod = ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, currentType); - if (implMethod != null) - return implMethod; - } - - foreach (TypeDesc iface in currentType.RuntimeInterfaces) - { - if (iface.CanCastTo(interfaceType)) - { - implMethod = iface.FindMethodOnTypeWithMatchingTypicalMethod(interfaceMethod); - Debug.Assert(implMethod != null); - implMethod = ResolveInterfaceMethodToVirtualMethodOnType(implMethod, currentType); - if (implMethod != null) - return implMethod; - } - } - - return null; - } - - // Helper routine used during implicit interface implementation discovery - private static MethodDesc ResolveInterfaceMethodToVirtualMethodOnTypeRecursive(MethodDesc interfaceMethod, MetadataType currentType) - { - while (true) - { - if (currentType == null) - return null; - - MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; - - if (!IsInterfaceImplementedOnType(currentType, interfaceType)) - { - // If the interface isn't implemented on this type at all, don't go searching - return null; - } - - MethodDesc currentTypeInterfaceResolution = ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, currentType); - if (currentTypeInterfaceResolution != null) - return currentTypeInterfaceResolution; - - currentType = currentType.MetadataBaseType; - } - } - - // Perform a name/sig match for a virtual method across the specified types and all of the types parents. - private static MethodDesc FindNameSigOverrideForInterfaceMethodRecursive(MethodDesc interfaceMethod, MetadataType currentType) - { - while (true) - { - if (currentType == null) - return null; - - MethodDesc nameSigOverride = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType - , reverseMethodSearch: true /* When searching for a name sig match for an interface on parent types search in reverse order of declaration */ - , nameSigMatchMethodIsValidCandidate:null); - - if (nameSigOverride != null) - { - return FindSlotDefiningMethodForVirtualMethod(nameSigOverride); - } - - currentType = currentType.MetadataBaseType; - } - } - - public override IEnumerable ComputeAllVirtualSlots(TypeDesc type) - { - return EnumAllVirtualSlots((MetadataType)type); - } - - // Enumerate all possible virtual slots of a type - public static IEnumerable EnumAllVirtualSlots(MetadataType type) - { - MethodDescHashtable alreadyEnumerated = new MethodDescHashtable(); - if (!type.IsInterface) - { - do - { - foreach (MethodDesc m in type.GetAllMethods()) - { - if (!m.IsVirtual) - continue; - - MethodDesc possibleVirtual = FindSlotDefiningMethodForVirtualMethod(m); - if (!alreadyEnumerated.Contains(possibleVirtual)) - { - alreadyEnumerated.AddOrGetExisting(possibleVirtual); - yield return possibleVirtual; - } - } - - type = type.MetadataBaseType; - } while (type != null); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.Diagnostic.cs deleted file mode 100644 index 946f4a0d79b..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.Diagnostic.cs +++ /dev/null @@ -1,11 +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. - -namespace Internal.TypeSystem -{ - partial class MethodDelegator - { - public override string DiagnosticName => _wrappedMethod.DiagnosticName; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.cs deleted file mode 100644 index b1fc85dfc90..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.cs +++ /dev/null @@ -1,53 +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. - -namespace Internal.TypeSystem -{ - /// - /// Wraps a object and delegates methods to that . - /// - public abstract partial class MethodDelegator : MethodDesc - { - protected readonly MethodDesc _wrappedMethod; - - public MethodDelegator(MethodDesc wrappedMethod) - { - _wrappedMethod = wrappedMethod; - } - - public override TypeSystemContext Context => _wrappedMethod.Context; - - public override TypeDesc OwningType => _wrappedMethod.OwningType; - - public override MethodSignature Signature => _wrappedMethod.Signature; - - public override Instantiation Instantiation => _wrappedMethod.Instantiation; - - public override bool IsDefaultConstructor => _wrappedMethod.IsDefaultConstructor; - - public override string Name => _wrappedMethod.Name; - - public override bool IsVirtual => _wrappedMethod.IsVirtual; - - public override bool IsNewSlot => _wrappedMethod.IsNewSlot; - - public override bool IsAbstract => _wrappedMethod.IsAbstract; - - public override bool IsFinal => _wrappedMethod.IsFinal; - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return _wrappedMethod.HasCustomAttribute(attributeNamespace, attributeName); - } - - // For this method, delegating to the wrapped MethodDesc would likely be the wrong thing. - public abstract override MethodDesc GetMethodDefinition(); - - // For this method, delegating to the wrapped MethodDesc would likely be the wrong thing. - public abstract override MethodDesc GetTypicalMethodDefinition(); - - // For this method, delegating to the wrapped MethodDesc would likely be the wrong thing. - public abstract override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs deleted file mode 100644 index 581125911c3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs +++ /dev/null @@ -1,13 +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.Text; - -namespace Internal.TypeSystem -{ - partial class MethodDesc - { - public abstract string DiagnosticName { get; } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.ToString.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.ToString.cs deleted file mode 100644 index 984faa2433e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.ToString.cs +++ /dev/null @@ -1,85 +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.Text; - -namespace Internal.TypeSystem -{ - partial class MethodSignature - { - public override string ToString() - { - return ToString(includeReturnType: true); - } - - public string ToString(bool includeReturnType) - { - var sb = new StringBuilder(); - - if (includeReturnType) - { - DebugNameFormatter.Instance.AppendName(sb, ReturnType, DebugNameFormatter.FormatOptions.None); - sb.Append('('); - } - - bool first = true; - foreach (TypeDesc param in _parameters) - { - if (first) - first = false; - else - sb.Append(','); - DebugNameFormatter.Instance.AppendName(sb, param, DebugNameFormatter.FormatOptions.None); - } - - if (includeReturnType) - sb.Append(')'); - - return sb.ToString(); - } - } - - partial class MethodDesc - { - public override string ToString() - { - var sb = new StringBuilder(); - - // (Skipping return type to keep things short) - sb.Append(OwningType); - sb.Append('.'); - sb.Append(DiagnosticName); - - bool first = true; - for (int i = 0; i < Instantiation.Length; i++) - { - if (first) - { - sb.Append('<'); - first = false; - } - else - { - sb.Append(','); - } - DebugNameFormatter.Instance.AppendName(sb, Instantiation[i], DebugNameFormatter.FormatOptions.None); - } - if (!first) - sb.Append('>'); - - sb.Append('('); - try - { - sb.Append(Signature.ToString(includeReturnType: false)); - } - catch - { - sb.Append("Unknown"); - } - sb.Append(')'); - - return sb.ToString(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.cs deleted file mode 100644 index 3e204f8fa75..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.cs +++ /dev/null @@ -1,580 +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 System.Diagnostics; -using System.Runtime.CompilerServices; -using Internal.NativeFormat; - -namespace Internal.TypeSystem -{ - [Flags] - public enum MethodSignatureFlags - { - None = 0x0000, - // TODO: Generic, etc. - - UnmanagedCallingConventionMask = 0x000F, - UnmanagedCallingConventionCdecl = 0x0001, - UnmanagedCallingConventionStdCall = 0x0002, - UnmanagedCallingConventionThisCall = 0x0003, - CallingConventionVarargs = 0x0005, - - Static = 0x0010, - } - - public enum EmbeddedSignatureDataKind - { - RequiredCustomModifier = 0, - OptionalCustomModifier = 1 - } - - public struct EmbeddedSignatureData - { - public string index; - public EmbeddedSignatureDataKind kind; - public TypeDesc type; - } - - /// - /// Represents the parameter types, the return type, and flags of a method. - /// - public sealed partial class MethodSignature : TypeSystemEntity - { - internal MethodSignatureFlags _flags; - internal int _genericParameterCount; - internal TypeDesc _returnType; - internal TypeDesc[] _parameters; - internal EmbeddedSignatureData[] _embeddedSignatureData; - - public MethodSignature(MethodSignatureFlags flags, int genericParameterCount, TypeDesc returnType, TypeDesc[] parameters, EmbeddedSignatureData[] embeddedSignatureData = null) - { - _flags = flags; - _genericParameterCount = genericParameterCount; - _returnType = returnType; - _parameters = parameters; - _embeddedSignatureData = embeddedSignatureData; - - Debug.Assert(parameters != null, "Parameters must not be null"); - } - - public MethodSignatureFlags Flags - { - get - { - return _flags; - } - } - - public bool IsStatic - { - get - { - return (_flags & MethodSignatureFlags.Static) != 0; - } - } - - public int GenericParameterCount - { - get - { - return _genericParameterCount; - } - } - - public TypeDesc ReturnType - { - get - { - return _returnType; - } - } - - /// - /// Gets the parameter type at the specified index. - /// - [IndexerName("Parameter")] - public TypeDesc this[int index] - { - get - { - return _parameters[index]; - } - } - - /// - /// Gets the number of parameters of this method signature. - /// - public int Length - { - get - { - return _parameters.Length; - } - } - - public bool Equals(MethodSignature otherSignature) - { - // TODO: Generics, etc. - if (this._flags != otherSignature._flags) - return false; - - if (this._genericParameterCount != otherSignature._genericParameterCount) - return false; - - if (this._returnType != otherSignature._returnType) - return false; - - if (this._parameters.Length != otherSignature._parameters.Length) - return false; - - for (int i = 0; i < this._parameters.Length; i++) - { - if (this._parameters[i] != otherSignature._parameters[i]) - return false; - } - - if (this._embeddedSignatureData == null && otherSignature._embeddedSignatureData == null) - { - return true; - } - - if (this._embeddedSignatureData != null && otherSignature._embeddedSignatureData != null) - { - if (this._embeddedSignatureData.Length != otherSignature._embeddedSignatureData.Length) - { - return false; - } - - for (int i = 0; i < this._embeddedSignatureData.Length; i++) - { - if (this._embeddedSignatureData[i].index != otherSignature._embeddedSignatureData[i].index) - return false; - if (this._embeddedSignatureData[i].kind != otherSignature._embeddedSignatureData[i].kind) - return false; - if (this._embeddedSignatureData[i].type != otherSignature._embeddedSignatureData[i].type) - return false; - } - - return true; - } - - return false; - } - - public override bool Equals(object obj) - { - return obj is MethodSignature && Equals((MethodSignature)obj); - } - - public override int GetHashCode() - { - return TypeHashingAlgorithms.ComputeMethodSignatureHashCode(_returnType.GetHashCode(), _parameters); - } - - public SignatureEnumerator GetEnumerator() - { - return new SignatureEnumerator(this); - } - - public override TypeSystemContext Context => _returnType.Context; - - public struct SignatureEnumerator - { - private int _index; - private MethodSignature _signature; - - public SignatureEnumerator(MethodSignature signature) - { - _signature = signature; - _index = -1; - } - - public TypeDesc Current => _signature[_index]; - - public bool MoveNext() - { - _index++; - return _index < _signature.Length; - } - } - } - - /// - /// Helper structure for building method signatures by cloning an existing method signature. - /// - /// - /// This can potentially avoid array allocation costs for allocating the parameter type list. - /// - public struct MethodSignatureBuilder - { - private MethodSignature _template; - private MethodSignatureFlags _flags; - private int _genericParameterCount; - private TypeDesc _returnType; - private TypeDesc[] _parameters; - private EmbeddedSignatureData[] _customModifiers; - - public MethodSignatureBuilder(MethodSignature template) - { - _template = template; - - _flags = template._flags; - _genericParameterCount = template._genericParameterCount; - _returnType = template._returnType; - _parameters = template._parameters; - _customModifiers = template._embeddedSignatureData; - } - - public MethodSignatureFlags Flags - { - set - { - _flags = value; - } - } - - public TypeDesc ReturnType - { - set - { - _returnType = value; - } - } - - [System.Runtime.CompilerServices.IndexerName("Parameter")] - public TypeDesc this[int index] - { - set - { - if (_parameters[index] == value) - return; - - if (_template != null && _parameters == _template._parameters) - { - TypeDesc[] parameters = new TypeDesc[_parameters.Length]; - for (int i = 0; i < parameters.Length; i++) - parameters[i] = _parameters[i]; - _parameters = parameters; - } - _parameters[index] = value; - } - } - - public int Length - { - set - { - _parameters = new TypeDesc[value]; - _template = null; - } - } - - public MethodSignature ToSignature() - { - if (_template == null || - _flags != _template._flags || - _genericParameterCount != _template._genericParameterCount || - _returnType != _template._returnType || - _parameters != _template._parameters) - { - _template = new MethodSignature(_flags, _genericParameterCount, _returnType, _parameters, _customModifiers); - } - - return _template; - } - } - - /// - /// Represents the fundamental base type for all methods within the type system. - /// - public abstract partial class MethodDesc : TypeSystemEntity - { - public static readonly MethodDesc[] EmptyMethods = new MethodDesc[0]; - - private int _hashcode; - - /// - /// Allows a performance optimization that skips the potentially expensive - /// construction of a hash code if a hash code has already been computed elsewhere. - /// Use to allow objects to have their hashcode computed - /// independently of the allocation of a MethodDesc object - /// For instance, compute the hashcode when looking up the object, - /// then when creating the object, pass in the hashcode directly. - /// The hashcode specified MUST exactly match the algorithm implemented - /// on this type normally. - /// - protected void SetHashCode(int hashcode) - { - _hashcode = hashcode; - Debug.Assert(hashcode == ComputeHashCode()); - } - - public sealed override int GetHashCode() - { - if (_hashcode != 0) - return _hashcode; - - return AcquireHashCode(); - } - - private int AcquireHashCode() - { - _hashcode = ComputeHashCode(); - return _hashcode; - } - - /// - /// Compute HashCode. Should only be overriden by a MethodDesc that represents an instantiated method. - /// - protected virtual int ComputeHashCode() - { - return TypeHashingAlgorithms.ComputeMethodHashCode(OwningType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(Name)); - } - - public override bool Equals(Object o) - { - // Its only valid to compare two MethodDescs in the same context - Debug.Assert(Object.ReferenceEquals(o, null) || !(o is MethodDesc) || Object.ReferenceEquals(((MethodDesc)o).Context, this.Context)); - return Object.ReferenceEquals(this, o); - } - - /// - /// Gets the type that owns this method. This will be a or - /// an . - /// - public abstract TypeDesc OwningType - { - get; - } - - /// - /// Gets the signature of the method. - /// - public abstract MethodSignature Signature - { - get; - } - - /// - /// Gets the generic instantiation information of this method. - /// For generic definitions, retrieves the generic parameters of the method. - /// For generic instantiation, retrieves the generic arguments of the method. - /// - public virtual Instantiation Instantiation - { - get - { - return Instantiation.Empty; - } - } - - /// - /// Gets a value indicating whether this method has a generic instantiation. - /// This will be true for generic method instantiations and generic definitions. - /// - public bool HasInstantiation - { - get - { - return this.Instantiation.Length != 0; - } - } - - /// - /// Gets a value indicating whether this method is an instance constructor. - /// - public bool IsConstructor - { - get - { - // TODO: Precise check - // TODO: Cache? - return this.Name == ".ctor"; - } - } - - /// - /// Gets a value indicating whether this is a public parameterless instance constructor - /// on a non-abstract type. - /// - public virtual bool IsDefaultConstructor - { - get - { - return OwningType.GetDefaultConstructor() == this; - } - } - - /// - /// Gets a value indicating whether this method is a static constructor. - /// - public bool IsStaticConstructor - { - get - { - return this == this.OwningType.GetStaticConstructor(); - } - } - - /// - /// Gets the name of the method as specified in the metadata. - /// - public virtual string Name - { - get - { - return null; - } - } - - /// - /// Gets a value indicating whether the method is virtual. - /// - public virtual bool IsVirtual - { - get - { - return false; - } - } - - /// - /// Gets a value indicating whether this virtual method should not override any - /// virtual methods defined in any of the base classes. - /// - public virtual bool IsNewSlot - { - get - { - return false; - } - } - - /// - /// Gets a value indicating whether this virtual method needs to be overriden - /// by all non-abstract classes deriving from the method's owning type. - /// - public virtual bool IsAbstract - { - get - { - return false; - } - } - - /// - /// Gets a value indicating that this method cannot be overriden. - /// - public virtual bool IsFinal - { - get - { - return false; - } - } - - public abstract bool HasCustomAttribute(string attributeNamespace, string attributeName); - - /// - /// Retrieves the uninstantiated form of the method on the method's . - /// For generic methods, this strips method instantiation. For non-generic methods, returns 'this'. - /// To also strip instantiation of the owning type, use . - /// - public virtual MethodDesc GetMethodDefinition() - { - return this; - } - - /// - /// Gets a value indicating whether this is a method definition. This property - /// is true for non-generic methods and for uninstantiated generic methods. - /// - public bool IsMethodDefinition - { - get - { - return GetMethodDefinition() == this; - } - } - - /// - /// Retrieves the generic definition of the method on the generic definition of the owning type. - /// To only uninstantiate the method without uninstantiating the owning type, use . - /// - public virtual MethodDesc GetTypicalMethodDefinition() - { - return this; - } - - /// - /// Gets a value indicating whether this is a typical definition. This property is true - /// if neither the owning type, nor the method are instantiated. - /// - public bool IsTypicalMethodDefinition - { - get - { - return GetTypicalMethodDefinition() == this; - } - } - - /// - /// Gets a value indicating whether this is an uninstantiated generic method. - /// - public bool IsGenericMethodDefinition - { - get - { - return HasInstantiation && IsMethodDefinition; - } - } - - public bool IsFinalizer - { - get - { - TypeDesc owningType = OwningType; - return (owningType.IsObject && Name == "Finalize") || (owningType.HasFinalizer && owningType.GetFinalizer() == this); - } - } - - public virtual MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - Instantiation instantiation = Instantiation; - TypeDesc[] clone = null; - - for (int i = 0; i < instantiation.Length; i++) - { - TypeDesc uninst = instantiation[i]; - TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); - if (inst != uninst) - { - if (clone == null) - { - clone = new TypeDesc[instantiation.Length]; - for (int j = 0; j < clone.Length; j++) - { - clone[j] = instantiation[j]; - } - } - clone[i] = inst; - } - } - - MethodDesc method = this; - - TypeDesc owningType = method.OwningType; - TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); - if (owningType != instantiatedOwningType) - { - method = Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType); - if (clone == null && instantiation.Length != 0) - return Context.GetInstantiatedMethod(method, instantiation); - } - - return (clone == null) ? method : Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone)); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs deleted file mode 100644 index e1e18c7d70b..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem -{ - public sealed partial class MethodForInstantiatedType - { - public override string DiagnosticName - { - get - { - return _typicalMethodDef.DiagnosticName; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.cs deleted file mode 100644 index 98e3c0be119..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.cs +++ /dev/null @@ -1,141 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public sealed partial class MethodForInstantiatedType : MethodDesc - { - private readonly MethodDesc _typicalMethodDef; - private readonly InstantiatedType _instantiatedType; - - private MethodSignature _signature; - - internal MethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) - { - Debug.Assert(typicalMethodDef.GetTypicalMethodDefinition() == typicalMethodDef); - _typicalMethodDef = typicalMethodDef; - _instantiatedType = instantiatedType; - } - - // This constructor is a performance optimization - it allows supplying the hash code if it has already - // been computed prior to the allocation of this type. The supplied hash code still has to match the - // hash code this type would compute on it's own (and we assert to enforce that). - internal MethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType, int hashcode) - : this(typicalMethodDef, instantiatedType) - { - SetHashCode(hashcode); - } - - public override TypeSystemContext Context - { - get - { - return _typicalMethodDef.Context; - } - } - - public override TypeDesc OwningType - { - get - { - return _instantiatedType; - } - } - - private TypeDesc Instantiate(TypeDesc type) - { - return type.InstantiateSignature(_instantiatedType.Instantiation, new Instantiation()); - } - - public override MethodSignature Signature - { - get - { - if (_signature == null) - { - MethodSignature template = _typicalMethodDef.Signature; - MethodSignatureBuilder builder = new MethodSignatureBuilder(template); - - builder.ReturnType = Instantiate(template.ReturnType); - for (int i = 0; i < template.Length; i++) - builder[i] = Instantiate(template[i]); - - _signature = builder.ToSignature(); - } - - return _signature; - } - } - - public override Instantiation Instantiation - { - get - { - return _typicalMethodDef.Instantiation; - } - } - - public override bool IsVirtual - { - get - { - return _typicalMethodDef.IsVirtual; - } - } - - public override bool IsNewSlot - { - get - { - return _typicalMethodDef.IsNewSlot; - } - } - - public override bool IsAbstract - { - get - { - return _typicalMethodDef.IsAbstract; - } - } - - public override bool IsFinal - { - get - { - return _typicalMethodDef.IsFinal; - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return _typicalMethodDef.HasCustomAttribute(attributeNamespace, attributeName); - } - - public override MethodDesc GetTypicalMethodDefinition() - { - return _typicalMethodDef; - } - - public override bool IsDefaultConstructor - { - get - { - return _typicalMethodDef.IsDefaultConstructor; - } - } - - public override string Name - { - get - { - return _typicalMethodDef.Name; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ModuleDesc.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ModuleDesc.cs deleted file mode 100644 index 6be6de9b163..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ModuleDesc.cs +++ /dev/null @@ -1,45 +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.Collections.Generic; - -namespace Internal.TypeSystem -{ - public abstract partial class ModuleDesc : TypeSystemEntity - { - public override TypeSystemContext Context - { - get; - } - - /// - /// Gets the assembly this module is part of (the assembly manifest module). - /// - public virtual IAssemblyDesc Assembly - { - get; - } - - public ModuleDesc(TypeSystemContext context, IAssemblyDesc assembly) - { - Context = context; - Assembly = assembly; - } - - /// - /// Gets a type in this module with the specified name. - /// - public abstract MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true); - - /// - /// Gets the global <Module> type. - /// - public abstract MetadataType GetGlobalModuleType(); - - /// - /// Retrieves a collection of all types defined in the current module. This includes nested types. - /// - public abstract IEnumerable GetAllTypes(); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ParameterizedType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ParameterizedType.cs deleted file mode 100644 index 33036e75888..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ParameterizedType.cs +++ /dev/null @@ -1,34 +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; - -namespace Internal.TypeSystem -{ - public abstract partial class ParameterizedType : TypeDesc - { - private TypeDesc _parameterType; - - internal ParameterizedType(TypeDesc parameterType) - { - _parameterType = parameterType; - } - - public TypeDesc ParameterType - { - get - { - return _parameterType; - } - } - - public override TypeSystemContext Context - { - get - { - return _parameterType.Context; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/PointerType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/PointerType.cs deleted file mode 100644 index 15e8adbde4e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/PointerType.cs +++ /dev/null @@ -1,43 +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. - -namespace Internal.TypeSystem -{ - /// - /// Represents an unmanaged pointer type. - /// - public sealed partial class PointerType : ParameterizedType - { - internal PointerType(TypeDesc parameterType) - : base(parameterType) - { - } - - public override int GetHashCode() - { - return Internal.NativeFormat.TypeHashingAlgorithms.ComputePointerTypeHashCode(this.ParameterType.GetHashCode()); - } - - public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc parameterType = this.ParameterType; - TypeDesc instantiatedParameterType = parameterType.InstantiateSignature(typeInstantiation, methodInstantiation); - if (instantiatedParameterType != parameterType) - return Context.GetPointerType(instantiatedParameterType); - - return this; - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = TypeFlags.Pointer; - - flags |= TypeFlags.HasGenericVarianceComputed; - flags |= TypeFlags.HasFinalizerComputed; - flags |= TypeFlags.AttributeCacheComputed; - - return flags; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/PropertySignature.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/PropertySignature.cs deleted file mode 100644 index da59e609d41..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/PropertySignature.cs +++ /dev/null @@ -1,39 +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. - -namespace Internal.TypeSystem -{ - public struct PropertySignature - { - private TypeDesc[] _parameters; - - public readonly bool IsStatic; - - public readonly TypeDesc ReturnType; - - [System.Runtime.CompilerServices.IndexerName("Parameter")] - public TypeDesc this[int index] - { - get - { - return _parameters[index]; - } - } - - public int Length - { - get - { - return _parameters.Length; - } - } - - public PropertySignature(bool isStatic, TypeDesc[] parameters, TypeDesc returnType) - { - IsStatic = isStatic; - _parameters = parameters; - ReturnType = returnType; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/RuntimeInterfacesAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/RuntimeInterfacesAlgorithm.cs deleted file mode 100644 index 515d531da46..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/RuntimeInterfacesAlgorithm.cs +++ /dev/null @@ -1,26 +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. - -namespace Internal.TypeSystem -{ - /// - /// Pluggable RuntimeInterfaces computation algorithm. Provides an abstraction to compute - /// the list of interfaces effectively implemented by a type at runtime. - /// The computed list is exposed as . - /// - /// - /// The algorithms are expected to be directly used by derivatives - /// only. The most obvious implementation of this algorithm that uses type's metadata to - /// compute the answers is in . - /// - public abstract class RuntimeInterfacesAlgorithm - { - /// - /// Compute the RuntimeInterfaces for a TypeDesc, is permitted to depend on - /// RuntimeInterfaces of base type, but must not depend on any other - /// details of the base type. - /// - public abstract DefType[] ComputeRuntimeInterfaces(TypeDesc type); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/SignatureVariable.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/SignatureVariable.cs deleted file mode 100644 index 2fde3c53897..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/SignatureVariable.cs +++ /dev/null @@ -1,119 +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.NativeFormat; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public abstract partial class SignatureVariable : TypeDesc - { - private TypeSystemContext _context; - private int _index; - - internal SignatureVariable(TypeSystemContext context, int index) - { - _context = context; - _index = index; - } - - public int Index - { - get - { - return _index; - } - } - - public override TypeSystemContext Context - { - get - { - return _context; - } - } - - public abstract bool IsMethodSignatureVariable - { - get; - } - } - - public sealed partial class SignatureTypeVariable : SignatureVariable - { - internal SignatureTypeVariable(TypeSystemContext context, int index) : base(context, index) - { - } - - public override bool IsMethodSignatureVariable - { - get - { - return false; - } - } - - public override int GetHashCode() - { - return TypeHashingAlgorithms.ComputeSignatureVariableHashCode(Index, false); - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = 0; - - if ((mask & TypeFlags.CategoryMask) != 0) - { - flags |= TypeFlags.SignatureTypeVariable; - } - - return flags; - } - - public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - return typeInstantiation.IsNull ? this : typeInstantiation[Index]; - } - } - - public sealed partial class SignatureMethodVariable : SignatureVariable - { - internal SignatureMethodVariable(TypeSystemContext context, int index) : base(context, index) - { - } - - public override bool IsMethodSignatureVariable - { - get - { - return true; - } - } - - public override int GetHashCode() - { - return TypeHashingAlgorithms.ComputeSignatureVariableHashCode(Index, true); - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = 0; - - if ((mask & TypeFlags.CategoryMask) != 0) - { - flags |= TypeFlags.SignatureMethodVariable; - } - - return flags; - } - - public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - return methodInstantiation.IsNull ? this : methodInstantiation[Index]; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TargetDetails.ToString.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TargetDetails.ToString.cs deleted file mode 100644 index 822272c15e3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TargetDetails.ToString.cs +++ /dev/null @@ -1,17 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - partial class TargetDetails - { - public override string ToString() - { - return $"{Architecture}-{OperatingSystem}-{Abi}"; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TargetDetails.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TargetDetails.cs deleted file mode 100644 index 8e4207d9a41..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TargetDetails.cs +++ /dev/null @@ -1,325 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// Specifies the target CPU architecture. - /// - public enum TargetArchitecture - { - Unknown, - ARM, - ARM64, - X64, - X86, - Wasm32, - } - - /// - /// Specifies the target ABI. - /// - public enum TargetOS - { - Unknown, - Windows, - Linux, - OSX, - FreeBSD, - NetBSD, - WebAssembly, - } - - public enum TargetAbi - { - Unknown, - /// - /// Cross-platform console model - /// - CoreRT, - /// - /// Jit runtime ABI - /// - Jit, - /// - /// Cross-platform portable C++ codegen - /// - CppCodegen, - } - - /// - /// Represents various details about the compilation target that affect - /// layout, padding, allocations, or ABI. - /// - public partial class TargetDetails - { - /// - /// Gets the target CPU architecture. - /// - public TargetArchitecture Architecture - { - get; - } - - /// - /// Gets the target ABI. - /// - public TargetOS OperatingSystem - { - get; - } - - public TargetAbi Abi - { - get; - } - - /// - /// Gets the size of a pointer for the target of the compilation. - /// - public int PointerSize - { - get - { - switch (Architecture) - { - case TargetArchitecture.ARM64: - case TargetArchitecture.X64: - return 8; - case TargetArchitecture.ARM: - case TargetArchitecture.X86: - case TargetArchitecture.Wasm32: - return 4; - default: - throw new NotSupportedException(); - } - } - } - - public bool SupportsRelativePointers - { - get - { - return (Abi != TargetAbi.CppCodegen) && (Architecture != TargetArchitecture.Wasm32); - } - } - - /// - /// Gets the maximum alignment to which something can be aligned - /// - public int MaximumAlignment - { - get - { - if (Architecture == TargetArchitecture.ARM) - { - // Corresponds to alignment required for __m128 (there's no __m256) - return 8; - } - else if (Architecture == TargetArchitecture.ARM64) - { - // Corresponds to alignmet required for __m256 - return 16; - } - - // 256-bit vector is the type with the higest alignment we support - return 32; - } - } - - public LayoutInt LayoutPointerSize => new LayoutInt(PointerSize); - - /// - /// Gets the default field packing size. - /// - public int DefaultPackingSize - { - get - { - // We use default packing size of 32 irrespective of the platform. - return 32; - } - } - - /// - /// Gets the minimum required alignment for methods whose address is visible - /// to managed code. - /// - public int MinimumFunctionAlignment - { - get - { - // We use a minimum alignment of 4 irrespective of the platform. - // This is to prevent confusing the method address with a fat function pointer. - return 4; - } - } - - /// - /// Gets the alignment that is optimal for this platform. - /// - public int OptimumFunctionAlignment - { - get - { - // Matches the choice in the C++ compiler. - // We want a number that is optimized for micro-op caches in the processor. - return 16; - } - } - - public int MinimumCodeAlignment - { - get - { - switch (Architecture) - { - case TargetArchitecture.ARM: - return 2; - case TargetArchitecture.ARM64: - return 4; - default: - return 1; - } - } - } - - public TargetDetails(TargetArchitecture architecture, TargetOS targetOS, TargetAbi abi) - { - Architecture = architecture; - OperatingSystem = targetOS; - Abi = abi; - } - - /// - /// Gets the dyadic logarithm of the maximum size of a primitive type - /// - public static int MaximumLog2PrimitiveSize - { - get - { - return 3; - } - } - - /// - /// Gets the maximum size of a primitive type - /// - public static int MaximumPrimitiveSize - { - get - { - return 1 << MaximumLog2PrimitiveSize; - } - } - - /// - /// Retrieves the size of a well known type. - /// - public LayoutInt GetWellKnownTypeSize(DefType type) - { - switch (type.Category) - { - case TypeFlags.Void: - return new LayoutInt(PointerSize); - case TypeFlags.Boolean: - return new LayoutInt(1); - case TypeFlags.Char: - return new LayoutInt(2); - case TypeFlags.Byte: - case TypeFlags.SByte: - return new LayoutInt(1); - case TypeFlags.UInt16: - case TypeFlags.Int16: - return new LayoutInt(2); - case TypeFlags.UInt32: - case TypeFlags.Int32: - return new LayoutInt(4); - case TypeFlags.UInt64: - case TypeFlags.Int64: - return new LayoutInt(8); - case TypeFlags.Single: - return new LayoutInt(4); - case TypeFlags.Double: - return new LayoutInt(8); - case TypeFlags.UIntPtr: - case TypeFlags.IntPtr: - return new LayoutInt(PointerSize); - } - - // Add new well known types if necessary - - throw new InvalidOperationException(); - } - - /// - /// Retrieves the alignment required by a well known type. - /// - public LayoutInt GetWellKnownTypeAlignment(DefType type) - { - // Size == Alignment for all platforms. - return GetWellKnownTypeSize(type); - } - - /// - /// Given an alignment of the fields of a type, determine the alignment that is necessary for allocating the object on the GC heap - /// - /// - public LayoutInt GetObjectAlignment(LayoutInt fieldAlignment) - { - switch (Architecture) - { - case TargetArchitecture.ARM: - // ARM supports two alignments for objects on the GC heap (4 byte and 8 byte) - if (fieldAlignment.IsIndeterminate) - return LayoutInt.Indeterminate; - - if (fieldAlignment.AsInt <= 4) - return new LayoutInt(4); - else - return new LayoutInt(8); - case TargetArchitecture.X64: - case TargetArchitecture.ARM64: - return new LayoutInt(8); - case TargetArchitecture.X86: - case TargetArchitecture.Wasm32: - return new LayoutInt(4); - default: - throw new NotSupportedException(); - } - } - - /// - /// Returns True if compiling for Windows - /// - public bool IsWindows - { - get - { - return OperatingSystem == TargetOS.Windows; - } - } - - /// - /// Maximum number of elements in a HFA type. - /// - public int MaximumHfaElementCount - { - get - { - // There is a hard limit of 4 elements on an HFA type, see - // http://blogs.msdn.com/b/vcblog/archive/2013/07/12/introducing-vector-calling-convention.aspx - Debug.Assert(Architecture == TargetArchitecture.ARM || - Architecture == TargetArchitecture.ARM64 || - Architecture == TargetArchitecture.X64 || - Architecture == TargetArchitecture.X86); - - return 4; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThreadSafeFlags.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThreadSafeFlags.cs deleted file mode 100644 index 70f0b22c40e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThreadSafeFlags.cs +++ /dev/null @@ -1,39 +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.Runtime.CompilerServices; -using Interlocked = System.Threading.Interlocked; - -namespace Internal.TypeSystem -{ - public struct ThreadSafeFlags - { - private volatile int _value; - - public int Value - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return _value; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasFlags(int value) - { - return (_value & value) == value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddFlags(int flagsToAdd) - { - var originalFlags = _value; - while (Interlocked.CompareExchange(ref _value, originalFlags | flagsToAdd, originalFlags) != originalFlags) - { - originalFlags = _value; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThrowHelper.Common.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThrowHelper.Common.cs deleted file mode 100644 index 40b5928d98e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThrowHelper.Common.cs +++ /dev/null @@ -1,127 +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 System.Text; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public static partial class ThrowHelper - { - [System.Diagnostics.DebuggerHidden] - public static void ThrowTypeLoadException(string nestedTypeName, ModuleDesc module) - { - ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, nestedTypeName, Format.Module(module)); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowTypeLoadException(string @namespace, string name, ModuleDesc module) - { - ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, Format.Type(@namespace, name), Format.Module(module)); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowTypeLoadException(TypeDesc type) - { - ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, Format.Type(type), Format.OwningModule(type)); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowTypeLoadException(ExceptionStringID id, MethodDesc method) - { - ThrowTypeLoadException(id, Format.Type(method.OwningType), Format.OwningModule(method), Format.Method(method)); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowTypeLoadException(ExceptionStringID id, TypeDesc type, string messageArg) - { - ThrowTypeLoadException(id, Format.Type(type), Format.OwningModule(type), messageArg); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowTypeLoadException(ExceptionStringID id, TypeDesc type) - { - ThrowTypeLoadException(id, Format.Type(type), Format.OwningModule(type)); - } - - private static partial class Format - { - public static string OwningModule(MethodDesc method) - { - return OwningModule(method.OwningType); - } - - public static string Module(ModuleDesc module) - { - if (module == null) - return "?"; - - IAssemblyDesc assembly = module as IAssemblyDesc; - if (assembly != null) - { - return assembly.GetName().FullName; - } - else - { - Debug.Fail("Multi-module assemblies"); - return module.ToString(); - } - } - - public static string Type(TypeDesc type) - { - return ExceptionTypeNameFormatter.Instance.FormatName(type); - } - - public static string Type(string @namespace, string name) - { - return String.IsNullOrEmpty(@namespace) ? name : @namespace + "." + name; - } - - public static string Field(TypeDesc owningType, string fieldName) - { - return Type(owningType) + "." + fieldName; - } - - public static string Method(MethodDesc method) - { - return Method(method.OwningType, method.Name, method.Signature); - } - - public static string Method(TypeDesc owningType, string methodName, MethodSignature signature) - { - StringBuilder sb = new StringBuilder(); - - if (signature != null) - { - sb.Append(ExceptionTypeNameFormatter.Instance.FormatName(signature.ReturnType)); - sb.Append(' '); - } - - sb.Append(ExceptionTypeNameFormatter.Instance.FormatName(owningType)); - sb.Append('.'); - sb.Append(methodName); - - if (signature != null) - { - sb.Append('('); - for (int i = 0; i < signature.Length; i++) - { - if (i > 0) - { - sb.Append(", "); - } - - sb.Append(ExceptionTypeNameFormatter.Instance.FormatName(signature[i])); - } - sb.Append(')'); - } - - return sb.ToString(); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThrowHelper.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThrowHelper.cs deleted file mode 100644 index 46ff4cee5a2..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ThrowHelper.cs +++ /dev/null @@ -1,65 +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. - -namespace Internal.TypeSystem -{ - public static partial class ThrowHelper - { - [System.Diagnostics.DebuggerHidden] - private static void ThrowTypeLoadException(ExceptionStringID id, string typeName, string assemblyName, string messageArg) - { - throw new TypeSystemException.TypeLoadException(id, typeName, assemblyName, messageArg); - } - - [System.Diagnostics.DebuggerHidden] - private static void ThrowTypeLoadException(ExceptionStringID id, string typeName, string assemblyName) - { - throw new TypeSystemException.TypeLoadException(id, typeName, assemblyName); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowMissingMethodException(TypeDesc owningType, string methodName, MethodSignature signature) - { - throw new TypeSystemException.MissingMethodException(ExceptionStringID.MissingMethod, Format.Method(owningType, methodName, signature)); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowMissingFieldException(TypeDesc owningType, string fieldName) - { - throw new TypeSystemException.MissingFieldException(ExceptionStringID.MissingField, Format.Field(owningType, fieldName)); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowFileNotFoundException(ExceptionStringID id, string fileName) - { - throw new TypeSystemException.FileNotFoundException(id, fileName); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowInvalidProgramException() - { - throw new TypeSystemException.InvalidProgramException(); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowInvalidProgramException(ExceptionStringID id, MethodDesc method) - { - throw new TypeSystemException.InvalidProgramException(id, Format.Method(method)); - } - - [System.Diagnostics.DebuggerHidden] - public static void ThrowBadImageFormatException() - { - throw new TypeSystemException.BadImageFormatException(); - } - - private static partial class Format - { - public static string OwningModule(TypeDesc type) - { - return Module((type as MetadataType)?.Module); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.Interfaces.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.Interfaces.cs deleted file mode 100644 index e28168c19a9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.Interfaces.cs +++ /dev/null @@ -1,42 +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 System.Threading; -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Api surface for TypeDesc that relates to interfaces - - public partial class TypeDesc - { - private DefType[] _runtimeInterfaces; - - /// - /// The interfaces implemented by this type at runtime. There may be duplicates in this list. - /// - /// - public DefType[] RuntimeInterfaces - { - get - { - if (_runtimeInterfaces == null) - { - return InitializeRuntimeInterfaces(); - } - - return _runtimeInterfaces; - } - } - - private DefType[] InitializeRuntimeInterfaces() - { - RuntimeInterfacesAlgorithm algorithm = this.Context.GetRuntimeInterfacesAlgorithmForType(this); - DefType[] computedInterfaces = algorithm != null ? algorithm.ComputeRuntimeInterfaces(this) : Array.Empty(); - Interlocked.CompareExchange(ref _runtimeInterfaces, computedInterfaces, null); - return _runtimeInterfaces; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.ToString.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.ToString.cs deleted file mode 100644 index 34e616fae47..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.ToString.cs +++ /dev/null @@ -1,14 +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. - -namespace Internal.TypeSystem -{ - partial class TypeDesc - { - public override string ToString() - { - return DebugNameFormatter.Instance.FormatName(this, DebugNameFormatter.FormatOptions.Default); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.cs deleted file mode 100644 index d9110d148e1..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.cs +++ /dev/null @@ -1,633 +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 System.Diagnostics; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace Internal.TypeSystem -{ - /// - /// Represents the fundamental base type of all types within the type system. - /// - public abstract partial class TypeDesc : TypeSystemEntity - { - public static readonly TypeDesc[] EmptyTypes = new TypeDesc[0]; - - /// Inherited types are required to override, and should use the algorithms - /// in TypeHashingAlgorithms in their implementation. - public abstract override int GetHashCode(); - - public override bool Equals(Object o) - { - // Its only valid to compare two TypeDescs in the same context - Debug.Assert(o == null || !(o is TypeDesc) || Object.ReferenceEquals(((TypeDesc)o).Context, this.Context)); - return Object.ReferenceEquals(this, o); - } - -#if DEBUG - public static bool operator ==(TypeDesc left, TypeDesc right) - { - // Its only valid to compare two TypeDescs in the same context - Debug.Assert(Object.ReferenceEquals(left, null) || Object.ReferenceEquals(right, null) || Object.ReferenceEquals(left.Context, right.Context)); - return Object.ReferenceEquals(left, right); - } - - public static bool operator !=(TypeDesc left, TypeDesc right) - { - // Its only valid to compare two TypeDescs in the same context - Debug.Assert(Object.ReferenceEquals(left, null) || Object.ReferenceEquals(right, null) || Object.ReferenceEquals(left.Context, right.Context)); - return !Object.ReferenceEquals(left, right); - } -#endif - - // The most frequently used type properties are cached here to avoid excesive virtual calls - private TypeFlags _typeFlags; - - /// - /// Gets the generic instantiation information of this type. - /// For generic definitions, retrieves the generic parameters of the type. - /// For generic instantiation, retrieves the generic arguments of the type. - /// - public virtual Instantiation Instantiation - { - get - { - return Instantiation.Empty; - } - } - - /// - /// Gets a value indicating whether this type has a generic instantiation. - /// This will be true for generic type instantiations and generic definitions. - /// - public bool HasInstantiation - { - get - { - return this.Instantiation.Length != 0; - } - } - - internal void SetWellKnownType(WellKnownType wellKnownType) - { - TypeFlags flags; - - switch (wellKnownType) - { - case WellKnownType.Void: - case WellKnownType.Boolean: - case WellKnownType.Char: - case WellKnownType.SByte: - case WellKnownType.Byte: - case WellKnownType.Int16: - case WellKnownType.UInt16: - case WellKnownType.Int32: - case WellKnownType.UInt32: - case WellKnownType.Int64: - case WellKnownType.UInt64: - case WellKnownType.IntPtr: - case WellKnownType.UIntPtr: - case WellKnownType.Single: - case WellKnownType.Double: - flags = (TypeFlags)wellKnownType; - break; - - case WellKnownType.ValueType: - case WellKnownType.Enum: - flags = TypeFlags.Class; - break; - - case WellKnownType.Nullable: - flags = TypeFlags.Nullable; - break; - - case WellKnownType.Object: - case WellKnownType.String: - case WellKnownType.Array: - case WellKnownType.MulticastDelegate: - case WellKnownType.Exception: - flags = TypeFlags.Class; - break; - - case WellKnownType.RuntimeTypeHandle: - case WellKnownType.RuntimeMethodHandle: - case WellKnownType.RuntimeFieldHandle: - case WellKnownType.TypedReference: - case WellKnownType.ByReferenceOfT: - flags = TypeFlags.ValueType; - break; - - default: - throw new ArgumentException(); - } - - _typeFlags = flags; - } - - protected abstract TypeFlags ComputeTypeFlags(TypeFlags mask); - - [MethodImpl(MethodImplOptions.NoInlining)] - private TypeFlags InitializeTypeFlags(TypeFlags mask) - { - TypeFlags flags = ComputeTypeFlags(mask); - - if ((flags & mask) == 0) - flags = Context.ComputeTypeFlags(this, flags, mask); - - Debug.Assert((flags & mask) != 0); - _typeFlags |= flags; - - return flags & mask; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected internal TypeFlags GetTypeFlags(TypeFlags mask) - { - TypeFlags flags = _typeFlags & mask; - if (flags != 0) - return flags; - return InitializeTypeFlags(mask); - } - - /// - /// Retrieves the category of the type. This is one of the possible values of - /// less than . - /// - public TypeFlags Category - { - get - { - return GetTypeFlags(TypeFlags.CategoryMask); - } - } - - /// - /// Gets a value indicating whether this type is an interface type. - /// - public bool IsInterface - { - get - { - return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Interface; - } - } - - /// - /// Gets a value indicating whether this type is a value type (not a reference type). - /// - public bool IsValueType - { - get - { - return GetTypeFlags(TypeFlags.CategoryMask) < TypeFlags.Class; - } - } - - /// - /// Gets a value indicating whether this is one of the primitive types (boolean, char, void, - /// a floating point, or an integer type). - /// - public bool IsPrimitive - { - get - { - return GetTypeFlags(TypeFlags.CategoryMask) < TypeFlags.ValueType; - } - } - - /// - /// Gets a value indicating whether this is an enum type. - /// Access to retrieve the underlying integral type. - /// - public bool IsEnum - { - get - { - return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Enum; - } - } - - /// - /// Gets a value indicating whether this is a delegate type. - /// - public bool IsDelegate - { - get - { - var baseType = this.BaseType; - return (baseType != null) ? baseType.IsWellKnownType(WellKnownType.MulticastDelegate) : false; - } - } - - /// - /// Gets a value indicating whether this is System.Void type. - /// - public bool IsVoid - { - get - { - return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Void; - } - } - - /// - /// Gets a value indicating whether this is System.String type. - /// - public bool IsString - { - get - { - return this.IsWellKnownType(WellKnownType.String); - } - } - - /// - /// Gets a value indicating whether this is System.Object type. - /// - public bool IsObject - { - get - { - return this.IsWellKnownType(WellKnownType.Object); - } - } - - /// - /// Gets a value indicating whether this is a generic definition, or - /// an instance of System.Nullable`1. - /// - public bool IsNullable - { - get - { - return this.GetTypeDefinition().IsWellKnownType(WellKnownType.Nullable); - } - } - - /// - /// Gets a value indicating whether this is a generic definition, or - /// an instance of System.ByReference`1. - /// - public bool IsByReferenceOfT - { - get - { - return this.GetTypeDefinition().IsWellKnownType(WellKnownType.ByReferenceOfT); - } - } - - /// - /// Gets a value indicating whether this is an array type (). - /// Note this will return true for both multidimensional array types and vector types. - /// Use to check for vector types. - /// - public bool IsArray - { - get - { - return this is ArrayType; - } - } - - /// - /// Gets a value indicating whether this is a vector type. A vector is a single-dimensional - /// array with a zero lower bound. To check for arrays in general, use . - /// - public bool IsSzArray - { - get - { - return this.IsArray && ((ArrayType)this).IsSzArray; - } - } - - /// - /// Gets a value indicating whether this is a non-vector array type. - /// To check for arrays in general, use . - /// - public bool IsMdArray - { - get - { - return this.IsArray && ((ArrayType)this).IsMdArray; - } - } - - /// - /// Gets a value indicating whether this is a managed pointer type (). - /// - public bool IsByRef - { - get - { - return this is ByRefType; - } - } - - /// - /// Gets a value indicating whether this is an unmanaged pointer type (). - /// - public bool IsPointer - { - get - { - return this is PointerType; - } - } - - /// - /// Gets a value indicating whether this is an unmanaged function pointer type (). - /// - public bool IsFunctionPointer - { - get - { - return this is FunctionPointerType; - } - } - - /// - /// Gets a value indicating whether this is a or . - /// - public bool IsSignatureVariable - { - get - { - return this is SignatureTypeVariable || this is SignatureMethodVariable; - } - } - - /// - /// Gets a value indicating whether this is a generic parameter (). - /// - public bool IsGenericParameter - { - get - { - return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.GenericParameter; - } - } - - /// - /// Gets a value indicating whether this is a pointer, byref, array, or szarray type, - /// and can be used as a ParameterizedType. - /// - public bool IsParameterizedType - { - get - { - TypeFlags flags = GetTypeFlags(TypeFlags.CategoryMask); - Debug.Assert((flags >= TypeFlags.Array && flags <= TypeFlags.Pointer) == (this is ParameterizedType)); - return (flags >= TypeFlags.Array && flags <= TypeFlags.Pointer); - } - } - - /// - /// Gets a value indicating whether this is a class, an interface, a value type, or a - /// generic instance of one of them. - /// - public bool IsDefType - { - get - { - Debug.Assert(GetTypeFlags(TypeFlags.CategoryMask) <= TypeFlags.Interface == this is DefType); - return GetTypeFlags(TypeFlags.CategoryMask) <= TypeFlags.Interface; - } - } - - /// - /// Gets a value indicating whether locations of this type refer to an object on the GC heap. - /// - public bool IsGCPointer - { - get - { - TypeFlags category = GetTypeFlags(TypeFlags.CategoryMask); - return category == TypeFlags.Class - || category == TypeFlags.Array - || category == TypeFlags.SzArray - || category == TypeFlags.Interface; - } - } - - /// - /// Gets the type from which this type derives from, or null if there's no such type. - /// - public virtual DefType BaseType - { - get - { - return null; - } - } - - /// - /// Gets a value indicating whether this type has a base type. - /// - public bool HasBaseType - { - get - { - return BaseType != null; - } - } - - /// - /// If this is an enum type, gets the underlying integral type of the enum type. - /// For all other types, returns 'this'. - /// - public virtual TypeDesc UnderlyingType - { - get - { - if (!this.IsEnum) - return this; - - // TODO: Cache the result? - foreach (var field in this.GetFields()) - { - if (!field.IsStatic) - return field.FieldType; - } - - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, this); - return null; // Unreachable - } - } - - /// - /// Gets a value indicating whether this type has a class constructor method. - /// Use to retrieve it. - /// - public bool HasStaticConstructor - { - get - { - return (GetTypeFlags(TypeFlags.HasStaticConstructor | TypeFlags.HasStaticConstructorComputed) & TypeFlags.HasStaticConstructor) != 0; - } - } - - /// - /// Gets all methods on this type defined within the type's metadata. - /// This will not include methods injected by the type system context. - /// - public virtual IEnumerable GetMethods() - { - return MethodDesc.EmptyMethods; - } - - /// - /// Gets a named method on the type. This method only looks at methods defined - /// in type's metadata. The parameter can be null. - /// If signature is not specified and there are multiple matches, the first one - /// is returned. Returns null if method not found. - /// - // TODO: Substitutions, generics, modopts, ... - public virtual MethodDesc GetMethod(string name, MethodSignature signature) - { - foreach (var method in GetMethods()) - { - if (method.Name == name) - { - if (signature == null || signature.Equals(method.Signature)) - return method; - } - } - return null; - } - - /// - /// Retrieves the class constructor method of this type. - /// - /// - public virtual MethodDesc GetStaticConstructor() - { - return null; - } - - /// - /// Retrieves the public parameterless constructor method of the type, or null if there isn't one - /// or the type is abstract. - /// - public virtual MethodDesc GetDefaultConstructor() - { - return null; - } - - /// - /// Gets all fields on the type as defined in the metadata. - /// - public virtual IEnumerable GetFields() - { - return FieldDesc.EmptyFields; - } - - /// - /// Gets a named field on the type. Returns null if the field wasn't found. - /// - // TODO: Substitutions, generics, modopts, ... - // TODO: field signature - public virtual FieldDesc GetField(string name) - { - foreach (var field in GetFields()) - { - if (field.Name == name) - return field; - } - return null; - } - - public virtual TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - return this; - } - - /// - /// Gets the definition of the type. If this is a generic type instance, - /// this method strips the instantiation (E.g C<int> -> C<T>) - /// - public virtual TypeDesc GetTypeDefinition() - { - return this; - } - - /// - /// Gets a value indicating whether this is a type definition. Returns false - /// if this is an instantiated generic type. - /// - public bool IsTypeDefinition - { - get - { - return GetTypeDefinition() == this; - } - } - - /// - /// Determine if two types share the same type definition - /// - public bool HasSameTypeDefinition(TypeDesc otherType) - { - return GetTypeDefinition() == otherType.GetTypeDefinition(); - } - - /// - /// Gets a value indicating whether this type has a finalizer method. - /// Use to retrieve the method. - /// - public bool HasFinalizer - { - get - { - return (GetTypeFlags(TypeFlags.HasFinalizer | TypeFlags.HasFinalizerComputed) & TypeFlags.HasFinalizer) != 0; - } - } - - /// - /// Gets the finalizer method (an override of the System.Object::Finalize method) - /// if this type has one. Returns null if the type doesn't define one. - /// - public virtual MethodDesc GetFinalizer() - { - return null; - } - - /// - /// Gets a value indicating whether this type has generic variance (the definition of the type - /// has a generic parameter that is co- or contravariant). - /// - public bool HasVariance - { - get - { - return (GetTypeFlags(TypeFlags.HasGenericVariance | TypeFlags.HasGenericVarianceComputed) & TypeFlags.HasGenericVariance) != 0; - } - } - - /// - /// Gets a value indicating whether this type is an uninstantiated definition of a generic type. - /// - public bool IsGenericDefinition - { - get - { - return HasInstantiation && IsTypeDefinition; - } - } - - /// - /// Gets a value indicating whether this is a byref-like type - /// (a TypedReference, Span<T>, etc.). - /// - public bool IsByRefLike - { - get - { - return (GetTypeFlags(TypeFlags.IsByRefLike | TypeFlags.AttributeCacheComputed) & TypeFlags.IsByRefLike) != 0; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeFlags.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeFlags.cs deleted file mode 100644 index 028a7356d21..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeFlags.cs +++ /dev/null @@ -1,64 +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; - -namespace Internal.TypeSystem -{ - [Flags] - public enum TypeFlags - { - CategoryMask = 0x3F, - - // Primitive - Unknown = 0x00, - Void = 0x01, - Boolean = 0x02, - Char = 0x03, - SByte = 0x04, - Byte = 0x05, - Int16 = 0x06, - UInt16 = 0x07, - Int32 = 0x08, - UInt32 = 0x09, - Int64 = 0x0A, - UInt64 = 0x0B, - IntPtr = 0x0C, - UIntPtr = 0x0D, - Single = 0x0E, - Double = 0x0F, - - ValueType = 0x10, - Enum = 0x11, // Parent is enum - Nullable = 0x12, // Nullable instantiation - // Unused 0x13 - - Class = 0x14, - Interface = 0x15, - // Unused 0x16 - - Array = 0x17, - SzArray = 0x18, - ByRef = 0x19, - Pointer = 0x1A, - FunctionPointer = 0x1B, - - GenericParameter = 0x1C, - SignatureTypeVariable = 0x1D, - SignatureMethodVariable = 0x1E, - - HasGenericVariance = 0x100, - HasGenericVarianceComputed = 0x200, - - HasStaticConstructor = 0x400, - HasStaticConstructorComputed = 0x800, - - HasFinalizerComputed = 0x1000, - HasFinalizer = 0x2000, - - IsByRefLike = 0x04000, - AttributeCacheComputed = 0x08000, - IsIntrinsic = 0x10000, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeHashingAlgorithms.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeHashingAlgorithms.cs deleted file mode 100644 index 8e84efc26b6..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeHashingAlgorithms.cs +++ /dev/null @@ -1,255 +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. - -// --------------------------------------------------------------------------- -// Generic functions to compute the hashcode value of types -// --------------------------------------------------------------------------- - -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Text; - -namespace Internal.NativeFormat -{ - public static class TypeHashingAlgorithms - { - public struct HashCodeBuilder - { - private int _hash1; - private int _hash2; - private int _numCharactersHashed; - - public HashCodeBuilder(string seed) - { - _hash1 = 0x6DA3B944; - _hash2 = 0; - _numCharactersHashed = 0; - - Append(seed); - } - - public void Append(string src) - { - if (src.Length == 0) - return; - - int startIndex = 0; - if ((_numCharactersHashed & 1) == 1) - { - _hash2 = (_hash2 + _rotl(_hash2, 5)) ^ src[0]; - startIndex = 1; - } - - for (int i = startIndex; i < src.Length; i += 2) - { - _hash1 = (_hash1 + _rotl(_hash1, 5)) ^ src[i]; - if ((i + 1) < src.Length) - _hash2 = (_hash2 + _rotl(_hash2, 5)) ^ src[i + 1]; - } - - _numCharactersHashed += src.Length; - } - - public int ToHashCode() - { - int hash1 = _hash1 + _rotl(_hash1, 8); - int hash2 = _hash2 + _rotl(_hash2, 8); - - return hash1 ^ hash2; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int _rotl(int value, int shift) - { - return (int)(((uint)value << shift) | ((uint)value >> (32 - shift))); - } - - // - // Returns the hashcode value of the 'src' string - // - public static int ComputeNameHashCode(string src) - { - int hash1 = 0x6DA3B944; - int hash2 = 0; - - for (int i = 0; i < src.Length; i += 2) - { - hash1 = (hash1 + _rotl(hash1, 5)) ^ src[i]; - if ((i + 1) < src.Length) - hash2 = (hash2 + _rotl(hash2, 5)) ^ src[i + 1]; - } - - hash1 += _rotl(hash1, 8); - hash2 += _rotl(hash2, 8); - - return hash1 ^ hash2; - } - - public static unsafe int ComputeASCIINameHashCode(byte* data, int length, out bool isAscii) - { - int hash1 = 0x6DA3B944; - int hash2 = 0; - int asciiMask = 0; - - for (int i = 0; i < length; i += 2) - { - int b1 = data[i]; - asciiMask |= b1; - hash1 = (hash1 + _rotl(hash1, 5)) ^ b1; - if ((i + 1) < length) - { - int b2 = data[i]; - asciiMask |= b2; - hash2 = (hash2 + _rotl(hash2, 5)) ^ b2; - } - } - - hash1 += _rotl(hash1, 8); - hash2 += _rotl(hash2, 8); - - isAscii = (asciiMask & 0x80) == 0; - - return hash1 ^ hash2; - } - - // This function may be needed in a portion of the codebase which is too low level to use - // globalization, ergo, we cannot call ToString on the integer. - private static string IntToString(int arg) - { - // This IntToString function is only expected to be used for MDArrayRanks, and therefore is only for positive numbers - Debug.Assert(arg > 0); - StringBuilder sb = new StringBuilder(1); - - while (arg != 0) - { - sb.Append((char)('0' + (arg % 10))); - arg = arg / 10; - } - - // Reverse the string - int sbLen = sb.Length; - int pivot = sbLen / 2; - for (int i = 0; i < pivot; i++) - { - int iToSwapWith = sbLen - i - 1; - char temp = sb[i]; - sb[i] = sb[iToSwapWith]; - sb[iToSwapWith] = temp; - } - - return sb.ToString(); - } - - public static int ComputeArrayTypeHashCode(int elementTypeHashCode, int rank) - { - // Arrays are treated as generic types in some parts of our system. The array hashcodes are - // carefully crafted to be the same as the hashcodes of their implementation generic types. - - int hashCode; - if (rank == -1) - { - hashCode = unchecked((int)0xd5313557u); - Debug.Assert(hashCode == ComputeNameHashCode("System.Array`1")); - } - else - { - hashCode = ComputeNameHashCode("System.MDArrayRank" + IntToString(rank) + "`1"); - } - - hashCode = (hashCode + _rotl(hashCode, 13)) ^ elementTypeHashCode; - return (hashCode + _rotl(hashCode, 15)); - } - - public static int ComputeArrayTypeHashCode(T elementType, int rank) - { - return ComputeArrayTypeHashCode(elementType.GetHashCode(), rank); - } - - - public static int ComputePointerTypeHashCode(int pointeeTypeHashCode) - { - return (pointeeTypeHashCode + _rotl(pointeeTypeHashCode, 5)) ^ 0x12D0; - } - - public static int ComputePointerTypeHashCode(T pointeeType) - { - return ComputePointerTypeHashCode(pointeeType.GetHashCode()); - } - - - public static int ComputeByrefTypeHashCode(int parameterTypeHashCode) - { - return (parameterTypeHashCode + _rotl(parameterTypeHashCode, 7)) ^ 0x4C85; - } - - public static int ComputeByrefTypeHashCode(T parameterType) - { - return ComputeByrefTypeHashCode(parameterType.GetHashCode()); - } - - - public static int ComputeNestedTypeHashCode(int enclosingTypeHashCode, int nestedTypeNameHash) - { - return (enclosingTypeHashCode + _rotl(enclosingTypeHashCode, 11)) ^ nestedTypeNameHash; - } - - - public static int ComputeGenericInstanceHashCode(int genericDefinitionHashCode, ARG[] genericTypeArguments) - { - int hashcode = genericDefinitionHashCode; - for (int i = 0; i < genericTypeArguments.Length; i++) - { - int argumentHashCode = genericTypeArguments[i].GetHashCode(); - hashcode = (hashcode + _rotl(hashcode, 13)) ^ argumentHashCode; - } - return (hashcode + _rotl(hashcode, 15)); - } - - public static int ComputeMethodSignatureHashCode(int returnTypeHashCode, ARG[] parameters) - { - // We're not taking calling conventions into consideration here mostly because there's no - // exchange enum type that would define them. We could define one, but the amount of additional - // information it would bring (16 or so possibilities) is likely not worth it. - int hashcode = returnTypeHashCode; - for (int i = 0; i < parameters.Length; i++) - { - int parameterHashCode = parameters[i].GetHashCode(); - hashcode = (hashcode + _rotl(hashcode, 13)) ^ parameterHashCode; - } - return (hashcode + _rotl(hashcode, 15)); - } - - /// - /// Produce a hashcode for a specific method - /// - /// HashCode of the type that owns the method - /// HashCode of either the name of the method (for non-generic methods) or the GenericInstanceHashCode of the name+generic arguments of the method. - /// - public static int ComputeMethodHashCode(int typeHashCode, int nameOrNameAndGenericArgumentsHashCode) - { - // TODO! This hash combining function isn't good, but it matches logic used in the past - // consider changing to a better combining function once all uses use this function - return typeHashCode ^ nameOrNameAndGenericArgumentsHashCode; - } - - /// - /// Produce a hashcode for a generic signature variable - /// - /// zero based index - /// true if the signature variable describes a method - public static int ComputeSignatureVariableHashCode(int index, bool method) - { - if (method) - { - return index * 0x7822381 + 0x54872645; - } - else - { - return index * 0x5498341 + 0x832424; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemContext.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemContext.cs deleted file mode 100644 index 35f009c3687..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemContext.cs +++ /dev/null @@ -1,784 +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 System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; - -using Internal.NativeFormat; - -namespace Internal.TypeSystem -{ - public abstract partial class TypeSystemContext - { - public TypeSystemContext() : this(new TargetDetails(TargetArchitecture.Unknown, TargetOS.Unknown, TargetAbi.Unknown)) - { - } - - public TypeSystemContext(TargetDetails target) - { - Target = target; - - _instantiatedTypes = new InstantiatedTypeKey.InstantiatedTypeKeyHashtable(); - - _arrayTypes = new ArrayTypeKey.ArrayTypeKeyHashtable(); - - _byRefTypes = new ByRefHashtable(); - - _pointerTypes = new PointerHashtable(); - - _functionPointerTypes = new FunctionPointerHashtable(); - - _instantiatedMethods = new InstantiatedMethodKey.InstantiatedMethodKeyHashtable(); - - _methodForInstantiatedTypes = new MethodForInstantiatedTypeKey.MethodForInstantiatedTypeKeyHashtable(); - - _fieldForInstantiatedTypes = new FieldForInstantiatedTypeKey.FieldForInstantiatedTypeKeyHashtable(); - - _signatureVariables = new SignatureVariableHashtable(this); - } - - public TargetDetails Target - { - get; - } - - public ModuleDesc SystemModule - { - get; - private set; - } - - protected void InitializeSystemModule(ModuleDesc systemModule) - { - Debug.Assert(SystemModule == null); - SystemModule = systemModule; - } - - public abstract DefType GetWellKnownType(WellKnownType wellKnownType, bool throwIfNotFound = true); - - public virtual ModuleDesc ResolveAssembly(AssemblyName name, bool throwIfNotFound = true) - { - if (throwIfNotFound) - throw new NotSupportedException(); - return null; - } - - internal virtual ModuleDesc ResolveModule(IAssemblyDesc referencingModule, string fileName, bool throwIfNotFound = true) - { - if (throwIfNotFound) - throw new NotSupportedException(); - return null; - } - - // - // Array types - // - - public ArrayType GetArrayType(TypeDesc elementType) - { - return GetArrayType(elementType, -1); - } - - // - // MDArray types - // - - private struct ArrayTypeKey - { - private TypeDesc _elementType; - private int _rank; - - public ArrayTypeKey(TypeDesc elementType, int rank) - { - _elementType = elementType; - _rank = rank; - } - - public TypeDesc ElementType - { - get - { - return _elementType; - } - } - - public int Rank - { - get - { - return _rank; - } - } - - public class ArrayTypeKeyHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(ArrayTypeKey key) - { - return TypeHashingAlgorithms.ComputeArrayTypeHashCode(key._elementType, key._rank); - } - - protected override int GetValueHashCode(ArrayType value) - { - return TypeHashingAlgorithms.ComputeArrayTypeHashCode(value.ElementType, value.IsSzArray ? -1 : value.Rank); - } - - protected override bool CompareKeyToValue(ArrayTypeKey key, ArrayType value) - { - if (key._elementType != value.ElementType) - return false; - - if (value.IsSzArray) - return key._rank == -1; - - return key._rank == value.Rank; - } - - protected override bool CompareValueToValue(ArrayType value1, ArrayType value2) - { - return (value1.ElementType == value2.ElementType) && (value1.Rank == value2.Rank) && value1.IsSzArray == value2.IsSzArray; - } - - protected override ArrayType CreateValueFromKey(ArrayTypeKey key) - { - return new ArrayType(key.ElementType, key.Rank); - } - } - } - - private ArrayTypeKey.ArrayTypeKeyHashtable _arrayTypes; - - public ArrayType GetArrayType(TypeDesc elementType, int rank) - { - return _arrayTypes.GetOrCreateValue(new ArrayTypeKey(elementType, rank)); - } - - // - // ByRef types - // - public class ByRefHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(TypeDesc key) - { - return key.GetHashCode(); - } - - protected override int GetValueHashCode(ByRefType value) - { - return value.ParameterType.GetHashCode(); - } - - protected override bool CompareKeyToValue(TypeDesc key, ByRefType value) - { - return key == value.ParameterType; - } - - protected override bool CompareValueToValue(ByRefType value1, ByRefType value2) - { - return value1.ParameterType == value2.ParameterType; - } - - protected override ByRefType CreateValueFromKey(TypeDesc key) - { - return new ByRefType(key); - } - } - - private ByRefHashtable _byRefTypes; - - public ByRefType GetByRefType(TypeDesc parameterType) - { - return _byRefTypes.GetOrCreateValue(parameterType); - } - - // - // Pointer types - // - public class PointerHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(TypeDesc key) - { - return key.GetHashCode(); - } - - protected override int GetValueHashCode(PointerType value) - { - return value.ParameterType.GetHashCode(); - } - - protected override bool CompareKeyToValue(TypeDesc key, PointerType value) - { - return key == value.ParameterType; - } - - protected override bool CompareValueToValue(PointerType value1, PointerType value2) - { - return value1.ParameterType == value2.ParameterType; - } - - protected override PointerType CreateValueFromKey(TypeDesc key) - { - return new PointerType(key); - } - } - - private PointerHashtable _pointerTypes; - - public PointerType GetPointerType(TypeDesc parameterType) - { - return _pointerTypes.GetOrCreateValue(parameterType); - } - - // - // Function pointer types - // - public class FunctionPointerHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(MethodSignature key) - { - return key.GetHashCode(); - } - - protected override int GetValueHashCode(FunctionPointerType value) - { - return value.Signature.GetHashCode(); - } - - protected override bool CompareKeyToValue(MethodSignature key, FunctionPointerType value) - { - return key.Equals(value.Signature); - } - - protected override bool CompareValueToValue(FunctionPointerType value1, FunctionPointerType value2) - { - return value1.Signature.Equals(value2.Signature); - } - - protected override FunctionPointerType CreateValueFromKey(MethodSignature key) - { - return new FunctionPointerType(key); - } - } - - private FunctionPointerHashtable _functionPointerTypes; - - public FunctionPointerType GetFunctionPointerType(MethodSignature signature) - { - return _functionPointerTypes.GetOrCreateValue(signature); - } - - // - // Instantiated types - // - - private struct InstantiatedTypeKey - { - private TypeDesc _typeDef; - private Instantiation _instantiation; - - public InstantiatedTypeKey(TypeDesc typeDef, Instantiation instantiation) - { - _typeDef = typeDef; - _instantiation = instantiation; - } - - public TypeDesc TypeDef - { - get - { - return _typeDef; - } - } - - public Instantiation Instantiation - { - get - { - return _instantiation; - } - } - - public class InstantiatedTypeKeyHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(InstantiatedTypeKey key) - { - return key._instantiation.ComputeGenericInstanceHashCode(key._typeDef.GetHashCode()); - } - - protected override int GetValueHashCode(InstantiatedType value) - { - return value.Instantiation.ComputeGenericInstanceHashCode(value.GetTypeDefinition().GetHashCode()); - } - - protected override bool CompareKeyToValue(InstantiatedTypeKey key, InstantiatedType value) - { - if (key._typeDef != value.GetTypeDefinition()) - return false; - - Instantiation valueInstantiation = value.Instantiation; - - if (key._instantiation.Length != valueInstantiation.Length) - return false; - - for (int i = 0; i < key._instantiation.Length; i++) - { - if (key._instantiation[i] != valueInstantiation[i]) - return false; - } - - return true; - } - - protected override bool CompareValueToValue(InstantiatedType value1, InstantiatedType value2) - { - if (value1.GetTypeDefinition() != value2.GetTypeDefinition()) - return false; - - Instantiation value1Instantiation = value1.Instantiation; - Instantiation value2Instantiation = value2.Instantiation; - - if (value1Instantiation.Length != value2Instantiation.Length) - return false; - - for (int i = 0; i < value1Instantiation.Length; i++) - { - if (value1Instantiation[i] != value2Instantiation[i]) - return false; - } - - return true; - } - - protected override InstantiatedType CreateValueFromKey(InstantiatedTypeKey key) - { - return new InstantiatedType((MetadataType)key.TypeDef, key.Instantiation); - } - } - } - - private InstantiatedTypeKey.InstantiatedTypeKeyHashtable _instantiatedTypes; - - public InstantiatedType GetInstantiatedType(MetadataType typeDef, Instantiation instantiation) - { - return _instantiatedTypes.GetOrCreateValue(new InstantiatedTypeKey(typeDef, instantiation)); - } - - // - // Instantiated methods - // - - private struct InstantiatedMethodKey - { - private MethodDesc _methodDef; - private Instantiation _instantiation; - private int _hashcode; - - public InstantiatedMethodKey(MethodDesc methodDef, Instantiation instantiation) - { - _methodDef = methodDef; - _instantiation = instantiation; - _hashcode = TypeHashingAlgorithms.ComputeMethodHashCode(methodDef.OwningType.GetHashCode(), - instantiation.ComputeGenericInstanceHashCode(TypeHashingAlgorithms.ComputeNameHashCode(methodDef.Name))); - } - - public MethodDesc MethodDef - { - get - { - return _methodDef; - } - } - - public Instantiation Instantiation - { - get - { - return _instantiation; - } - } - - public class InstantiatedMethodKeyHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(InstantiatedMethodKey key) - { - return key._hashcode; - } - - protected override int GetValueHashCode(InstantiatedMethod value) - { - return value.GetHashCode(); - } - - protected override bool CompareKeyToValue(InstantiatedMethodKey key, InstantiatedMethod value) - { - if (key._methodDef != value.GetMethodDefinition()) - return false; - - Instantiation valueInstantiation = value.Instantiation; - - if (key._instantiation.Length != valueInstantiation.Length) - return false; - - for (int i = 0; i < key._instantiation.Length; i++) - { - if (key._instantiation[i] != valueInstantiation[i]) - return false; - } - - return true; - } - - protected override bool CompareValueToValue(InstantiatedMethod value1, InstantiatedMethod value2) - { - if (value1.GetMethodDefinition() != value2.GetMethodDefinition()) - return false; - - Instantiation value1Instantiation = value1.Instantiation; - Instantiation value2Instantiation = value2.Instantiation; - - if (value1Instantiation.Length != value2Instantiation.Length) - return false; - - for (int i = 0; i < value1Instantiation.Length; i++) - { - if (value1Instantiation[i] != value2Instantiation[i]) - return false; - } - - return true; - } - - protected override InstantiatedMethod CreateValueFromKey(InstantiatedMethodKey key) - { - return new InstantiatedMethod(key.MethodDef, key.Instantiation, key._hashcode); - } - } - } - - private InstantiatedMethodKey.InstantiatedMethodKeyHashtable _instantiatedMethods; - - public InstantiatedMethod GetInstantiatedMethod(MethodDesc methodDef, Instantiation instantiation) - { - Debug.Assert(!(methodDef is InstantiatedMethod)); - return _instantiatedMethods.GetOrCreateValue(new InstantiatedMethodKey(methodDef, instantiation)); - } - - // - // Methods for instantiated type - // - - private struct MethodForInstantiatedTypeKey - { - private MethodDesc _typicalMethodDef; - private InstantiatedType _instantiatedType; - private int _hashcode; - - public MethodForInstantiatedTypeKey(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) - { - _typicalMethodDef = typicalMethodDef; - _instantiatedType = instantiatedType; - _hashcode = TypeHashingAlgorithms.ComputeMethodHashCode(instantiatedType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(typicalMethodDef.Name)); - } - - public MethodDesc TypicalMethodDef - { - get - { - return _typicalMethodDef; - } - } - - public InstantiatedType InstantiatedType - { - get - { - return _instantiatedType; - } - } - - public class MethodForInstantiatedTypeKeyHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(MethodForInstantiatedTypeKey key) - { - return key._hashcode; - } - - protected override int GetValueHashCode(MethodForInstantiatedType value) - { - return value.GetHashCode(); - } - - protected override bool CompareKeyToValue(MethodForInstantiatedTypeKey key, MethodForInstantiatedType value) - { - if (key._typicalMethodDef != value.GetTypicalMethodDefinition()) - return false; - - return key._instantiatedType == value.OwningType; - } - - protected override bool CompareValueToValue(MethodForInstantiatedType value1, MethodForInstantiatedType value2) - { - return (value1.GetTypicalMethodDefinition() == value2.GetTypicalMethodDefinition()) && (value1.OwningType == value2.OwningType); - } - - protected override MethodForInstantiatedType CreateValueFromKey(MethodForInstantiatedTypeKey key) - { - return new MethodForInstantiatedType(key.TypicalMethodDef, key.InstantiatedType, key._hashcode); - } - } - } - - private MethodForInstantiatedTypeKey.MethodForInstantiatedTypeKeyHashtable _methodForInstantiatedTypes; - - public MethodDesc GetMethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) - { - Debug.Assert(!(typicalMethodDef is MethodForInstantiatedType)); - Debug.Assert(!(typicalMethodDef is InstantiatedMethod)); - - return _methodForInstantiatedTypes.GetOrCreateValue(new MethodForInstantiatedTypeKey(typicalMethodDef, instantiatedType)); - } - - // - // Fields for instantiated type - // - - private struct FieldForInstantiatedTypeKey - { - private FieldDesc _fieldDef; - private InstantiatedType _instantiatedType; - - public FieldForInstantiatedTypeKey(FieldDesc fieldDef, InstantiatedType instantiatedType) - { - _fieldDef = fieldDef; - _instantiatedType = instantiatedType; - } - - public FieldDesc TypicalFieldDef - { - get - { - return _fieldDef; - } - } - - public InstantiatedType InstantiatedType - { - get - { - return _instantiatedType; - } - } - - public class FieldForInstantiatedTypeKeyHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(FieldForInstantiatedTypeKey key) - { - return key._fieldDef.GetHashCode() ^ key._instantiatedType.GetHashCode(); - } - - protected override int GetValueHashCode(FieldForInstantiatedType value) - { - return value.GetTypicalFieldDefinition().GetHashCode() ^ value.OwningType.GetHashCode(); - } - - protected override bool CompareKeyToValue(FieldForInstantiatedTypeKey key, FieldForInstantiatedType value) - { - if (key._fieldDef != value.GetTypicalFieldDefinition()) - return false; - - return key._instantiatedType == value.OwningType; - } - - protected override bool CompareValueToValue(FieldForInstantiatedType value1, FieldForInstantiatedType value2) - { - return (value1.GetTypicalFieldDefinition() == value2.GetTypicalFieldDefinition()) && (value1.OwningType == value2.OwningType); - } - - protected override FieldForInstantiatedType CreateValueFromKey(FieldForInstantiatedTypeKey key) - { - return new FieldForInstantiatedType(key.TypicalFieldDef, key.InstantiatedType); - } - } - } - - private FieldForInstantiatedTypeKey.FieldForInstantiatedTypeKeyHashtable _fieldForInstantiatedTypes; - - public FieldDesc GetFieldForInstantiatedType(FieldDesc fieldDef, InstantiatedType instantiatedType) - { - return _fieldForInstantiatedTypes.GetOrCreateValue(new FieldForInstantiatedTypeKey(fieldDef, instantiatedType)); - } - - // - // Signature variables - // - private class SignatureVariableHashtable : LockFreeReaderHashtable - { - private TypeSystemContext _context; - public SignatureVariableHashtable(TypeSystemContext context) - { - _context = context; - } - - protected override int GetKeyHashCode(uint key) - { - return (int)key; - } - - protected override int GetValueHashCode(SignatureVariable value) - { - uint combinedIndex = value.IsMethodSignatureVariable ? ((uint)value.Index | 0x80000000) : (uint)value.Index; - return (int)combinedIndex; - } - - protected override bool CompareKeyToValue(uint key, SignatureVariable value) - { - uint combinedIndex = value.IsMethodSignatureVariable ? ((uint)value.Index | 0x80000000) : (uint)value.Index; - return key == combinedIndex; - } - - protected override bool CompareValueToValue(SignatureVariable value1, SignatureVariable value2) - { - uint combinedIndex1 = value1.IsMethodSignatureVariable ? ((uint)value1.Index | 0x80000000) : (uint)value1.Index; - uint combinedIndex2 = value2.IsMethodSignatureVariable ? ((uint)value2.Index | 0x80000000) : (uint)value2.Index; - - return combinedIndex1 == combinedIndex2; - } - - protected override SignatureVariable CreateValueFromKey(uint key) - { - bool method = ((key & 0x80000000) != 0); - int index = (int)(key & 0x7FFFFFFF); - if (method) - return new SignatureMethodVariable(_context, index); - else - return new SignatureTypeVariable(_context, index); - } - } - - private SignatureVariableHashtable _signatureVariables; - - public TypeDesc GetSignatureVariable(int index, bool method) - { - if (index < 0) - throw new BadImageFormatException(); - - uint combinedIndex = method ? ((uint)index | 0x80000000) : (uint)index; - return _signatureVariables.GetOrCreateValue(combinedIndex); - } - - protected internal virtual IEnumerable GetAllMethods(TypeDesc type) - { - return type.GetMethods(); - } - - /// - /// Abstraction to allow the type system context to affect the field layout - /// algorithm used by types to lay themselves out. - /// - public virtual FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) - { - // Type system contexts that support computing field layout need to override this. - throw new NotSupportedException(); - } - - /// - /// Abstraction to allow the type system context to control the interfaces - /// algorithm used by types. - /// - public RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForType(TypeDesc type) - { - if (type.IsDefType) - { - return GetRuntimeInterfacesAlgorithmForDefType((DefType)type); - } - else if (type.IsArray) - { - ArrayType arrType = (ArrayType)type; - TypeDesc elementType = arrType.ElementType; - if (arrType.IsSzArray && !elementType.IsPointer && !elementType.IsFunctionPointer) - { - return GetRuntimeInterfacesAlgorithmForNonPointerArrayType((ArrayType)type); - } - else - { - return BaseTypeRuntimeInterfacesAlgorithm.Instance; - } - } - - return null; - } - - /// - /// Abstraction to allow the type system context to control the interfaces - /// algorithm used by types. - /// - protected virtual RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) - { - // Type system contexts that support computing runtime interfaces need to override this. - throw new NotSupportedException(); - } - - /// - /// Abstraction to allow the type system context to control the interfaces - /// algorithm used by single dimensional array types. - /// - protected virtual RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) - { - // Type system contexts that support computing runtime interfaces need to override this. - throw new NotSupportedException(); - } - - public virtual VirtualMethodAlgorithm GetVirtualMethodAlgorithmForType(TypeDesc type) - { - // Type system contexts that support virtual method resolution need to override this. - throw new NotSupportedException(); - } - - // Abstraction to allow different runtimes to have different policy about which fields are - // in the GC static region, and which are not - protected internal virtual bool ComputeHasGCStaticBase(FieldDesc field) - { - // Type system contexts that support this need to override this. - throw new NotSupportedException(); - } - - /// - /// TypeSystemContext controlled type flags computation. This allows computation of flags which depend - /// on the particular TypeSystemContext in use - /// - internal TypeFlags ComputeTypeFlags(TypeDesc type, TypeFlags flags, TypeFlags mask) - { - // If we are looking to compute HasStaticConstructor, and we haven't yet assigned a value - if ((mask & TypeFlags.HasStaticConstructorComputed) == TypeFlags.HasStaticConstructorComputed) - { - TypeDesc typeDefinition = type.GetTypeDefinition(); - - if (typeDefinition != type) - { - // If the type definition is different, the code was working with an instantiated generic or some such. - // In that case, just query the HasStaticConstructor property, as it can cache the answer - if (typeDefinition.HasStaticConstructor) - flags |= TypeFlags.HasStaticConstructor; - } - else - { - if (ComputeHasStaticConstructor(typeDefinition)) - { - flags |= TypeFlags.HasStaticConstructor; - } - } - - flags |= TypeFlags.HasStaticConstructorComputed; - } - - return flags; - } - - /// - /// Algorithm to control which types are considered to have static constructors - /// - protected internal abstract bool ComputeHasStaticConstructor(TypeDesc type); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemEntity.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemEntity.cs deleted file mode 100644 index ad3d3739d16..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemEntity.cs +++ /dev/null @@ -1,14 +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. - -namespace Internal.TypeSystem -{ - public abstract class TypeSystemEntity - { - /// - /// Gets the type system context this entity belongs to. - /// - public abstract TypeSystemContext Context { get; } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemException.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemException.cs deleted file mode 100644 index afe5ebf7bbb..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemException.cs +++ /dev/null @@ -1,147 +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 System.Collections.Generic; - -namespace Internal.TypeSystem -{ - /// - /// Base type for all type system exceptions. - /// - public abstract class TypeSystemException : Exception - { - private string[] _arguments; - - /// - /// Gets the resource string identifier. - /// - public ExceptionStringID StringID { get; } - - /// - /// Gets the formatting arguments for the exception string. - /// - public IReadOnlyList Arguments - { - get - { - return _arguments; - } - } - - public override string Message - { - get - { - return GetExceptionString(StringID, _arguments); - } - } - - internal TypeSystemException(ExceptionStringID id, params string[] args) - { - StringID = id; - _arguments = args; - } - - private static string GetExceptionString(ExceptionStringID id, string[] args) - { - // TODO: Share the strings and lookup logic with System.Private.CoreLib. - return "[TEMPORARY EXCEPTION MESSAGE] " + id.ToString() + ": " + String.Join(", ", args); - } - - /// - /// The exception that is thrown when type-loading failures occur. - /// - public class TypeLoadException : TypeSystemException - { - public string TypeName { get; } - - public string AssemblyName { get; } - - internal TypeLoadException(ExceptionStringID id, string typeName, string assemblyName, string messageArg) - : base(id, new string[] { typeName, assemblyName, messageArg }) - { - TypeName = typeName; - AssemblyName = assemblyName; - } - - internal TypeLoadException(ExceptionStringID id, string typeName, string assemblyName) - : base(id, new string[] { typeName, assemblyName }) - { - TypeName = typeName; - AssemblyName = assemblyName; - } - } - - /// - /// The exception that is thrown when there is an attempt to access a class member that does not exist - /// or that is not declared as public. - /// - public abstract class MissingMemberException : TypeSystemException - { - protected internal MissingMemberException(ExceptionStringID id, params string[] args) - : base(id, args) - { - } - } - - /// - /// The exception that is thrown when there is an attempt to access a method that does not exist. - /// - public class MissingMethodException : MissingMemberException - { - internal MissingMethodException(ExceptionStringID id, params string[] args) - : base(id, args) - { - } - } - - /// - /// The exception that is thrown when there is an attempt to access a field that does not exist. - /// - public class MissingFieldException : MissingMemberException - { - internal MissingFieldException(ExceptionStringID id, params string[] args) - : base(id, args) - { - } - } - - /// - /// The exception that is thrown when an attempt to access a file that does not exist on disk fails. - /// - public class FileNotFoundException : TypeSystemException - { - internal FileNotFoundException(ExceptionStringID id, string fileName) - : base(id, fileName) - { - } - } - - /// - /// The exception that is thrown when a program contains invalid Microsoft intermediate language (MSIL) or metadata. - /// Generally this indicates a bug in the compiler that generated the program. - /// - public class InvalidProgramException : TypeSystemException - { - internal InvalidProgramException(ExceptionStringID id, string method) - : base(id, method) - { - } - - internal InvalidProgramException() - : base(ExceptionStringID.InvalidProgramDefault) - { - } - } - - public class BadImageFormatException : TypeSystemException - { - internal BadImageFormatException() - : base(ExceptionStringID.BadImageFormatGeneric) - { - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemHelpers.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemHelpers.cs deleted file mode 100644 index e76f5e30870..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeSystemHelpers.cs +++ /dev/null @@ -1,415 +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 System.Collections.Generic; -using System.Diagnostics; - -namespace Internal.TypeSystem -{ - public static class TypeSystemHelpers - { - public static bool IsWellKnownType(this TypeDesc type, WellKnownType wellKnownType) - { - return type == type.Context.GetWellKnownType(wellKnownType, false); - } - - public static InstantiatedType MakeInstantiatedType(this MetadataType typeDef, Instantiation instantiation) - { - return typeDef.Context.GetInstantiatedType(typeDef, instantiation); - } - - public static InstantiatedType MakeInstantiatedType(this MetadataType typeDef, params TypeDesc[] genericParameters) - { - return typeDef.Context.GetInstantiatedType(typeDef, new Instantiation(genericParameters)); - } - - - public static InstantiatedMethod MakeInstantiatedMethod(this MethodDesc methodDef, Instantiation instantiation) - { - return methodDef.Context.GetInstantiatedMethod(methodDef, instantiation); - } - - public static InstantiatedMethod MakeInstantiatedMethod(this MethodDesc methodDef, params TypeDesc[] genericParameters) - { - return methodDef.Context.GetInstantiatedMethod(methodDef, new Instantiation(genericParameters)); - } - - public static ArrayType MakeArrayType(this TypeDesc type) - { - return type.Context.GetArrayType(type); - } - - /// - /// Creates a multidimensional array type with the specified rank. - /// To create a vector, use the overload. - /// - public static ArrayType MakeArrayType(this TypeDesc type, int rank) - { - return type.Context.GetArrayType(type, rank); - } - - public static ByRefType MakeByRefType(this TypeDesc type) - { - return type.Context.GetByRefType(type); - } - - public static PointerType MakePointerType(this TypeDesc type) - { - return type.Context.GetPointerType(type); - } - - public static TypeDesc GetParameterType(this TypeDesc type) - { - ParameterizedType paramType = (ParameterizedType) type; - return paramType.ParameterType; - } - - public static bool HasLayout(this MetadataType mdType) - { - return mdType.IsSequentialLayout || mdType.IsExplicitLayout; - } - - public static LayoutInt GetElementSize(this TypeDesc type) - { - if (type.IsValueType) - { - return ((DefType)type).InstanceFieldSize; - } - else - { - return type.Context.Target.LayoutPointerSize; - } - } - - /// - /// Gets the parameterless instance constructor on the specified type. To get the default constructor, use . - /// - public static MethodDesc GetParameterlessConstructor(this TypeDesc type) - { - // TODO: Do we want check for specialname/rtspecialname? Maybe add another overload on GetMethod? - var sig = new MethodSignature(0, 0, type.Context.GetWellKnownType(WellKnownType.Void), TypeDesc.EmptyTypes); - return type.GetMethod(".ctor", sig); - } - - public static bool HasExplicitOrImplicitDefaultConstructor(this TypeDesc type) - { - return type.IsValueType || type.GetDefaultConstructor() != null; - } - - internal static MethodDesc FindMethodOnExactTypeWithMatchingTypicalMethod(this TypeDesc type, MethodDesc method) - { - MethodDesc methodTypicalDefinition = method.GetTypicalMethodDefinition(); - - var instantiatedType = type as InstantiatedType; - if (instantiatedType != null) - { - Debug.Assert(instantiatedType.GetTypeDefinition() == methodTypicalDefinition.OwningType); - return method.Context.GetMethodForInstantiatedType(methodTypicalDefinition, instantiatedType); - } - else if (type.IsArray) - { - Debug.Assert(method.OwningType.IsArray); - return ((ArrayType)type).GetArrayMethod(((ArrayMethod)method).Kind); - } - else - { - Debug.Assert(type == methodTypicalDefinition.OwningType); - return methodTypicalDefinition; - } - } - - /// - /// Returns method as defined on a non-generic base class or on a base - /// instantiation. - /// For example, If Foo<T> : Bar<T> and overrides method M, - /// if method is Bar<string>.M(), then this returns Bar<T>.M() - /// but if Foo : Bar<string>, then this returns Bar<string>.M() - /// - /// A potentially derived type - /// A base class's virtual method - public static MethodDesc FindMethodOnTypeWithMatchingTypicalMethod(this TypeDesc targetType, MethodDesc method) - { - // If method is nongeneric and on a nongeneric type, then it is the matching method - if (!method.HasInstantiation && !method.OwningType.HasInstantiation) - { - return method; - } - - // Since method is an instantiation that may or may not be the same as typeExamine's hierarchy, - // find a matching base class on an open type and then work from the instantiation in typeExamine's - // hierarchy - TypeDesc typicalTypeOfTargetMethod = method.GetTypicalMethodDefinition().OwningType; - TypeDesc targetOrBase = targetType; - do - { - TypeDesc openTargetOrBase = targetOrBase; - if (openTargetOrBase is InstantiatedType) - { - openTargetOrBase = openTargetOrBase.GetTypeDefinition(); - } - if (openTargetOrBase == typicalTypeOfTargetMethod) - { - // Found an open match. Now find an equivalent method on the original target typeOrBase - MethodDesc matchingMethod = targetOrBase.FindMethodOnExactTypeWithMatchingTypicalMethod(method); - return matchingMethod; - } - targetOrBase = targetOrBase.BaseType; - } while (targetOrBase != null); - - Debug.Fail("method has no related type in the type hierarchy of type"); - return null; - } - - /// - /// Attempts to resolve constrained call to into a concrete non-unboxing - /// method on . - /// The ability to resolve constraint methods is affected by the degree of code sharing we are performing - /// for generic code. - /// - /// The resolved method or null if the constraint couldn't be resolved. - public static MethodDesc TryResolveConstraintMethodApprox(this TypeDesc constrainedType, TypeDesc interfaceType, MethodDesc interfaceMethod, out bool forceRuntimeLookup) - { - forceRuntimeLookup = false; - - // We can't resolve constraint calls effectively for reference types, and there's - // not a lot of perf. benefit in doing it anyway. - if (!constrainedType.IsValueType) - { - return null; - } - - // Non-virtual methods called through constraints simply resolve to the specified method without constraint resolution. - if (!interfaceMethod.IsVirtual) - { - return null; - } - - MethodDesc method; - - MethodDesc genInterfaceMethod = interfaceMethod.GetMethodDefinition(); - if (genInterfaceMethod.OwningType.IsInterface) - { - // Sometimes (when compiling shared generic code) - // we don't have enough exact type information at JIT time - // even to decide whether we will be able to resolve to an unboxed entry point... - // To cope with this case we always go via the helper function if there's any - // chance of this happening by checking for all interfaces which might possibly - // be compatible with the call (verification will have ensured that - // at least one of them will be) - - // Enumerate all potential interface instantiations - - // TODO: this code assumes no shared generics - Debug.Assert(interfaceType == interfaceMethod.OwningType); - - method = constrainedType.ResolveInterfaceMethodToVirtualMethodOnType(genInterfaceMethod); - } - else if (genInterfaceMethod.IsVirtual) - { - method = constrainedType.FindVirtualFunctionTargetMethodOnObjectType(genInterfaceMethod); - } - else - { - // The method will be null if calling a non-virtual instance - // methods on System.Object, i.e. when these are used as a constraint. - method = null; - } - - if (method == null) - { - // Fall back to VSD - return null; - } - - //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod - // Only return a method if the value type itself declares the method, - // otherwise we might get a method from Object or System.ValueType - if (!method.OwningType.IsValueType) - { - // Fall back to VSD - return null; - } - - // We've resolved the method, ignoring its generic method arguments - // If the method is a generic method then go and get the instantiated descriptor - if (interfaceMethod.HasInstantiation) - { - method = method.MakeInstantiatedMethod(interfaceMethod.Instantiation); - } - - Debug.Assert(method != null); - //assert(!pMD->IsUnboxingStub()); - - return method; - } - - /// - /// Retrieves the namespace qualified name of a . - /// - public static string GetFullName(this DefType metadataType) - { - string ns = metadataType.Namespace; - return ns.Length > 0 ? String.Concat(ns, ".", metadataType.Name) : metadataType.Name; - } - - /// - /// Retrieves all methods on a type, including the ones injected by the type system context. - /// - public static IEnumerable GetAllMethods(this TypeDesc type) - { - return type.Context.GetAllMethods(type); - } - - public static IEnumerable EnumAllVirtualSlots(this TypeDesc type) - { - return type.Context.GetVirtualMethodAlgorithmForType(type).ComputeAllVirtualSlots(type); - } - - /// - /// Resolves interface method '' to a method on '' - /// that implements the the method. - /// - public static MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(this TypeDesc type, MethodDesc interfaceMethod) - { - return type.Context.GetVirtualMethodAlgorithmForType(type).ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, type); - } - - public static MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(this TypeDesc type, MethodDesc interfaceMethod) - { - return type.Context.GetVirtualMethodAlgorithmForType(type).ResolveVariantInterfaceMethodToVirtualMethodOnType(interfaceMethod, type); - } - - /// - /// Resolves a virtual method call. - /// - public static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(this TypeDesc type, MethodDesc targetMethod) - { - return type.Context.GetVirtualMethodAlgorithmForType(type).FindVirtualFunctionTargetMethodOnObjectType(targetMethod, type); - } - - /// - /// Creates an open instantiation of a type. Given Foo<T>, returns Foo<!0>. - /// If the type is not generic, returns the . - /// - public static TypeDesc InstantiateAsOpen(this TypeDesc type) - { - if (!type.IsGenericDefinition) - { - Debug.Assert(!type.HasInstantiation); - return type; - } - - TypeSystemContext context = type.Context; - - var inst = new TypeDesc[type.Instantiation.Length]; - for (int i = 0; i < inst.Length; i++) - { - inst[i] = context.GetSignatureVariable(i, false); - } - - return context.GetInstantiatedType((MetadataType)type, new Instantiation(inst)); - } - - /// - /// Creates an open instantiation of a field. Given Foo<T>.Field, returns - /// Foo<!0>.Field. If the owning type is not generic, returns the . - /// - public static FieldDesc InstantiateAsOpen(this FieldDesc field) - { - Debug.Assert(field.GetTypicalFieldDefinition() == field); - - TypeDesc owner = field.OwningType; - - if (owner.HasInstantiation) - { - var instantiatedOwner = (InstantiatedType)owner.InstantiateAsOpen(); - return field.Context.GetFieldForInstantiatedType(field, instantiatedOwner); - } - - return field; - } - - /// - /// Creates an open instantiation of a method. Given Foo<T>.Method, returns - /// Foo<!0>.Method. If the owning type is not generic, returns the . - /// - public static MethodDesc InstantiateAsOpen(this MethodDesc method) - { - Debug.Assert(method.IsMethodDefinition && !method.HasInstantiation); - - TypeDesc owner = method.OwningType; - - if (owner.HasInstantiation) - { - MetadataType instantiatedOwner = (MetadataType)owner.InstantiateAsOpen(); - return method.Context.GetMethodForInstantiatedType(method, (InstantiatedType)instantiatedOwner); - } - - return method; - } - - /// - /// Scan the type and its base types for an implementation of an interface method. Returns null if no - /// implementation is found. - /// - public static MethodDesc ResolveInterfaceMethodTarget(this TypeDesc thisType, MethodDesc interfaceMethodToResolve) - { - Debug.Assert(interfaceMethodToResolve.OwningType.IsInterface); - - MethodDesc result = null; - TypeDesc currentType = thisType; - do - { - result = currentType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethodToResolve); - currentType = currentType.BaseType; - } - while (result == null && currentType != null); - - return result; - } - - public static bool ContainsSignatureVariables(this TypeDesc thisType) - { - switch (thisType.Category) - { - case TypeFlags.Array: - case TypeFlags.SzArray: - case TypeFlags.ByRef: - case TypeFlags.Pointer: - return ((ParameterizedType)thisType).ParameterType.ContainsSignatureVariables(); - - case TypeFlags.FunctionPointer: - - var fptr = (FunctionPointerType)thisType; - if (fptr.Signature.ReturnType.ContainsSignatureVariables()) - return true; - - for (int i = 0; i < fptr.Signature.Length; i++) - { - if (fptr.Signature[i].ContainsSignatureVariables()) - return true; - } - return false; - - case TypeFlags.SignatureMethodVariable: - case TypeFlags.SignatureTypeVariable: - return true; - - case TypeFlags.GenericParameter: - throw new ArgumentException(); - - default: - Debug.Assert(thisType is DefType); - foreach (TypeDesc arg in thisType.Instantiation) - { - if (arg.ContainsSignatureVariables()) - return true; - } - - return false; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameFormatter.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameFormatter.cs deleted file mode 100644 index 864a7b3220c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameFormatter.cs +++ /dev/null @@ -1,187 +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 System.Text; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// Formats type names in the 'SerString' format as defined by the ECMA-335 standard. - /// This is the inverse of what does. - /// - public sealed class CustomAttributeTypeNameFormatter : TypeNameFormatter - { - private readonly IAssemblyDesc _relativeHomeAssembly; - - public CustomAttributeTypeNameFormatter() - { - } - - public CustomAttributeTypeNameFormatter(IAssemblyDesc relativeHomeAssembly) - { - _relativeHomeAssembly = relativeHomeAssembly; - } - - private void AppendAssemblyName(StringBuilder sb, IAssemblyDesc assembly) - { - if (assembly == _relativeHomeAssembly || assembly == null) - return; - - sb.Append(','); - AppendEscapedIdentifier(sb, assembly.GetName().Name); - } - - public override IAssemblyDesc AppendName(StringBuilder sb, ArrayType type, bool assemblyQualify) - { - IAssemblyDesc homeAssembly = AppendName(sb, type.ElementType, false); - - if (type.IsSzArray) - { - sb.Append("[]"); - } - else if (type.Rank == 1) - { - sb.Append("[*]"); - } - else - { - sb.Append('['); - sb.Append(',', type.Rank - 1); - sb.Append(']'); - } - - if (assemblyQualify) - AppendAssemblyName(sb, homeAssembly); - - return homeAssembly; - } - - public override IAssemblyDesc AppendName(StringBuilder sb, ByRefType type, bool assemblyQualify) - { - IAssemblyDesc homeAssembly = AppendName(sb, type.ParameterType, false); - - sb.Append('&'); - - if (assemblyQualify) - AppendAssemblyName(sb, homeAssembly); - - return homeAssembly; - } - - public override IAssemblyDesc AppendName(StringBuilder sb, PointerType type, bool assemblyQualify) - { - IAssemblyDesc homeAssembly = AppendName(sb, type.ParameterType, false); - - sb.Append('*'); - - if (assemblyQualify) - AppendAssemblyName(sb, homeAssembly); - - return homeAssembly; - } - - public override IAssemblyDesc AppendName(StringBuilder sb, FunctionPointerType type, bool assemblyQualify) - { - throw new NotSupportedException(); - } - - public override IAssemblyDesc AppendName(StringBuilder sb, GenericParameterDesc type, bool assemblyQualify) - { - throw new NotSupportedException(); - } - - public override IAssemblyDesc AppendName(StringBuilder sb, SignatureMethodVariable type, bool assemblyQualify) - { - throw new NotSupportedException(); - } - - public override IAssemblyDesc AppendName(StringBuilder sb, SignatureTypeVariable type, bool assemblyQualify) - { - throw new NotSupportedException(); - } - - protected override IAssemblyDesc AppendNameForInstantiatedType(StringBuilder sb, DefType type, bool assemblyQualify) - { - IAssemblyDesc homeAssembly = AppendName(sb, type.GetTypeDefinition(), false); - - sb.Append('['); - - for (int i = 0; i < type.Instantiation.Length; i++) - { - if (i != 0) - sb.Append(','); - - sb.Append('['); - AppendName(sb, type.Instantiation[i], true); - sb.Append(']'); - } - - sb.Append(']'); - - if (assemblyQualify) - AppendAssemblyName(sb, homeAssembly); - - return homeAssembly; - } - - protected override IAssemblyDesc AppendNameForNamespaceType(StringBuilder sb, DefType type, bool assemblyQualify) - { - string ns = type.Namespace; - if (ns.Length > 0) - { - AppendEscapedIdentifier(sb, ns); - sb.Append('.'); - } - AppendEscapedIdentifier(sb, type.Name); - - if (type is MetadataType mdType) - { - Debug.Assert(mdType.Module is IAssemblyDesc, "Multi-module?"); - - if (assemblyQualify) - AppendAssemblyName(sb, (IAssemblyDesc)mdType.Module); - - return (IAssemblyDesc)mdType.Module; - } - - return null; - } - - protected override IAssemblyDesc AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType, bool assemblyQualify) - { - IAssemblyDesc homeAssembly = AppendName(sb, containingType, false); - - sb.Append('+'); - - AppendEscapedIdentifier(sb, nestedType.Name); - - if (assemblyQualify) - AppendAssemblyName(sb, homeAssembly); - - return homeAssembly; - } - - private static char[] s_escapedChars = new char[] { ',', '=', '"', ']', '[', '*', '&', '+', '\\' }; - private void AppendEscapedIdentifier(StringBuilder sb, string identifier) - { - if (identifier.IndexOfAny(s_escapedChars) < 0) - { - string escapedIdentifier = identifier; - foreach (char escapedChar in s_escapedChars) - { - string escapedCharString = new string(escapedChar, 1); - escapedIdentifier = escapedIdentifier.Replace(escapedCharString, "\\" + escapedCharString); - } - sb.Append(escapedIdentifier); - } - else - { - sb.Append(identifier); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs deleted file mode 100644 index 1bea19a91a5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs +++ /dev/null @@ -1,453 +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 System.Collections.Generic; -using System.Text; - -using AssemblyName = System.Reflection.AssemblyName; -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // TODO: This file is pretty much a line-by-line port of C++ code to parse CA type name strings from NUTC. - // It's a stopgap solution. - // This should be replaced with type name parser in System.Reflection.Metadata once it starts shipping. - - public static class CustomAttributeTypeNameParser - { - /// - /// Parses the string '' and returns the type corresponding to the parsed type name. - /// The type name string should be in the 'SerString' format as defined by the ECMA-335 standard. - /// This is the inverse of what does. - /// - public static TypeDesc GetTypeByCustomAttributeTypeName(this ModuleDesc module, string name, bool throwIfNotFound = true, Func resolver = null) - { - TypeDesc loadedType; - - StringBuilder genericTypeDefName = new StringBuilder(name.Length); - - var ch = name.Begin(); - var nameEnd = name.End(); - - for (; ch < nameEnd; ++ch) - { - // Always pass escaped characters through. - if (ch.Current == '\\') - { - genericTypeDefName.Append(ch.Current); - ++ch; - if (ch < nameEnd) - { - genericTypeDefName.Append(ch.Current); - } - continue; - } - - // The type def name ends if - - // The start of a generic argument list - if (ch.Current == '[') - break; - - // Indication that the type is a pointer - if (ch.Current == '*') - break; - - // Indication that the type is a reference - if (ch.Current == '&') - break; - - // A comma that indicates that the rest of the name is an assembly reference - if (ch.Current == ',') - break; - - genericTypeDefName.Append(ch.Current); - } - - ModuleDesc homeModule = module; - AssemblyName homeAssembly = FindAssemblyIfNamePresent(name); - if (homeAssembly != null) - { - homeModule = module.Context.ResolveAssembly(homeAssembly); - } - MetadataType typeDef = resolver != null ? resolver(genericTypeDefName.ToString(), homeModule, throwIfNotFound) : - ResolveCustomAttributeTypeDefinitionName(genericTypeDefName.ToString(), homeModule, throwIfNotFound); - if (typeDef == null) - return null; - - ArrayBuilder genericArgs = new ArrayBuilder(); - - // Followed by generic instantiation parameters (but check for the array case) - if (ch < nameEnd && ch.Current == '[' && (ch + 1) < nameEnd && (ch + 1).Current != ']' && (ch + 1).Current != ',') - { - ch++; // truncate the '[' - var genericInstantiationEnd = ch + ReadTypeArgument(ch, nameEnd, true); // find the end of the instantiation list - while (ch < genericInstantiationEnd) - { - if (ch.Current == ',') - ch++; - - int argLen = ReadTypeArgument(ch, name.End(), false); - string typeArgName; - if (ch.Current == '[') - { - // This type argument name is stringified, - // we need to remove the [] from around it - ch++; - typeArgName = StringIterator.Substring(ch, ch + (argLen - 2)); - ch += argLen - 1; - } - else - { - typeArgName = StringIterator.Substring(ch, ch + argLen); - ch += argLen; - } - - TypeDesc argType = module.GetTypeByCustomAttributeTypeName(typeArgName, throwIfNotFound, resolver); - if (argType == null) - return null; - genericArgs.Add(argType); - } - - Debug.Assert(ch == genericInstantiationEnd); - ch++; - - loadedType = typeDef.MakeInstantiatedType(genericArgs.ToArray()); - } - else - { - // Non-generic type - loadedType = typeDef; - } - - // At this point the characters following may be any number of * characters to indicate pointer depth - while (ch < nameEnd) - { - if (ch.Current == '*') - { - loadedType = loadedType.MakePointerType(); - } - else - { - break; - } - ch++; - } - - // Followed by any number of "[]" or "[,*]" pairs to indicate arrays - int commasSeen = 0; - bool bracketSeen = false; - while (ch < nameEnd) - { - if (ch.Current == '[') - { - ch++; - commasSeen = 0; - bracketSeen = true; - } - else if (ch.Current == ']') - { - if (!bracketSeen) - break; - - ch++; - if (commasSeen == 0) - { - loadedType = loadedType.MakeArrayType(); - } - else - { - loadedType = loadedType.MakeArrayType(commasSeen + 1); - } - - bracketSeen = false; - } - else if (ch.Current == ',') - { - if (!bracketSeen) - break; - ch++; - commasSeen++; - } - else - { - break; - } - } - - // Followed by at most one & character to indicate a byref. - if (ch < nameEnd) - { - if (ch.Current == '&') - { - loadedType = loadedType.MakeByRefType(); - ch++; - } - } - - return loadedType; - } - - - public static MetadataType ResolveCustomAttributeTypeDefinitionName(string name, ModuleDesc module, bool throwIfNotFound) - { - MetadataType containingType = null; - StringBuilder typeName = new StringBuilder(name.Length); - bool escaped = false; - for (var c = name.Begin(); c < name.End(); c++) - { - if (c.Current == '\\' && !escaped) - { - escaped = true; - continue; - } - - if (escaped) - { - escaped = false; - typeName.Append(c.Current); - continue; - } - - if (c.Current == ',') - { - break; - } - - if (c.Current == '[' || c.Current == '*' || c.Current == '&') - { - break; - } - - if (c.Current == '+') - { - if (containingType != null) - { - MetadataType outerType = containingType; - containingType = outerType.GetNestedType(typeName.ToString()); - if (containingType == null) - { - if (throwIfNotFound) - ThrowHelper.ThrowTypeLoadException(typeName.ToString(), outerType.Module); - - return null; - } - } - else - { - containingType = module.GetType(typeName.ToString(), throwIfNotFound); - if (containingType == null) - return null; - } - typeName.Length = 0; - continue; - } - - typeName.Append(c.Current); - } - - if (containingType != null) - { - MetadataType type = containingType.GetNestedType(typeName.ToString()); - if ((type == null) && throwIfNotFound) - ThrowHelper.ThrowTypeLoadException(typeName.ToString(), containingType.Module); - - return type; - } - - return module.GetType(typeName.ToString(), throwIfNotFound); - } - - private static MetadataType GetType(this ModuleDesc module, string fullName, bool throwIfNotFound = true) - { - string namespaceName; - string typeName; - int split = fullName.LastIndexOf('.'); - if (split < 0) - { - namespaceName = ""; - typeName = fullName; - } - else - { - namespaceName = fullName.Substring(0, split); - typeName = fullName.Substring(split + 1); - } - return module.GetType(namespaceName, typeName, throwIfNotFound); - } - - private static AssemblyName FindAssemblyIfNamePresent(string name) - { - AssemblyName result = null; - var endOfType = name.Begin() + ReadTypeArgument(name.Begin(), name.End(), false); - if (endOfType < name.End() && endOfType.Current == ',') - { - // There is an assembly name here - int foundCommas = 0; - var endOfAssemblyName = endOfType; - for (var ch = endOfType + 1; ch < name.End(); ch++) - { - if (foundCommas == 3) - { - // We're now eating the public key token, looking for the end of the name, - // or a right bracket - if (ch.Current == ']' || ch.Current == ',') - { - endOfAssemblyName = ch - 1; - break; - } - } - - if (ch.Current == ',') - { - foundCommas++; - } - } - if (endOfAssemblyName == endOfType) - { - endOfAssemblyName = name.End(); - } - - // eat the comma - endOfType++; - for (; endOfType < endOfAssemblyName; ++endOfType) - { - // trim off spaces - if (endOfType.Current != ' ') - break; - } - result = new AssemblyName(StringIterator.Substring(endOfType, endOfAssemblyName)); - } - return result; - } - - private static int ReadTypeArgument(StringIterator strBegin, StringIterator strEnd, bool ignoreComma) - { - int level = 0; - int length = 0; - for (var c = strBegin; c < strEnd; c++) - { - if (c.Current == '\\') - { - length++; - if ((c + 1) < strEnd) - { - c++; - length++; - } - continue; - } - if (c.Current == '[') - { - level++; - } - else if (c.Current == ']') - { - if (level == 0) - break; - level--; - } - else if (!ignoreComma && (c.Current == ',')) - { - if (level == 0) - break; - } - - length++; - } - - return length; - } - - #region C++ string iterator compatibility shim - - private static StringIterator Begin(this string s) - { - return new StringIterator(s, 0); - } - - private static StringIterator End(this string s) - { - return new StringIterator(s, s.Length); - } - - struct StringIterator - { - private string _string; - private int _index; - - public char Current - { - get - { - return _string[_index]; - } - } - - public StringIterator(string s, int index) - { - Debug.Assert(index <= s.Length); - _string = s; - _index = index; - } - - public static string Substring(StringIterator it1, StringIterator it2) - { - Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); - return it1._string.Substring(it1._index, it2._index - it1._index); - } - - public static StringIterator operator++(StringIterator it) - { - return new StringIterator(it._string, ++it._index); - } - - public static bool operator <(StringIterator it1, StringIterator it2) - { - Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); - return it1._index < it2._index; - } - - public static bool operator >(StringIterator it1, StringIterator it2) - { - Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); - return it1._index > it2._index; - } - - public static StringIterator operator+(StringIterator it, int val) - { - return new StringIterator(it._string, it._index + val); - } - - public static StringIterator operator-(StringIterator it, int val) - { - return new StringIterator(it._string, it._index - val); - } - - public static bool operator==(StringIterator it1, StringIterator it2) - { - Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); - return it1._index == it2._index; - } - - public static bool operator !=(StringIterator it1, StringIterator it2) - { - Debug.Assert(Object.ReferenceEquals(it1._string, it2._string)); - return it1._index != it2._index; - } - - public override bool Equals(object obj) - { - throw new NotImplementedException(); - } - - public override int GetHashCode() - { - throw new NotImplementedException(); - } - } - #endregion - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/DebugNameFormatter.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/DebugNameFormatter.cs deleted file mode 100644 index ea8dfb77288..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/DebugNameFormatter.cs +++ /dev/null @@ -1,275 +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 System.Text; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - public partial class DebugNameFormatter : TypeNameFormatter - { - public static readonly DebugNameFormatter Instance = new DebugNameFormatter(); - - public override Void AppendName(StringBuilder sb, ArrayType type, FormatOptions options) - { - AppendName(sb, type.ElementType, options); - - if (!type.IsSzArray && type.Rank == 1) - { - sb.Append("[*]"); - } - else - { - sb.Append('['); - sb.Append(',', type.Rank - 1); - sb.Append(']'); - } - - return Void.Value; - } - - public override Void AppendName(StringBuilder sb, ByRefType type, FormatOptions options) - { - AppendName(sb, type.ParameterType, options); - sb.Append('&'); - - return Void.Value; - } - - public override Void AppendName(StringBuilder sb, PointerType type, FormatOptions options) - { - AppendName(sb, type.ParameterType, options); - sb.Append('*'); - - return Void.Value; - } - - public override Void AppendName(StringBuilder sb, FunctionPointerType type, FormatOptions options) - { - MethodSignature signature = type.Signature; - - sb.Append("(*"); - AppendName(sb, signature.ReturnType, options); - sb.Append(")("); - for (int i = 0; i < signature.Length; i++) - { - if (i > 0) - sb.Append(','); - AppendName(sb, signature[i], options); - } - sb.Append(')'); - - return Void.Value; - } - - public override Void AppendName(StringBuilder sb, GenericParameterDesc type, FormatOptions options) - { - sb.Append(type.DiagnosticName); - return Void.Value; - } - - public override Void AppendName(StringBuilder sb, SignatureMethodVariable type, FormatOptions options) - { - sb.Append("!!"); - sb.Append(type.Index.ToStringInvariant()); - - return Void.Value; - } - - public override Void AppendName(StringBuilder sb, SignatureTypeVariable type, FormatOptions options) - { - sb.Append("!"); - sb.Append(type.Index.ToStringInvariant()); - - return Void.Value; - } - - protected override Void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType, FormatOptions options) - { - if ((options & FormatOptions.NamespaceQualify) != 0) - { - AppendName(sb, containingType, options); - sb.Append('+'); - } - - sb.Append(nestedType.DiagnosticName); - - return Void.Value; - } - - protected override Void AppendNameForNamespaceType(StringBuilder sb, DefType type, FormatOptions options) - { - int initialLen = sb.Length; - try - { - // Shortcut some of the well known types - switch (type.Category) - { - case TypeFlags.Void: - sb.Append("void"); - return Void.Value; - case TypeFlags.Boolean: - sb.Append("bool"); - return Void.Value; - case TypeFlags.Char: - sb.Append("char"); - return Void.Value; - case TypeFlags.SByte: - sb.Append("int8"); - return Void.Value; - case TypeFlags.Byte: - sb.Append("uint8"); - return Void.Value; - case TypeFlags.Int16: - sb.Append("int16"); - return Void.Value; - case TypeFlags.UInt16: - sb.Append("uint16"); - return Void.Value; - case TypeFlags.Int32: - sb.Append("int32"); - return Void.Value; - case TypeFlags.UInt32: - sb.Append("uint32"); - return Void.Value; - case TypeFlags.Int64: - sb.Append("int64"); - return Void.Value; - case TypeFlags.UInt64: - sb.Append("uint64"); - return Void.Value; - case TypeFlags.IntPtr: - sb.Append("native int"); - return Void.Value; - case TypeFlags.UIntPtr: - sb.Append("native uint"); - return Void.Value; - case TypeFlags.Single: - sb.Append("float32"); - return Void.Value; - case TypeFlags.Double: - sb.Append("float64"); - return Void.Value; - } - - if (type.IsString) - { - sb.Append("string"); - return Void.Value; - } - - if (type.IsObject) - { - sb.Append("object"); - return Void.Value; - } - - AssemblyQualify(sb, type, options); - NamespaceQualify(sb, type, options); - sb.Append(type.DiagnosticName); - } - catch - { - sb.Length = initialLen; - - // - AssemblyQualify(sb, type, options); - NamespaceQualify(sb, type, options); - sb.Append(type.DiagnosticName); - } - - return Void.Value; - } - - private void AssemblyQualify(StringBuilder sb, DefType type, FormatOptions options) - { - if (((options & FormatOptions.AssemblyQualify) != 0) - && type is MetadataType mdType - && mdType.Module is IAssemblyDesc) - { - sb.Append('['); - - // Trim the "System.Private." prefix - string assemblyName; - try - { - assemblyName = ((IAssemblyDesc)mdType.Module).GetName().Name; - } - catch - { - assemblyName = "Unknown"; - } - - if (assemblyName.StartsWith("System.Private", StringComparison.Ordinal)) - assemblyName = "S.P" + assemblyName.Substring(14); - - sb.Append(assemblyName); - sb.Append(']'); - } - } - - private void NamespaceQualify(StringBuilder sb, DefType type, FormatOptions options) - { - if ((options & FormatOptions.NamespaceQualify) != 0) - { - string ns = type.DiagnosticNamespace; - if (!string.IsNullOrEmpty(ns)) - { - sb.Append(ns); - sb.Append('.'); - } - } - } - - protected override Void AppendNameForInstantiatedType(StringBuilder sb, DefType type, FormatOptions options) - { - AppendName(sb, type.GetTypeDefinition(), options); - - FormatOptions parameterOptions = options & ~FormatOptions.AssemblyQualify; - - sb.Append('<'); - - for (int i = 0; i < type.Instantiation.Length; i++) - { - if (i != 0) - sb.Append(','); - - AppendName(sb, type.Instantiation[i], parameterOptions); - } - - sb.Append('>'); - - return Void.Value; - } - - protected override DefType GetContainingType(DefType possibleInnerType, FormatOptions options) - { - try - { - return possibleInnerType.ContainingType; - } - catch - { - return null; - } - } - - public struct Void - { - public static Void Value => default(Void); - } - - [Flags] - public enum FormatOptions - { - None = 0, - AssemblyQualify = 0x1, - NamespaceQualify = 0x2, - - Default = AssemblyQualify | NamespaceQualify, - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.Metadata.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.Metadata.cs deleted file mode 100644 index f79364bfd1d..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.Metadata.cs +++ /dev/null @@ -1,20 +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. - -namespace Internal.TypeSystem -{ - // Type name formatting functionality that relies on metadata. - partial class ExceptionTypeNameFormatter - { - private string GetTypeName(DefType type) - { - return type.Name; - } - - private string GetTypeNamespace(DefType type) - { - return type.Namespace; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.cs deleted file mode 100644 index 4e7447cc4a3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/ExceptionTypeNameFormatter.cs +++ /dev/null @@ -1,118 +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 System.Text; - -namespace Internal.TypeSystem -{ - /// - /// Provides a name formatter that is compatible with SigFormat.cpp in the CLR. - /// - public partial class ExceptionTypeNameFormatter : TypeNameFormatter - { - public static ExceptionTypeNameFormatter Instance { get; } = new ExceptionTypeNameFormatter(); - - public override void AppendName(StringBuilder sb, PointerType type) - { - AppendName(sb, type.ParameterType); - sb.Append('*'); - } - - public override void AppendName(StringBuilder sb, GenericParameterDesc type) - { - string prefix = type.Kind == GenericParameterKind.Type ? "!" : "!!"; - sb.Append(prefix); - sb.Append(type.Name); - } - - public override void AppendName(StringBuilder sb, SignatureTypeVariable type) - { - sb.Append("!"); - sb.Append(type.Index.ToStringInvariant()); - } - - public override void AppendName(StringBuilder sb, SignatureMethodVariable type) - { - sb.Append("!!"); - sb.Append(type.Index.ToStringInvariant()); - } - - public override void AppendName(StringBuilder sb, FunctionPointerType type) - { - MethodSignature signature = type.Signature; - - AppendName(sb, signature.ReturnType); - - sb.Append(" ("); - for (int i = 0; i < signature.Length; i++) - { - if (i > 0) - sb.Append(", "); - AppendName(sb, signature[i]); - } - - // TODO: Append '...' for vararg methods - - sb.Append(')'); - } - - public override void AppendName(StringBuilder sb, ByRefType type) - { - AppendName(sb, type.ParameterType); - sb.Append(" ByRef"); - } - - public override void AppendName(StringBuilder sb, ArrayType type) - { - AppendName(sb, type.ElementType); - sb.Append('['); - - // NOTE: We're ignoring difference between SzArray and MdArray rank 1 for SigFormat.cpp compat. - sb.Append(',', type.Rank - 1); - - sb.Append(']'); - } - - protected override void AppendNameForInstantiatedType(StringBuilder sb, DefType type) - { - AppendName(sb, type.GetTypeDefinition()); - sb.Append('<'); - - for (int i = 0; i < type.Instantiation.Length; i++) - { - if (i > 0) - sb.Append(", "); - AppendName(sb, type.Instantiation[i]); - } - - sb.Append('>'); - } - - protected override void AppendNameForNamespaceType(StringBuilder sb, DefType type) - { - if (type.IsPrimitive) - { - sb.Append(GetTypeName(type)); - } - else - { - string ns = GetTypeNamespace(type); - if (ns.Length > 0) - { - sb.Append(ns); - sb.Append('.'); - } - sb.Append(GetTypeName(type)); - } - } - - protected override void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType) - { - // NOTE: We're ignoring the containing type for compatiblity with SigFormat.cpp - sb.Append(GetTypeName(nestedType)); - } - } -} - diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs deleted file mode 100644 index f9b929546c3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs +++ /dev/null @@ -1,600 +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 System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading; -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// A hash table which is lock free for readers and up to 1 writer at a time. - /// It must be possible to compute the key's hashcode from a value. - /// All values must be reference types. - /// It must be possible to perform an equality check between a key and a value. - /// It must be possible to perform an equality check between a value and a value. - /// A LockFreeReaderKeyValueComparer must be provided to perform these operations. - /// - /// - /// - abstract public class LockFreeReaderHashtable where TValue : class - { - private const int _initialSize = 16; - private const int _fillPercentageBeforeResize = 60; - - /// - /// _hashtable is the currently visible underlying array for the hashtable - /// Any modifications to this array must be additive only, and there must - /// never be a situation where the visible _hashtable has less data than - /// it did at an earlier time. This value is initialized to an array of size - /// 1. (That array is never mutated as any additions will trigger an Expand - /// operation, but we don't use an empty array as the - /// initial step, as this approach allows the TryGetValue logic to always - /// succeed without needing any length or null checks.) - /// - private volatile TValue[] _hashtable = new TValue[_initialSize]; - - /// - /// Tracks the hashtable being used by expansion. Used as a sentinel - /// to threads trying to add to the old hashtable that an expansion is - /// in progress. - /// - private volatile TValue[] _newHashTable; - - /// - /// _count represents the current count of elements in the hashtable - /// _count is used in combination with _resizeCount to control when the - /// hashtable should expand - /// - private volatile int _count = 0; - - /// - /// Represents _count plus the number of potential adds currently happening. - /// If this reaches _hashTable.Length-1, an expansion is required (because - /// one slot must always be null for seeks to complete). - /// - private int _reserve = 0; - - /// - /// _resizeCount represents the size at which the hashtable should resize. - /// While this doesn't strictly need to be volatile, having threads read stale values - /// triggers a lot of unneeded attempts to expand. - /// - private volatile int _resizeCount = _initialSize * _fillPercentageBeforeResize / 100; - - /// - /// Get the underlying array for the hashtable at this time. - /// - private TValue[] GetCurrentHashtable() - { - return _hashtable; - } - - /// - /// Set the newly visible hashtable underlying array. Used by writers after - /// the new array is fully constructed. The volatile write is used to ensure - /// that all writes to the contents of hashtable are completed before _hashtable - /// is visible to readers. - /// - private void SetCurrentHashtable(TValue[] hashtable) - { - _hashtable = hashtable; - } - - /// - /// Used to ensure that the hashtable can function with - /// fairly poor initial hash codes. - /// - public static int HashInt1(int key) - { - unchecked - { - int a = (int)0x9e3779b9 + key; - int b = (int)0x9e3779b9; - int c = 16777619; - a -= b; a -= c; a ^= (c >> 13); - b -= c; b -= a; b ^= (a << 8); - c -= a; c -= b; c ^= (b >> 13); - a -= b; a -= c; a ^= (c >> 12); - b -= c; b -= a; b ^= (a << 16); - c -= a; c -= b; c ^= (b >> 5); - a -= b; a -= c; a ^= (c >> 3); - b -= c; b -= a; b ^= (a << 10); - c -= a; c -= b; c ^= (b >> 15); - return c; - } - } - - /// - /// Generate a somewhat independent hash value from another integer. This is used - /// as part of a double hashing scheme. By being relatively prime with powers of 2 - /// this hash function can be reliably used as part of a double hashing scheme as it - /// is guaranteed to eventually probe every slot in the table. (Table sizes are - /// constrained to be a power of two) - /// - public static int HashInt2(int key) - { - unchecked - { - int hash = unchecked((int)0xB1635D64) + key; - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - hash |= 0x00000001; // To make sure that this is relatively prime with power of 2 - return hash; - } - } - - /// - /// Create the LockFreeReaderHashtable. This hash table is designed for GetOrCreateValue - /// to be a generally lock free api (unless an add is necessary) - /// - public LockFreeReaderHashtable() - { -#if DEBUG - // Ensure the initial value is a power of 2 - bool foundAOne = false; - for (int i = 0; i < 32; i++) - { - int lastBit = _initialSize >> i; - if ((lastBit & 0x1) == 0x1) - { - Debug.Assert(!foundAOne); - foundAOne = true; - } - } -#endif // DEBUG - _newHashTable = _hashtable; - } - - /// - /// The current count of elements in the hashtable - /// - public int Count { get { return _count; } } - - /// - /// Gets the value associated with the specified key. - /// - /// The key of the value to get. - /// When this method returns, contains the value associated with - /// the specified key, if the key is found; otherwise, the default value for the type - /// of the value parameter. This parameter is passed uninitialized. This function is threadsafe, - /// and wait-free - /// true if a value was found - public bool TryGetValue(TKey key, out TValue value) - { - TValue[] hashTableLocal = GetCurrentHashtable(); - Debug.Assert(hashTableLocal.Length > 0); - int mask = hashTableLocal.Length - 1; - int hashCode = GetKeyHashCode(key); - int tableIndex = HashInt1(hashCode) & mask; - - if (hashTableLocal[tableIndex] == null) - { - value = null; - return false; - } - - if (CompareKeyToValue(key, hashTableLocal[tableIndex])) - { - value = hashTableLocal[tableIndex]; - return true; - } - - int hash2 = HashInt2(hashCode); - tableIndex = (tableIndex + hash2) & mask; - - while (hashTableLocal[tableIndex] != null) - { - if (CompareKeyToValue(key, hashTableLocal[tableIndex])) - { - value = hashTableLocal[tableIndex]; - return true; - } - tableIndex = (tableIndex + hash2) & mask; - } - value = null; - return false; - } - - /// - /// Make the underlying array of the hashtable bigger. This function - /// does not change the contents of the hashtable. This entire function locks. - /// - private void Expand(TValue[] oldHashtable) - { - lock(this) - { - // If somebody else already resized, don't try to do it based on an old table - if(oldHashtable != _hashtable) - { - return; - } - - // The checked statement here protects against both the hashTable size and _reserve overflowing. That does mean - // the maximum size of _hashTable is 0x70000000 - int newSize = checked(oldHashtable.Length * 2); - - // The hashtable only functions well when it has a certain minimum size - const int minimumUsefulSize = 16; - if (newSize < minimumUsefulSize) - newSize = minimumUsefulSize; - - // Work in a local variable to avoid lots of unnecessary volatile reads of _newHashTable since only this method can - // change it and we're under a lock - TValue[] newHashTable = new TValue[newSize]; - _newHashTable = newHashTable; - // Due to the volatile write above, any adds on other threads after this point will - // fail and be redone, thus writing to the new hash table. - - int mask = newHashTable.Length - 1; - foreach (TValue value in oldHashtable) - { - if (value == null) - continue; - - // If there's a deadlock at this point, GetValueHashCode is re-entering Add, which it must not do. - int hashCode = GetValueHashCode(value); - int tableIndex = HashInt1(hashCode) & mask; - - // Initial probe into hashtable found empty spot - if (newHashTable[tableIndex] == null) - { - // Add to hash - newHashTable[tableIndex] = value; - continue; - } - - int hash2 = HashInt2(hashCode); - tableIndex = (tableIndex + hash2) & mask; - - while (newHashTable[tableIndex] != null) - { - tableIndex = (tableIndex + hash2) & mask; - } - - // We've probed to find an empty spot - // Add to hash - newHashTable[tableIndex] = value; - } - - _resizeCount = checked((newSize * _fillPercentageBeforeResize) / 100); - SetCurrentHashtable(newHashTable); - } - } - - /// - /// Adds a value to the hashtable if it is not already present. - /// Note that the key is not specified as it is implicit in the value. This function is thread-safe, - /// but must only take locks around internal operations and GetValueHashCode. - /// - /// Value to attempt to add to the hashtable, must not be null - /// True if the value was added. False if it was already present. - public bool TryAdd(TValue value) - { - bool addedValue; - AddOrGetExistingInner(value, out addedValue); - return addedValue; - } - - /// - /// Add a value to the hashtable, or find a value which is already present in the hashtable. - /// Note that the key is not specified as it is implicit in the value. This function is thread-safe, - /// but must only take locks around internal operations and GetValueHashCode. - /// - /// Value to attempt to add to the hashtable, must not be null - /// Newly added value, or a value which was already present in the hashtable which is equal to it. - public TValue AddOrGetExisting(TValue value) - { - bool unused; - return AddOrGetExistingInner(value, out unused); - } - - private TValue AddOrGetExistingInner(TValue value, out bool addedValue) - { - if (value == null) - throw new ArgumentNullException(); - - // Optimistically check to see if adding this value may require an expansion. If so, expand - // the table now. This isn't required to ensure space for the write, but helps keep - // the ratio in a good range. - if (_count >= _resizeCount) - { - Expand(_hashtable); - } - - TValue result; - do - { - result = TryAddOrGetExisting(value, out addedValue); - } while (result == null); - return result; - } - - /// - /// Attemps to add a value to the hashtable, or find a value which is already present in the hashtable. - /// In some cases, this will fail due to contention with other additions and must be retried. - /// Note that the key is not specified as it is implicit in the value. This function is thread-safe, - /// but must only take locks around internal operations and GetValueHashCode. - /// - /// Value to attempt to add to the hashtable, must not be null - /// Set to true if was added to the table. False if the value - /// was already present. Not defined if adding was attempted but failed. - /// Newly added value if adding succeds, a value which was already present in the hashtable which is equal to it, - /// or null if adding fails and must be retried. - private TValue TryAddOrGetExisting(TValue value, out bool addedValue) - { - // The table must be captured into a local to ensure reads/writes - // don't get torn by expansions - TValue[] hashTableLocal = _hashtable; - - addedValue = true; - int mask = hashTableLocal.Length - 1; - int hashCode = GetValueHashCode(value); - int tableIndex = HashInt1(hashCode) & mask; - - // Find an empty spot, starting with the initial tableIndex - if (hashTableLocal[tableIndex] != null) - { - if (CompareValueToValue(value, hashTableLocal[tableIndex])) - { - // Value is already present in hash, do not add - addedValue = false; - return hashTableLocal[tableIndex]; - } - - int hash2 = HashInt2(hashCode); - tableIndex = (tableIndex + hash2) & mask; - - while (hashTableLocal[tableIndex] != null) - { - if (CompareValueToValue(value, hashTableLocal[tableIndex])) - { - // Value is already present in hash, do not add - addedValue = false; - return hashTableLocal[tableIndex]; - } - tableIndex = (tableIndex + hash2) & mask; - } - } - - // Ensure there's enough space for at least one null slot after this write - if (Interlocked.Increment(ref _reserve) >= hashTableLocal.Length - 1) - { - Interlocked.Decrement(ref _reserve); - Expand(hashTableLocal); - - // Since we expanded, our index won't work, restart - return null; - } - - // We've probed to find an empty spot, add to hash - if (!TryWriteValueToLocation(value, hashTableLocal, tableIndex)) - { - Interlocked.Decrement(ref _reserve); - return null; - } - - // Now that we've written to the local array, find out if that array has been - // replaced by expansion. If it has, we need to restart and write to the new array. - if (_newHashTable != hashTableLocal) - { - // Pulse the lock so we don't spin during an expansion - lock(this) { } - Interlocked.Decrement(ref _reserve); - return null; - } - - // If the write succeeded, increment _count - Interlocked.Increment(ref _count); - return value; - } - - /// - /// Attampts to write a value into the table. May fail if another value has been added. - /// - /// True if the value was successfully written - private bool TryWriteValueToLocation(TValue value, TValue[] hashTableLocal, int tableIndex) - { - // Add to hash, use a volatile write to ensure that - // the contents of the value are fully published to all - // threads before adding to the hashtable - if (Interlocked.CompareExchange(ref hashTableLocal[tableIndex], value, null) == null) - { - return true; - } - - return false; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private TValue CreateValueAndEnsureValueIsInTable(TKey key) - { - TValue newValue = CreateValueFromKey(key); - Debug.Assert(GetValueHashCode(newValue) == GetKeyHashCode(key)); - - return AddOrGetExisting(newValue); - } - - /// - /// Get the value associated with a key. If value is not present in dictionary, use the creator delegate passed in - /// at object construction time to create the value, and attempt to add it to the table. (Create the value while not - /// under the lock, but add it to the table while under the lock. This may result in a throw away object being constructed) - /// This function is thread-safe, but will take a lock to perform its operations. - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TValue GetOrCreateValue(TKey key) - { - TValue existingValue; - if (TryGetValue(key, out existingValue)) - return existingValue; - - return CreateValueAndEnsureValueIsInTable(key); - } - - /// - /// Determine if this collection contains a value associated with a key. This function is thread-safe, and wait-free. - /// - public bool Contains(TKey key) - { - TValue dummyExistingValue; - return TryGetValue(key, out dummyExistingValue); - } - - /// - /// Determine if this collection contains a given value, and returns the value in the hashtable if found. This function is thread-safe, and wait-free. - /// - /// Value to search for in the hashtable, must not be null - /// Value from the hashtable if found, otherwise null. - public TValue GetValueIfExists(TValue value) - { - if (value == null) - throw new ArgumentNullException(); - - TValue[] hashTableLocal = GetCurrentHashtable(); - Debug.Assert(hashTableLocal.Length > 0); - int mask = hashTableLocal.Length - 1; - int hashCode = GetValueHashCode(value); - int tableIndex = HashInt1(hashCode) & mask; - - if (hashTableLocal[tableIndex] == null) - return null; - - if (CompareValueToValue(value, hashTableLocal[tableIndex])) - return hashTableLocal[tableIndex]; - - int hash2 = HashInt2(hashCode); - tableIndex = (tableIndex + hash2) & mask; - - while (hashTableLocal[tableIndex] != null) - { - if (CompareValueToValue(value, hashTableLocal[tableIndex])) - return hashTableLocal[tableIndex]; - - tableIndex = (tableIndex + hash2) & mask; - } - - return null; - } - - /// - /// Enumerator type for the LockFreeReaderHashtable - /// This is threadsafe, but is not garaunteed to avoid torn state. - /// In particular, the enumerator may report some newly added values - /// but not others. All values in the hashtable as of enumerator - /// creation will always be enumerated. - /// - public struct Enumerator : IEnumerator - { - private TValue[] _hashtableContentsToEnumerate; - private int _index; - private TValue _current; - - /// - /// Use this to get an enumerable collection from a LockFreeReaderHashtable. - /// Used instead of a GetEnumerator method on the LockFreeReaderHashtable to - /// reduce excess type creation. (By moving the method here, the generic dictionary for - /// LockFreeReaderHashtable does not need to contain a reference to the - /// enumerator type. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Enumerator Get(LockFreeReaderHashtable hashtable) - { - return new Enumerator(hashtable); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() - { - return this; - } - - internal Enumerator(LockFreeReaderHashtable hashtable) - { - _hashtableContentsToEnumerate = hashtable._hashtable; - _index = 0; - _current = default(TValue); - } - - public bool MoveNext() - { - if ((_hashtableContentsToEnumerate != null) && (_index < _hashtableContentsToEnumerate.Length)) - { - for (; _index < _hashtableContentsToEnumerate.Length; _index++) - { - if (_hashtableContentsToEnumerate[_index] != null) - { - _current = _hashtableContentsToEnumerate[_index]; - _index++; - return true; - } - } - } - - _current = default(TValue); - return false; - } - - public void Dispose() - { - } - - public void Reset() - { - throw new NotSupportedException(); - } - - public TValue Current - { - get - { - return _current; - } - } - - object IEnumerator.Current - { - get - { - throw new NotSupportedException(); - } - } - } - - /// - /// Given a key, compute a hash code. This function must be thread safe. - /// - protected abstract int GetKeyHashCode(TKey key); - - /// - /// Given a value, compute a hash code which would be identical to the hash code - /// for a key which should look up this value. This function must be thread safe. - /// This function must also not cause additional hashtable adds. - /// - protected abstract int GetValueHashCode(TValue value); - - /// - /// Compare a key and value. If the key refers to this value, return true. - /// This function must be thread safe. - /// - protected abstract bool CompareKeyToValue(TKey key, TValue value); - - /// - /// Compare a value with another value. Return true if values are equal. - /// This function must be thread safe. - /// - protected abstract bool CompareValueToValue(TValue value1, TValue value2); - - /// - /// Create a new value from a key. Must be threadsafe. Value may or may not be added - /// to collection. Return value must not be null. - /// - protected abstract TValue CreateValueFromKey(TKey key); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/TypeNameFormatter.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/TypeNameFormatter.cs deleted file mode 100644 index 1f946786cb9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/TypeNameFormatter.cs +++ /dev/null @@ -1,146 +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 System.Text; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// Provides services to convert types to strings. - /// - public abstract class TypeNameFormatter - { - public void AppendName(StringBuilder sb, TypeDesc type) - { - switch (type.Category) - { - case TypeFlags.Array: - case TypeFlags.SzArray: - AppendName(sb, (ArrayType)type); - return; - case TypeFlags.ByRef: - AppendName(sb, (ByRefType)type); - return; - case TypeFlags.Pointer: - AppendName(sb, (PointerType)type); - return; - case TypeFlags.FunctionPointer: - AppendName(sb, (FunctionPointerType)type); - return; - case TypeFlags.GenericParameter: - AppendName(sb, (GenericParameterDesc)type); - return; - case TypeFlags.SignatureTypeVariable: - AppendName(sb, (SignatureTypeVariable)type); - return; - case TypeFlags.SignatureMethodVariable: - AppendName(sb, (SignatureMethodVariable)type); - return; - default: - Debug.Assert(type.IsDefType); - AppendName(sb, (DefType)type); - return; - } - } - - public void AppendName(StringBuilder sb, DefType type) - { - if (!type.IsTypeDefinition) - { - AppendNameForInstantiatedType(sb, type); - } - else - { - DefType containingType = type.ContainingType; - if (containingType != null) - AppendNameForNestedType(sb, type, containingType); - else - AppendNameForNamespaceType(sb, type); - } - } - - public abstract void AppendName(StringBuilder sb, ArrayType type); - public abstract void AppendName(StringBuilder sb, ByRefType type); - public abstract void AppendName(StringBuilder sb, PointerType type); - public abstract void AppendName(StringBuilder sb, FunctionPointerType type); - public abstract void AppendName(StringBuilder sb, GenericParameterDesc type); - public abstract void AppendName(StringBuilder sb, SignatureMethodVariable type); - public abstract void AppendName(StringBuilder sb, SignatureTypeVariable type); - - protected abstract void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType); - protected abstract void AppendNameForNamespaceType(StringBuilder sb, DefType type); - protected abstract void AppendNameForInstantiatedType(StringBuilder sb, DefType type); - - public string FormatName(TypeDesc type) - { - StringBuilder sb = new StringBuilder(); - AppendName(sb, type); - return sb.ToString(); - } - } - - public abstract class TypeNameFormatter - { - public TState AppendName(StringBuilder sb, TypeDesc type, TOptions options) - { - // Don't use Category to switch here as it may fail for some types, and the DebugNameFormatter - // which is derived from that type cannot tolerate those failures - return type switch - { - ArrayType arrayType => AppendName(sb, arrayType, options), - ByRefType byRefType => AppendName(sb, byRefType, options), - PointerType pointerType => AppendName(sb, pointerType, options), - FunctionPointerType functionPointerType => AppendName(sb, functionPointerType, options), - GenericParameterDesc genericPointerType => AppendName(sb, genericPointerType, options), - SignatureTypeVariable sigTypeVar => AppendName(sb, sigTypeVar, options), - SignatureMethodVariable sigMethodVar => AppendName(sb, sigMethodVar, options), - _ => AppendName(sb, (DefType)type, options) - }; - } - - public TState AppendName(StringBuilder sb, DefType type, TOptions options) - { - if (!type.IsTypeDefinition) - { - return AppendNameForInstantiatedType(sb, type, options); - } - else - { - DefType containingType = GetContainingType(type, options); - - if (containingType != null) - return AppendNameForNestedType(sb, type, containingType, options); - else - return AppendNameForNamespaceType(sb, type, options); - } - } - - public abstract TState AppendName(StringBuilder sb, ArrayType type, TOptions options); - public abstract TState AppendName(StringBuilder sb, ByRefType type, TOptions options); - public abstract TState AppendName(StringBuilder sb, PointerType type, TOptions options); - public abstract TState AppendName(StringBuilder sb, FunctionPointerType type, TOptions options); - public abstract TState AppendName(StringBuilder sb, GenericParameterDesc type, TOptions options); - public abstract TState AppendName(StringBuilder sb, SignatureMethodVariable type, TOptions options); - public abstract TState AppendName(StringBuilder sb, SignatureTypeVariable type, TOptions options); - - protected abstract TState AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType, TOptions options); - protected abstract TState AppendNameForNamespaceType(StringBuilder sb, DefType type, TOptions options); - protected abstract TState AppendNameForInstantiatedType(StringBuilder sb, DefType type, TOptions options); - - protected virtual DefType GetContainingType(DefType possibleInnerType, TOptions options) - { - return possibleInnerType.ContainingType; - } - - public string FormatName(TypeDesc type, TOptions options) - { - StringBuilder sb = new StringBuilder(); - AppendName(sb, type, options); - return sb.ToString(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs deleted file mode 100644 index 4f22881d4a9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs +++ /dev/null @@ -1,38 +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.Collections.Generic; - -namespace Internal.TypeSystem -{ - /// - /// Pluggable virtual method computation algorithm. Provides an abstraction to resolve - /// virtual and interface methods on types. - /// - /// - /// The algorithms are expected to be directly used by derivatives - /// only. The most obvious implementation of this algorithm that uses type's metadata to - /// compute the answers is in . - /// - public abstract class VirtualMethodAlgorithm - { - /// - /// Resolves interface method '' to a method on '' - /// that implements the the method. - /// - public abstract MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType); - - public abstract MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType); - - /// - /// Resolves a virtual method call. - /// - public abstract MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, TypeDesc objectType); - - /// - /// Enumerates all virtual slots on ''. - /// - public abstract IEnumerable ComputeAllVirtualSlots(TypeDesc type); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/WellKnownType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/WellKnownType.cs deleted file mode 100644 index 1f0e22c8411..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/WellKnownType.cs +++ /dev/null @@ -1,52 +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; - -namespace Internal.TypeSystem -{ - // The following enum is required for interop with the VS Debugger - // Prior to making any changes to this enum, please reach out to the VS Debugger - // team to make sure that your changes are not going to prevent the debugger - // from working. - public enum WellKnownType - { - Unknown, - - // Primitive types are first - keep in sync with type flags - Void, - Boolean, - Char, - SByte, - Byte, - Int16, - UInt16, - Int32, - UInt32, - Int64, - UInt64, - IntPtr, - UIntPtr, - Single, - Double, - - ValueType, - Enum, - Nullable, - - Object, - String, - Array, - MulticastDelegate, - - RuntimeTypeHandle, - RuntimeMethodHandle, - RuntimeFieldHandle, - - Exception, - - TypedReference, - ByReferenceOfT, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/CachingMetadataStringDecoder.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/CachingMetadataStringDecoder.cs deleted file mode 100644 index f965a8bce32..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/CachingMetadataStringDecoder.cs +++ /dev/null @@ -1,195 +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 System.Reflection.Metadata; -using System.Runtime.CompilerServices; -using Debug = System.Diagnostics.Debug; - -using Internal.NativeFormat; - -namespace Internal.TypeSystem.Ecma -{ - /// - /// MetadataReader string decoder that caches and reuses strings rather than allocating - /// on each call to MetadataReader.GetString(handle). - /// Safe to use from multiple threads and lock free. - /// - public sealed class CachingMetadataStringDecoder : MetadataStringDecoder - { - private struct Entry - { - // hash code of the entry - public int HashCode; - - // full text of the item - public string Text; - } - - // TODO: Tune the bucket size - private const int BucketSize = 4; - - // The table of cached entries. The size of the table has to be power of 2. - private Entry[] _table; - - // The next candidate in the bucket range for eviction - private int _evictionHint; - - public CachingMetadataStringDecoder(int size) - : base(System.Text.Encoding.UTF8) - { - Debug.Assert((size & (size - 1)) == 0, "The cache size must be power of 2"); - - _table = new Entry[size]; - } - - private string Find(int hashCode, string s) - { - var arr = _table; - int mask = _table.Length - 1; - - int idx = hashCode & mask; - - // we use quadratic probing here - // bucket positions are (n^2 + n)/2 relative to the masked hashcode - for (int i = 1; i < BucketSize + 1; i++) - { - string e = arr[idx].Text; - int hash = arr[idx].HashCode; - - if (e == null) - { - // once we see unfilled entry, the rest of the bucket will be empty - break; - } - - if (hash == hashCode && s == e) - { - return e; - } - - idx = (idx + i) & mask; - } - return null; - } - - private unsafe string FindASCII(int hashCode, byte* bytes, int byteCount) - { - var arr = _table; - int mask = _table.Length - 1; - - int idx = hashCode & mask; - - // we use quadratic probing here - // bucket positions are (n^2 + n)/2 relative to the masked hashcode - for (int i = 1; i < BucketSize + 1; i++) - { - string e = arr[idx].Text; - int hash = arr[idx].HashCode; - - if (e == null) - { - // once we see unfilled entry, the rest of the bucket will be empty - break; - } - - if (hash == hashCode && TextEqualsASCII(e, bytes, byteCount)) - { - return e; - } - - idx = (idx + i) & mask; - } - return null; - } - - private static unsafe bool TextEqualsASCII(string text, byte* ascii, int length) - { -#if DEBUG - for (var i = 0; i < length; i++) - { - Debug.Assert((ascii[i] & 0x80) == 0, "The byte* input to this method must be valid ASCII."); - } -#endif - - if (length != text.Length) - { - return false; - } - - for (var i = 0; i < length; i++) - { - if (ascii[i] != text[i]) - { - return false; - } - } - - return true; - } - - private string Add(int hashCode, string s) - { - var arr = _table; - int mask = _table.Length - 1; - - int idx = hashCode & mask; - - // try finding an empty spot in the bucket - // we use quadratic probing here - // bucket positions are (n^2 + n)/2 relative to the masked hashcode - int curIdx = idx; - for (int i = 1; i < BucketSize + 1; i++) - { - if (arr[curIdx].Text == null) - { - idx = curIdx; - goto foundIdx; - } - - curIdx = (curIdx + i) & BucketSize; - } - - // or pick a victim within the bucket range - // and replace with new entry - var i1 = _evictionHint++ & (BucketSize - 1); - idx = (idx + ((i1 * i1 + i1) / 2)) & mask; - - foundIdx: - arr[idx].HashCode = hashCode; - arr[idx].Text = s; - - return s; - } - - public string Lookup(string s) - { - int hashCode = TypeHashingAlgorithms.ComputeNameHashCode(s); - - string existing = Find(hashCode, s); - if (existing != null) - return existing; - - return Add(hashCode, s); - } - - public unsafe override string GetString(byte* bytes, int byteCount) - { - bool isAscii; - int hashCode = TypeHashingAlgorithms.ComputeASCIINameHashCode(bytes, byteCount, out isAscii); - - if (isAscii) - { - string existing = FindASCII(hashCode, bytes, byteCount); - if (existing != null) - return existing; - return Add(hashCode, Encoding.GetString(bytes, byteCount)); - } - else - { - return Lookup(Encoding.GetString(bytes, byteCount)); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/CustomAttributeTypeProvider.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/CustomAttributeTypeProvider.cs deleted file mode 100644 index 2e9d88e3d8f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/CustomAttributeTypeProvider.cs +++ /dev/null @@ -1,97 +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 System.Reflection.Metadata; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem.Ecma -{ - public struct CustomAttributeTypeProvider : ICustomAttributeTypeProvider - { - private EcmaModule _module; - - public CustomAttributeTypeProvider(EcmaModule module) - { - _module = module; - } - - public TypeDesc GetPrimitiveType(PrimitiveTypeCode typeCode) - { - return PrimitiveTypeProvider.GetPrimitiveType(_module.Context, typeCode); - } - - public TypeDesc GetSystemType() - { - MetadataType systemType = _module.Context.SystemModule.GetType("System", "Type"); - return systemType; - } - - public TypeDesc GetSZArrayType(TypeDesc elementType) - { - return elementType.MakeArrayType(); - } - - public TypeDesc GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) - { - Debug.Assert(reader == _module.MetadataReader); - return _module.GetType(handle); - } - - public TypeDesc GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) - { - Debug.Assert(reader == _module.MetadataReader); - return _module.GetType(handle); - } - - public TypeDesc GetTypeFromSpecification(MetadataReader reader, TypeSpecificationHandle handle, byte rawTypeKind) - { - Debug.Assert(reader == _module.MetadataReader); - return _module.GetType(handle); - } - - public TypeDesc GetTypeFromSerializedName(string name) - { - if (name == null) - return null; - - return _module.GetTypeByCustomAttributeTypeName(name); - } - - public PrimitiveTypeCode GetUnderlyingEnumType(TypeDesc type) - { - switch (type.UnderlyingType.Category) - { - case TypeFlags.Byte: - return PrimitiveTypeCode.Byte; - case TypeFlags.SByte: - return PrimitiveTypeCode.SByte; - case TypeFlags.UInt16: - return PrimitiveTypeCode.UInt16; - case TypeFlags.Int16: - return PrimitiveTypeCode.Int16; - case TypeFlags.UInt32: - return PrimitiveTypeCode.UInt32; - case TypeFlags.Int32: - return PrimitiveTypeCode.Int32; - case TypeFlags.UInt64: - return PrimitiveTypeCode.UInt64; - case TypeFlags.Int64: - return PrimitiveTypeCode.Int64; - default: - throw new BadImageFormatException(); - } - } - - public bool IsSystemType(TypeDesc type) - { - var metadataType = type as MetadataType; - return metadataType != null - && metadataType.Name == "Type" - && metadataType.Module == _module.Context.SystemModule - && metadataType.Namespace == "System"; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaAssembly.Symbols.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaAssembly.Symbols.cs deleted file mode 100644 index 11f66f171c3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaAssembly.Symbols.cs +++ /dev/null @@ -1,19 +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.Reflection.Metadata; -using System.Reflection.PortableExecutable; - -namespace Internal.TypeSystem.Ecma -{ - // Pluggable file that adds PDB handling functionality to EcmaAssembly - partial class EcmaAssembly - { - internal EcmaAssembly(TypeSystemContext context, PEReader peReader, MetadataReader metadataReader, PdbSymbolReader pdbReader) - : base(context, peReader, metadataReader, containingAssembly: null, pdbReader) - { - _assemblyDefinition = metadataReader.GetAssemblyDefinition(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaAssembly.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaAssembly.cs deleted file mode 100644 index e14056fdd26..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaAssembly.cs +++ /dev/null @@ -1,75 +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.Reflection; -using System.Reflection.Metadata; -using System.Reflection.PortableExecutable; - -namespace Internal.TypeSystem.Ecma -{ - public sealed partial class EcmaAssembly : EcmaModule, IAssemblyDesc - { - private AssemblyName _assemblyName; - private AssemblyDefinition _assemblyDefinition; - - public AssemblyDefinition AssemblyDefinition - { - get - { - return _assemblyDefinition; - } - } - - public override IAssemblyDesc Assembly - { - get - { - return this; - } - } - - public EcmaAssembly(TypeSystemContext context, PEReader peReader, MetadataReader metadataReader) - : base(context, peReader, metadataReader, containingAssembly: null) - { - if (!metadataReader.IsAssembly) - { - ThrowHelper.ThrowBadImageFormatException(); - } - - _assemblyDefinition = metadataReader.GetAssemblyDefinition(); - } - - // Returns cached copy of the name. Caller has to create a clone before mutating the name. - public AssemblyName GetName() - { - if (_assemblyName == null) - { - MetadataReader metadataReader = this.MetadataReader; - - AssemblyName an = new AssemblyName(); - an.Name = metadataReader.GetString(_assemblyDefinition.Name); - an.Version = _assemblyDefinition.Version; - an.SetPublicKey(metadataReader.GetBlobBytes(_assemblyDefinition.PublicKey)); - - an.CultureName = metadataReader.GetString(_assemblyDefinition.Culture); - an.ContentType = GetContentTypeFromAssemblyFlags(_assemblyDefinition.Flags); - - _assemblyName = an; - } - - return _assemblyName; - } - - public override string ToString() - { - return GetName().Name; - } - - public bool HasAssemblyCustomAttribute(string attributeNamespace, string attributeName) - { - return _metadataReader.GetCustomAttributeHandle(_assemblyDefinition.GetCustomAttributes(), - attributeNamespace, attributeName).IsNil; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.CodeGen.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.CodeGen.cs deleted file mode 100644 index a964d40111f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.CodeGen.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem.Ecma -{ - partial class EcmaField - { - public override bool IsIntrinsic - { - get - { - return (GetFieldFlags(FieldFlags.AttributeMetadataCache | FieldFlags.Intrinsic) & FieldFlags.Intrinsic) != 0; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.Serialization.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.Serialization.cs deleted file mode 100644 index 24b6da5a07d..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.Serialization.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem.Ecma -{ - partial class EcmaField - { - public override bool IsNotSerialized - { - get - { - return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.NotSerialized) & FieldFlags.NotSerialized) != 0; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.Sorting.cs deleted file mode 100644 index 79c5a28b0fc..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.Sorting.cs +++ /dev/null @@ -1,28 +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.Reflection.Metadata.Ecma335; - -namespace Internal.TypeSystem.Ecma -{ - // Functionality related to deterministic ordering of types and members - partial class EcmaField - { - protected internal override int ClassCode => 44626835; - - protected internal override int CompareToImpl(FieldDesc other, TypeSystemComparer comparer) - { - var otherField = (EcmaField)other; - - EcmaModule module = _type.EcmaModule; - EcmaModule otherModule = otherField._type.EcmaModule; - - int result = module.MetadataReader.GetToken(_handle) - otherModule.MetadataReader.GetToken(otherField._handle); - if (result != 0) - return result; - - return module.CompareTo(otherModule); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.cs deleted file mode 100644 index ee492d03de3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.cs +++ /dev/null @@ -1,299 +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 System.Diagnostics; -using System.Reflection; -using System.Reflection.Metadata; -using System.Runtime.CompilerServices; - -using Internal.TypeSystem; - -namespace Internal.TypeSystem.Ecma -{ - public sealed partial class EcmaField : FieldDesc, EcmaModule.IEntityHandleObject - { - private static class FieldFlags - { - public const int BasicMetadataCache = 0x0001; - public const int Static = 0x0002; - public const int InitOnly = 0x0004; - public const int Literal = 0x0008; - public const int HasRva = 0x0010; - public const int NotSerialized = 0x0020; - - public const int AttributeMetadataCache = 0x0100; - public const int ThreadStatic = 0x0200; - public const int Intrinsic = 0x0400; - }; - - private EcmaType _type; - private FieldDefinitionHandle _handle; - - // Cached values - private ThreadSafeFlags _fieldFlags; - private TypeDesc _fieldType; - private string _name; - - internal EcmaField(EcmaType type, FieldDefinitionHandle handle) - { - _type = type; - _handle = handle; - -#if DEBUG - // Initialize name eagerly in debug builds for convenience - InitializeName(); -#endif - } - - EntityHandle EcmaModule.IEntityHandleObject.Handle - { - get - { - return _handle; - } - } - - - public override TypeSystemContext Context - { - get - { - return _type.Module.Context; - } - } - - public override DefType OwningType - { - get - { - return _type; - } - } - - public EcmaModule Module - { - get - { - return _type.EcmaModule; - } - } - - public MetadataReader MetadataReader - { - get - { - return _type.MetadataReader; - } - } - - public FieldDefinitionHandle Handle - { - get - { - return _handle; - } - } - - private TypeDesc InitializeFieldType() - { - var metadataReader = MetadataReader; - BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetFieldDefinition(_handle).Signature); - - EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader); - var fieldType = parser.ParseFieldSignature(); - return (_fieldType = fieldType); - } - - public override TypeDesc FieldType - { - get - { - if (_fieldType == null) - return InitializeFieldType(); - return _fieldType; - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private int InitializeFieldFlags(int mask) - { - int flags = 0; - - if ((mask & FieldFlags.BasicMetadataCache) != 0) - { - var fieldAttributes = Attributes; - - if ((fieldAttributes & FieldAttributes.Static) != 0) - flags |= FieldFlags.Static; - - if ((fieldAttributes & FieldAttributes.InitOnly) != 0) - flags |= FieldFlags.InitOnly; - - if ((fieldAttributes & FieldAttributes.Literal) != 0) - flags |= FieldFlags.Literal; - - if ((fieldAttributes & FieldAttributes.HasFieldRVA) != 0) - flags |= FieldFlags.HasRva; - - if ((fieldAttributes & FieldAttributes.NotSerialized) != 0) - flags |= FieldFlags.NotSerialized; - - flags |= FieldFlags.BasicMetadataCache; - } - - // Fetching custom attribute based properties is more expensive, so keep that under - // a separate cache that might not be accessed very frequently. - if ((mask & FieldFlags.AttributeMetadataCache) != 0) - { - var metadataReader = this.MetadataReader; - var fieldDefinition = metadataReader.GetFieldDefinition(_handle); - - foreach (var attributeHandle in fieldDefinition.GetCustomAttributes()) - { - StringHandle namespaceHandle, nameHandle; - if (!metadataReader.GetAttributeNamespaceAndName(attributeHandle, out namespaceHandle, out nameHandle)) - continue; - - if (metadataReader.StringComparer.Equals(nameHandle, "ThreadStaticAttribute") - && metadataReader.StringComparer.Equals(namespaceHandle, "System")) - { - flags |= FieldFlags.ThreadStatic; - } - else if (metadataReader.StringComparer.Equals(nameHandle, "IntrinsicAttribute") - && metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices")) - { - flags |= FieldFlags.Intrinsic; - } - } - - flags |= FieldFlags.AttributeMetadataCache; - } - - Debug.Assert((flags & mask) != 0); - - _fieldFlags.AddFlags(flags); - - Debug.Assert((flags & mask) != 0); - return flags & mask; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetFieldFlags(int mask) - { - int flags = _fieldFlags.Value & mask; - if (flags != 0) - return flags; - return InitializeFieldFlags(mask); - } - - public override bool IsStatic - { - get - { - return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.Static) & FieldFlags.Static) != 0; - } - } - - public override bool IsThreadStatic - { - get - { - return IsStatic && - (GetFieldFlags(FieldFlags.AttributeMetadataCache | FieldFlags.ThreadStatic) & FieldFlags.ThreadStatic) != 0; - } - } - - public override bool IsInitOnly - { - get - { - return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.InitOnly) & FieldFlags.InitOnly) != 0; - } - } - - public override bool HasRva - { - get - { - return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.HasRva) & FieldFlags.HasRva) != 0; - } - } - - public override bool IsLiteral - { - get - { - return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.Literal) & FieldFlags.Literal) != 0; - } - } - - public FieldAttributes Attributes - { - get - { - return MetadataReader.GetFieldDefinition(_handle).Attributes; - } - } - - private string InitializeName() - { - var metadataReader = MetadataReader; - var name = metadataReader.GetString(metadataReader.GetFieldDefinition(_handle).Name); - return (_name = name); - } - - public override string Name - { - get - { - if (_name == null) - return InitializeName(); - return _name; - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return !MetadataReader.GetCustomAttributeHandle(MetadataReader.GetFieldDefinition(_handle).GetCustomAttributes(), - attributeNamespace, attributeName).IsNil; - } - - public override MarshalAsDescriptor GetMarshalAsDescriptor() - { - MetadataReader reader = MetadataReader; - FieldDefinition definition = reader.GetFieldDefinition(_handle); - if ((definition.Attributes & FieldAttributes.HasFieldMarshal) != 0) - { - BlobReader marshalAsReader = reader.GetBlobReader(definition.GetMarshallingDescriptor()); - EcmaSignatureParser parser = new EcmaSignatureParser(_type.EcmaModule, marshalAsReader); - return parser.ParseMarshalAsDescriptor(); - } - - return null; - } - } - - public static class EcmaFieldExtensions - { - /// - /// Retrieves the data associated with an RVA mapped field from the PE module. - /// - public static byte[] GetFieldRvaData(this EcmaField field) - { - Debug.Assert(field.HasRva); - int addr = field.MetadataReader.GetFieldDefinition(field.Handle).GetRelativeVirtualAddress(); - var memBlock = field.Module.PEReader.GetSectionData(addr).GetContent(); - - int size = field.FieldType.GetElementSize().AsInt; - if (size > memBlock.Length) - throw new BadImageFormatException(); - - byte[] result = new byte[size]; - memBlock.CopyTo(0, result, 0, result.Length); - - return result; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs deleted file mode 100644 index 2def7d24cf5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs +++ /dev/null @@ -1,26 +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.Reflection.Metadata.Ecma335; - -namespace Internal.TypeSystem.Ecma -{ - public sealed partial class EcmaGenericParameter - { - public override string DiagnosticName - { - get - { - try - { - return Name; - } - catch - { - return $"GenericParam({MetadataReader.GetToken(Handle):x8})"; - } - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Sorting.cs deleted file mode 100644 index b1c4bbce6e0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Sorting.cs +++ /dev/null @@ -1,24 +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.Reflection.Metadata.Ecma335; - -namespace Internal.TypeSystem.Ecma -{ - // Functionality related to determinstic ordering of types - partial class EcmaGenericParameter - { - protected internal override int ClassCode => -1548417824; - - protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - var otherType = (EcmaGenericParameter)other; - int result = _module.MetadataReader.GetToken(_handle) - otherType._module.MetadataReader.GetToken(otherType._handle); - if (result != 0) - return result; - - return _module.CompareTo(otherType._module); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.cs deleted file mode 100644 index 28a43f0424c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.cs +++ /dev/null @@ -1,137 +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 System.Collections.Generic; -using System.Reflection.Metadata; -using Internal.NativeFormat; - -using Debug = System.Diagnostics.Debug; -using GenericParameterAttributes = System.Reflection.GenericParameterAttributes; - -namespace Internal.TypeSystem.Ecma -{ - public sealed partial class EcmaGenericParameter : GenericParameterDesc - { - private EcmaModule _module; - private GenericParameterHandle _handle; - - internal EcmaGenericParameter(EcmaModule module, GenericParameterHandle handle) - { - _module = module; - _handle = handle; - } - - public GenericParameterHandle Handle - { - get - { - return _handle; - } - } - - public MetadataReader MetadataReader - { - get - { - return _module.MetadataReader; - } - } - - public EcmaModule Module - { - get - { - return _module; - } - } - - public override TypeSystemContext Context - { - get - { - return _module.Context; - } - } - - public override string Name - { - get - { - MetadataReader reader = _module.MetadataReader; - return reader.GetString(reader.GetGenericParameter(_handle).Name); - } - } - - public override GenericParameterKind Kind - { - get - { - GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle); - if (parameter.Parent.Kind == HandleKind.MethodDefinition) - { - return GenericParameterKind.Method; - } - else - { - Debug.Assert(parameter.Parent.Kind == HandleKind.TypeDefinition); - return GenericParameterKind.Type; - } - } - } - - public override int Index - { - get - { - GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle); - return parameter.Index; - } - } - - public override GenericVariance Variance - { - get - { - Debug.Assert((int)GenericVariance.Contravariant == (int)GenericParameterAttributes.Contravariant); - GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle); - return (GenericVariance)(parameter.Attributes & GenericParameterAttributes.VarianceMask); - } - } - - public override GenericConstraints Constraints - { - get - { - Debug.Assert((int)GenericConstraints.DefaultConstructorConstraint == (int)GenericParameterAttributes.DefaultConstructorConstraint); - GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle); - return (GenericConstraints)(parameter.Attributes & GenericParameterAttributes.SpecialConstraintMask); - } - } - - public override IEnumerable TypeConstraints - { - get - { - MetadataReader reader = _module.MetadataReader; - - GenericParameter parameter = reader.GetGenericParameter(_handle); - GenericParameterConstraintHandleCollection constraintHandles = parameter.GetConstraints(); - - if (constraintHandles.Count == 0) - return TypeDesc.EmptyTypes; - - TypeDesc[] constraintTypes = new TypeDesc[constraintHandles.Count]; - - for (int i = 0; i < constraintTypes.Length; i++) - { - GenericParameterConstraint constraint = reader.GetGenericParameterConstraint(constraintHandles[i]); - constraintTypes[i] = _module.GetType(constraint.Type); - }; - - return constraintTypes; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs deleted file mode 100644 index 88ff3ca78c3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs +++ /dev/null @@ -1,26 +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.Reflection.Metadata.Ecma335; - -namespace Internal.TypeSystem.Ecma -{ - public sealed partial class EcmaMethod - { - public override string DiagnosticName - { - get - { - try - { - return Name; - } - catch - { - return $"MethodDef({MetadataReader.GetToken(Handle):x8})"; - } - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs deleted file mode 100644 index b9cfbda2859..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs +++ /dev/null @@ -1,28 +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.Reflection.Metadata.Ecma335; - -namespace Internal.TypeSystem.Ecma -{ - // Functionality related to deterministic ordering of types - partial class EcmaMethod - { - protected internal override int ClassCode => 1419431046; - - protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) - { - var otherMethod = (EcmaMethod)other; - - EcmaModule module = _type.EcmaModule; - EcmaModule otherModule = otherMethod._type.EcmaModule; - - int result = module.MetadataReader.GetToken(_handle) - otherModule.MetadataReader.GetToken(otherMethod._handle); - if (result != 0) - return result; - - return module.CompareTo(otherModule); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.cs deleted file mode 100644 index 6d1aa8a59bc..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.cs +++ /dev/null @@ -1,585 +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.Diagnostics; -using System.Runtime.CompilerServices; -using System.Reflection; -using System.Reflection.Metadata; -using System.Threading; - -namespace Internal.TypeSystem.Ecma -{ - public sealed partial class EcmaMethod : MethodDesc, EcmaModule.IEntityHandleObject - { - private static class MethodFlags - { - public const int BasicMetadataCache = 0x00001; - public const int Virtual = 0x00002; - public const int NewSlot = 0x00004; - public const int Abstract = 0x00008; - public const int Final = 0x00010; - public const int NoInlining = 0x00020; - public const int AggressiveInlining = 0x00040; - public const int RuntimeImplemented = 0x00080; - public const int InternalCall = 0x00100; - public const int Synchronized = 0x00200; - public const int AggressiveOptimization = 0x00400; - public const int NoOptimization = 0x00800; - public const int RequireSecObject = 0x01000; - - public const int AttributeMetadataCache = 0x02000; - public const int Intrinsic = 0x04000; - public const int NativeCallable = 0x08000; - public const int RuntimeExport = 0x10000; - }; - - private EcmaType _type; - private MethodDefinitionHandle _handle; - - // Cached values - private ThreadSafeFlags _methodFlags; - private MethodSignature _signature; - private string _name; - private TypeDesc[] _genericParameters; // TODO: Optional field? - - internal EcmaMethod(EcmaType type, MethodDefinitionHandle handle) - { - _type = type; - _handle = handle; - -#if DEBUG - // Initialize name eagerly in debug builds for convenience - InitializeName(); -#endif - } - - EntityHandle EcmaModule.IEntityHandleObject.Handle - { - get - { - return _handle; - } - } - - public override TypeSystemContext Context - { - get - { - return _type.Module.Context; - } - } - - public override TypeDesc OwningType - { - get - { - return _type; - } - } - - private MethodSignature InitializeSignature() - { - var metadataReader = MetadataReader; - BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetMethodDefinition(_handle).Signature); - - EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader); - var signature = parser.ParseMethodSignature(); - return (_signature = signature); - } - - public override MethodSignature Signature - { - get - { - if (_signature == null) - return InitializeSignature(); - return _signature; - } - } - - public EcmaModule Module - { - get - { - return _type.EcmaModule; - } - } - - public MetadataReader MetadataReader - { - get - { - return _type.MetadataReader; - } - } - - public MethodDefinitionHandle Handle - { - get - { - return _handle; - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private int InitializeMethodFlags(int mask) - { - int flags = 0; - - if ((mask & MethodFlags.BasicMetadataCache) != 0) - { - var methodAttributes = Attributes; - var methodImplAttributes = ImplAttributes; - - if ((methodAttributes & MethodAttributes.Virtual) != 0) - flags |= MethodFlags.Virtual; - - if ((methodAttributes & MethodAttributes.NewSlot) != 0) - flags |= MethodFlags.NewSlot; - - if ((methodAttributes & MethodAttributes.Abstract) != 0) - flags |= MethodFlags.Abstract; - - if ((methodAttributes & MethodAttributes.Final) != 0) - flags |= MethodFlags.Final; - - if ((methodAttributes & MethodAttributes.RequireSecObject) != 0) - flags |= MethodFlags.RequireSecObject; - - if ((methodImplAttributes & MethodImplAttributes.NoInlining) != 0) - flags |= MethodFlags.NoInlining; - - // System.Reflection.Primitives we build against doesn't define AggressiveOptimization - const MethodImplAttributes MethodImplAttributes_AggressiveOptimization = (MethodImplAttributes)0x0200; - - // No optimization bit beats aggressive optimization bit (CLR compatible behavior) - if ((methodImplAttributes & MethodImplAttributes.NoOptimization) != 0) - flags |= MethodFlags.NoOptimization; - else if ((methodImplAttributes & MethodImplAttributes_AggressiveOptimization) != 0) - flags |= MethodFlags.AggressiveOptimization; - - if ((methodImplAttributes & MethodImplAttributes.AggressiveInlining) != 0) - flags |= MethodFlags.AggressiveInlining; - - if ((methodImplAttributes & MethodImplAttributes.Runtime) != 0) - flags |= MethodFlags.RuntimeImplemented; - - if ((methodImplAttributes & MethodImplAttributes.InternalCall) != 0) - flags |= MethodFlags.InternalCall; - - if ((methodImplAttributes & MethodImplAttributes.Synchronized) != 0) - flags |= MethodFlags.Synchronized; - - flags |= MethodFlags.BasicMetadataCache; - } - - // Fetching custom attribute based properties is more expensive, so keep that under - // a separate cache that might not be accessed very frequently. - if ((mask & MethodFlags.AttributeMetadataCache) != 0) - { - var metadataReader = this.MetadataReader; - var methodDefinition = metadataReader.GetMethodDefinition(_handle); - - foreach (var attributeHandle in methodDefinition.GetCustomAttributes()) - { - StringHandle namespaceHandle, nameHandle; - if (!metadataReader.GetAttributeNamespaceAndName(attributeHandle, out namespaceHandle, out nameHandle)) - continue; - - if (metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices")) - { - if (metadataReader.StringComparer.Equals(nameHandle, "IntrinsicAttribute")) - { - flags |= MethodFlags.Intrinsic; - } - } - else - if (metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime.InteropServices")) - { - if (metadataReader.StringComparer.Equals(nameHandle, "NativeCallableAttribute")) - { - flags |= MethodFlags.NativeCallable; - } - } - else - if (metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime")) - { - if (metadataReader.StringComparer.Equals(nameHandle, "RuntimeExportAttribute")) - { - flags |= MethodFlags.RuntimeExport; - } - } - } - - flags |= MethodFlags.AttributeMetadataCache; - } - - Debug.Assert((flags & mask) != 0); - _methodFlags.AddFlags(flags); - - return flags & mask; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetMethodFlags(int mask) - { - int flags = _methodFlags.Value & mask; - if (flags != 0) - return flags; - return InitializeMethodFlags(mask); - } - - public override bool IsVirtual - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Virtual) & MethodFlags.Virtual) != 0; - } - } - - public override bool IsNewSlot - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NewSlot) & MethodFlags.NewSlot) != 0; - } - } - - public override bool IsAbstract - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Abstract) & MethodFlags.Abstract) != 0; - } - } - - public override bool IsFinal - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Final) & MethodFlags.Final) != 0; - } - } - - public override bool IsNoInlining - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NoInlining) & MethodFlags.NoInlining) != 0; - } - } - - public override bool RequireSecObject - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.RequireSecObject) & MethodFlags.RequireSecObject) != 0; - } - } - - public override bool IsAggressiveOptimization - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.AggressiveOptimization) & MethodFlags.AggressiveOptimization) != 0; - } - } - - public override bool IsNoOptimization - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NoOptimization) & MethodFlags.NoOptimization) != 0; - } - } - - public override bool IsAggressiveInlining - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.AggressiveInlining) & MethodFlags.AggressiveInlining) != 0; - } - } - - public override bool IsRuntimeImplemented - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.RuntimeImplemented) & MethodFlags.RuntimeImplemented) != 0; - } - } - - public override bool IsIntrinsic - { - get - { - return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.Intrinsic) & MethodFlags.Intrinsic) != 0; - } - } - - public override bool IsInternalCall - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.InternalCall) & MethodFlags.InternalCall) != 0; - } - } - - public override bool IsSynchronized - { - get - { - return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Synchronized) & MethodFlags.Synchronized) != 0; - } - } - - public override bool IsNativeCallable - { - get - { - return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.NativeCallable) & MethodFlags.NativeCallable) != 0; - } - } - - public override bool IsRuntimeExport - { - get - { - return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.RuntimeExport) & MethodFlags.RuntimeExport) != 0; - } - } - - public override bool IsSpecialName - { - get - { - return (Attributes & MethodAttributes.SpecialName) != 0; - } - } - - public override bool IsDefaultConstructor - { - get - { - MethodAttributes attributes = Attributes; - return attributes.IsRuntimeSpecialName() - && attributes.IsPublic() - && Signature.Length == 0 - && Name == ".ctor" - && !_type.IsAbstract; - } - } - - public MethodAttributes Attributes - { - get - { - return MetadataReader.GetMethodDefinition(_handle).Attributes; - } - } - - public MethodImplAttributes ImplAttributes - { - get - { - return MetadataReader.GetMethodDefinition(_handle).ImplAttributes; - } - } - - private string InitializeName() - { - var metadataReader = MetadataReader; - var name = metadataReader.GetString(metadataReader.GetMethodDefinition(_handle).Name); - return (_name = name); - } - - public override string Name - { - get - { - if (_name == null) - return InitializeName(); - return _name; - } - } - - private void ComputeGenericParameters() - { - var genericParameterHandles = MetadataReader.GetMethodDefinition(_handle).GetGenericParameters(); - int count = genericParameterHandles.Count; - if (count > 0) - { - TypeDesc[] genericParameters = new TypeDesc[count]; - int i = 0; - foreach (var genericParameterHandle in genericParameterHandles) - { - genericParameters[i++] = new EcmaGenericParameter(Module, genericParameterHandle); - } - Interlocked.CompareExchange(ref _genericParameters, genericParameters, null); - } - else - { - _genericParameters = TypeDesc.EmptyTypes; - } - } - - public override Instantiation Instantiation - { - get - { - if (_genericParameters == null) - ComputeGenericParameters(); - return new Instantiation(_genericParameters); - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return !MetadataReader.GetCustomAttributeHandle(MetadataReader.GetMethodDefinition(_handle).GetCustomAttributes(), - attributeNamespace, attributeName).IsNil; - } - - public override bool IsPInvoke - { - get - { - return (((int)Attributes & (int)MethodAttributes.PinvokeImpl) != 0); - } - } - - public override PInvokeMetadata GetPInvokeMethodMetadata() - { - if (!IsPInvoke) - return default(PInvokeMetadata); - - MetadataReader metadataReader = MetadataReader; - MethodDefinition methodDef = metadataReader.GetMethodDefinition(_handle); - MethodImport import = methodDef.GetImport(); - string name = metadataReader.GetString(import.Name); - - ModuleReference moduleRef = metadataReader.GetModuleReference(import.Module); - string moduleName = metadataReader.GetString(moduleRef.Name); - - MethodImportAttributes importAttributes = import.Attributes; - - // If either BestFitMapping or ThrowOnUnmappable wasn't set on the p/invoke, - // look for the value in the owning type or assembly. - if ((importAttributes & MethodImportAttributes.BestFitMappingMask) == 0 || - (importAttributes & MethodImportAttributes.ThrowOnUnmappableCharMask) == 0) - { - TypeDefinition declaringType = metadataReader.GetTypeDefinition(methodDef.GetDeclaringType()); - - // Start with owning type - MethodImportAttributes fromCA = GetImportAttributesFromBestFitMappingAttribute(declaringType.GetCustomAttributes()); - if ((importAttributes & MethodImportAttributes.BestFitMappingMask) == 0) - importAttributes |= fromCA & MethodImportAttributes.BestFitMappingMask; - if ((importAttributes & MethodImportAttributes.ThrowOnUnmappableCharMask) == 0) - importAttributes |= fromCA & MethodImportAttributes.ThrowOnUnmappableCharMask; - - // If we still don't know, check the assembly - if ((importAttributes & MethodImportAttributes.BestFitMappingMask) == 0 || - (importAttributes & MethodImportAttributes.ThrowOnUnmappableCharMask) == 0) - { - fromCA = GetImportAttributesFromBestFitMappingAttribute(metadataReader.GetAssemblyDefinition().GetCustomAttributes()); - if ((importAttributes & MethodImportAttributes.BestFitMappingMask) == 0) - importAttributes |= fromCA & MethodImportAttributes.BestFitMappingMask; - if ((importAttributes & MethodImportAttributes.ThrowOnUnmappableCharMask) == 0) - importAttributes |= fromCA & MethodImportAttributes.ThrowOnUnmappableCharMask; - } - } - - // Spot check the enums match - Debug.Assert((int)MethodImportAttributes.CallingConventionStdCall == (int)PInvokeAttributes.CallingConventionStdCall); - Debug.Assert((int)MethodImportAttributes.CharSetAuto == (int)PInvokeAttributes.CharSetAuto); - Debug.Assert((int)MethodImportAttributes.CharSetUnicode == (int)PInvokeAttributes.CharSetUnicode); - Debug.Assert((int)MethodImportAttributes.SetLastError == (int)PInvokeAttributes.SetLastError); - - PInvokeAttributes attributes = (PInvokeAttributes)importAttributes; - - if ((ImplAttributes & MethodImplAttributes.PreserveSig) != 0) - attributes |= PInvokeAttributes.PreserveSig; - - return new PInvokeMetadata(moduleName, name, attributes); - } - - private MethodImportAttributes GetImportAttributesFromBestFitMappingAttribute(CustomAttributeHandleCollection attributeHandles) - { - // Look for the [BestFitMapping(BestFitMapping: x, ThrowOnUnmappableChar = y)] attribute and - // translate that to MethodImportAttributes - - MethodImportAttributes result = 0; - MetadataReader reader = MetadataReader; - - CustomAttributeHandle attributeHandle = reader.GetCustomAttributeHandle( - attributeHandles, "System.Runtime.InteropServices", "BestFitMappingAttribute"); - if (!attributeHandle.IsNil) - { - CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); - CustomAttributeValue decoded = attribute.DecodeValue( - new CustomAttributeTypeProvider(_type.EcmaModule)); - - if (decoded.FixedArguments.Length != 1 || !(decoded.FixedArguments[0].Value is bool)) - ThrowHelper.ThrowBadImageFormatException(); - if ((bool)decoded.FixedArguments[0].Value) - result |= MethodImportAttributes.BestFitMappingEnable; - else - result |= MethodImportAttributes.BestFitMappingDisable; - - foreach (CustomAttributeNamedArgument namedArg in decoded.NamedArguments) - { - if (namedArg.Name == "ThrowOnUnmappableChar") - { - if (!(namedArg.Value is bool)) - ThrowHelper.ThrowBadImageFormatException(); - if ((bool)namedArg.Value) - result |= MethodImportAttributes.ThrowOnUnmappableCharEnable; - else - result |= MethodImportAttributes.ThrowOnUnmappableCharDisable; - break; - } - } - } - - return result; - } - - public override ParameterMetadata[] GetParameterMetadata() - { - MetadataReader metadataReader = MetadataReader; - - // Spot check the enums match - Debug.Assert((int)ParameterAttributes.In == (int)ParameterMetadataAttributes.In); - Debug.Assert((int)ParameterAttributes.Out == (int)ParameterMetadataAttributes.Out); - Debug.Assert((int)ParameterAttributes.Optional == (int)ParameterMetadataAttributes.Optional); - Debug.Assert((int)ParameterAttributes.HasDefault == (int)ParameterMetadataAttributes.HasDefault); - Debug.Assert((int)ParameterAttributes.HasFieldMarshal == (int)ParameterMetadataAttributes.HasFieldMarshal); - - ParameterHandleCollection parameterHandles = metadataReader.GetMethodDefinition(_handle).GetParameters(); - ParameterMetadata[] parameterMetadataArray = new ParameterMetadata[parameterHandles.Count]; - int index = 0; - foreach (ParameterHandle parameterHandle in parameterHandles) - { - Parameter parameter = metadataReader.GetParameter(parameterHandle); - MarshalAsDescriptor marshalAsDescriptor = GetMarshalAsDescriptor(parameter); - ParameterMetadata data = new ParameterMetadata(parameter.SequenceNumber, (ParameterMetadataAttributes)parameter.Attributes, marshalAsDescriptor); - parameterMetadataArray[index++] = data; - } - return parameterMetadataArray; - } - - private MarshalAsDescriptor GetMarshalAsDescriptor(Parameter parameter) - { - if ((parameter.Attributes & ParameterAttributes.HasFieldMarshal) == ParameterAttributes.HasFieldMarshal) - { - MetadataReader metadataReader = MetadataReader; - BlobReader marshalAsReader = metadataReader.GetBlobReader(parameter.GetMarshallingDescriptor()); - EcmaSignatureParser parser = new EcmaSignatureParser(Module, marshalAsReader); - MarshalAsDescriptor marshalAs = parser.ParseMarshalAsDescriptor(); - Debug.Assert(marshalAs != null); - return marshalAs; - } - return null; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.Sorting.cs deleted file mode 100644 index 3549c767ffa..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.Sorting.cs +++ /dev/null @@ -1,25 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem.Ecma -{ - partial class EcmaModule - { - public int CompareTo(EcmaModule other) - { - if (this == other) - return 0; - - Guid thisMvid = _metadataReader.GetGuid(_metadataReader.GetModuleDefinition().Mvid); - Guid otherMvid = other._metadataReader.GetGuid(other.MetadataReader.GetModuleDefinition().Mvid); - - Debug.Assert(thisMvid.CompareTo(otherMvid) != 0, "Different instance of EcmaModule but same MVID?"); - return thisMvid.CompareTo(otherMvid); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.Symbols.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.Symbols.cs deleted file mode 100644 index 5b6d3b732f1..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.Symbols.cs +++ /dev/null @@ -1,34 +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.Reflection.Metadata; -using System.Reflection.PortableExecutable; - -namespace Internal.TypeSystem.Ecma -{ - // Pluggable file that adds PDB handling functionality to EcmaModule - partial class EcmaModule - { - public PdbSymbolReader PdbReader - { - get; - } - - internal EcmaModule(TypeSystemContext context, PEReader peReader, MetadataReader metadataReader, IAssemblyDesc containingAssembly, PdbSymbolReader pdbReader) - : this(context, peReader, metadataReader, containingAssembly) - { - PdbReader = pdbReader; - } - - public static EcmaModule Create(TypeSystemContext context, PEReader peReader, IAssemblyDesc containingAssembly, PdbSymbolReader pdbReader) - { - MetadataReader metadataReader = CreateMetadataReader(context, peReader); - - if (containingAssembly == null) - return new EcmaAssembly(context, peReader, metadataReader, pdbReader); - else - return new EcmaModule(context, peReader, metadataReader, containingAssembly, pdbReader); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.cs deleted file mode 100644 index 9f9705c7e2c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaModule.cs +++ /dev/null @@ -1,553 +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 System.Collections.Generic; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; - -namespace Internal.TypeSystem.Ecma -{ - public partial class EcmaModule : ModuleDesc - { - private PEReader _peReader; - protected MetadataReader _metadataReader; - - internal interface IEntityHandleObject - { - EntityHandle Handle - { - get; - } - } - - private sealed class EcmaObjectLookupWrapper : IEntityHandleObject - { - private EntityHandle _handle; - private object _obj; - - public EcmaObjectLookupWrapper(EntityHandle handle, object obj) - { - _obj = obj; - _handle = handle; - } - - public EntityHandle Handle - { - get - { - return _handle; - } - } - - public object Object - { - get - { - return _obj; - } - } - } - - internal class EcmaObjectLookupHashtable : LockFreeReaderHashtable - { - private EcmaModule _module; - - public EcmaObjectLookupHashtable(EcmaModule module) - { - _module = module; - } - - protected override int GetKeyHashCode(EntityHandle key) - { - return key.GetHashCode(); - } - - protected override int GetValueHashCode(IEntityHandleObject value) - { - return value.Handle.GetHashCode(); - } - - protected override bool CompareKeyToValue(EntityHandle key, IEntityHandleObject value) - { - return key.Equals(value.Handle); - } - - protected override bool CompareValueToValue(IEntityHandleObject value1, IEntityHandleObject value2) - { - if (Object.ReferenceEquals(value1, value2)) - return true; - else - return value1.Handle.Equals(value2.Handle); - } - - protected override IEntityHandleObject CreateValueFromKey(EntityHandle handle) - { - object item; - switch (handle.Kind) - { - case HandleKind.TypeDefinition: - item = new EcmaType(_module, (TypeDefinitionHandle)handle); - break; - - case HandleKind.MethodDefinition: - { - MethodDefinitionHandle methodDefinitionHandle = (MethodDefinitionHandle)handle; - TypeDefinitionHandle typeDefinitionHandle = _module._metadataReader.GetMethodDefinition(methodDefinitionHandle).GetDeclaringType(); - EcmaType type = (EcmaType)_module.GetObject(typeDefinitionHandle); - item = new EcmaMethod(type, methodDefinitionHandle); - } - break; - - case HandleKind.FieldDefinition: - { - FieldDefinitionHandle fieldDefinitionHandle = (FieldDefinitionHandle)handle; - TypeDefinitionHandle typeDefinitionHandle = _module._metadataReader.GetFieldDefinition(fieldDefinitionHandle).GetDeclaringType(); - EcmaType type = (EcmaType)_module.GetObject(typeDefinitionHandle); - item = new EcmaField(type, fieldDefinitionHandle); - } - break; - - case HandleKind.TypeReference: - item = _module.ResolveTypeReference((TypeReferenceHandle)handle); - break; - - case HandleKind.MemberReference: - item = _module.ResolveMemberReference((MemberReferenceHandle)handle); - break; - - case HandleKind.AssemblyReference: - item = _module.ResolveAssemblyReference((AssemblyReferenceHandle)handle); - break; - - case HandleKind.TypeSpecification: - item = _module.ResolveTypeSpecification((TypeSpecificationHandle)handle); - break; - - case HandleKind.MethodSpecification: - item = _module.ResolveMethodSpecification((MethodSpecificationHandle)handle); - break; - - case HandleKind.ExportedType: - item = _module.ResolveExportedType((ExportedTypeHandle)handle); - break; - - case HandleKind.StandaloneSignature: - item = _module.ResolveStandaloneSignature((StandaloneSignatureHandle)handle); - break; - - case HandleKind.ModuleDefinition: - // ECMA-335 Partition 2 II.22.38 1d: This should not occur in a CLI ("compressed metadata") module, - // but resolves to "current module". - item = _module; - break; - - case HandleKind.ModuleReference: - item = _module.ResolveModuleReference((ModuleReferenceHandle)handle); - break; - - default: - throw new BadImageFormatException("Unknown metadata token type: " + handle.Kind); - } - - switch (handle.Kind) - { - case HandleKind.TypeDefinition: - case HandleKind.MethodDefinition: - case HandleKind.FieldDefinition: - // type/method/field definitions directly correspond to their target item. - return (IEntityHandleObject)item; - default: - // Everything else is some form of reference which cannot be self-describing - return new EcmaObjectLookupWrapper(handle, item); - } - } - } - - private object ResolveModuleReference(ModuleReferenceHandle handle) - { - ModuleReference moduleReference = _metadataReader.GetModuleReference(handle); - string fileName = _metadataReader.GetString(moduleReference.Name); - return Context.ResolveModule(this.Assembly, fileName); - } - - private LockFreeReaderHashtable _resolvedTokens; - - internal EcmaModule(TypeSystemContext context, PEReader peReader, MetadataReader metadataReader, IAssemblyDesc containingAssembly) - : base(context, containingAssembly) - { - _peReader = peReader; - _metadataReader = metadataReader; - _resolvedTokens = new EcmaObjectLookupHashtable(this); - } - - public static EcmaModule Create(TypeSystemContext context, PEReader peReader, IAssemblyDesc containingAssembly) - { - MetadataReader metadataReader = CreateMetadataReader(context, peReader); - - if (containingAssembly == null) - return new EcmaAssembly(context, peReader, metadataReader); - else - return new EcmaModule(context, peReader, metadataReader, containingAssembly); - } - - private static MetadataReader CreateMetadataReader(TypeSystemContext context, PEReader peReader) - { - if (!peReader.HasMetadata) - { - ThrowHelper.ThrowBadImageFormatException(); - } - - var stringDecoderProvider = context as IMetadataStringDecoderProvider; - - MetadataReader metadataReader = peReader.GetMetadataReader(MetadataReaderOptions.None /* MetadataReaderOptions.ApplyWindowsRuntimeProjections */, - (stringDecoderProvider != null) ? stringDecoderProvider.GetMetadataStringDecoder() : null); - - return metadataReader; - } - - public PEReader PEReader - { - get - { - return _peReader; - } - } - - public MetadataReader MetadataReader - { - get - { - return _metadataReader; - } - } - - /// - /// Gets the managed entrypoint method of this module or null if the module has no managed entrypoint. - /// - public MethodDesc EntryPoint - { - get - { - CorHeader corHeader = _peReader.PEHeaders.CorHeader; - if ((corHeader.Flags & CorFlags.NativeEntryPoint) != 0) - { - // Entrypoint is an RVA to an unmanaged method - return null; - } - - int entryPointToken = corHeader.EntryPointTokenOrRelativeVirtualAddress; - if (entryPointToken == 0) - { - // No entrypoint - return null; - } - - EntityHandle handle = MetadataTokens.EntityHandle(entryPointToken); - - if (handle.Kind == HandleKind.MethodDefinition) - { - return GetMethod(handle); - } - else if (handle.Kind == HandleKind.AssemblyFile) - { - // Entrypoint not in the manifest assembly - throw new NotImplementedException(); - } - - // Bad metadata - throw new BadImageFormatException(); - } - } - - public sealed override MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true) - { - var stringComparer = _metadataReader.StringComparer; - - // TODO: More efficient implementation? - foreach (var typeDefinitionHandle in _metadataReader.TypeDefinitions) - { - var typeDefinition = _metadataReader.GetTypeDefinition(typeDefinitionHandle); - if (stringComparer.Equals(typeDefinition.Name, name) && - stringComparer.Equals(typeDefinition.Namespace, nameSpace)) - { - return (MetadataType)GetType((EntityHandle)typeDefinitionHandle); - } - } - - foreach (var exportedTypeHandle in _metadataReader.ExportedTypes) - { - var exportedType = _metadataReader.GetExportedType(exportedTypeHandle); - if (stringComparer.Equals(exportedType.Name, name) && - stringComparer.Equals(exportedType.Namespace, nameSpace)) - { - if (exportedType.IsForwarder) - { - Object implementation = GetObject(exportedType.Implementation); - - if (implementation is ModuleDesc) - { - return ((ModuleDesc)(implementation)).GetType(nameSpace, name); - } - - // TODO - throw new NotImplementedException(); - } - // TODO: - throw new NotImplementedException(); - } - } - - if (throwIfNotFound) - ThrowHelper.ThrowTypeLoadException(nameSpace, name, this); - - return null; - } - - public TypeDesc GetType(EntityHandle handle) - { - TypeDesc type = GetObject(handle) as TypeDesc; - if (type == null) - throw new BadImageFormatException("Type expected"); - return type; - } - - public MethodDesc GetMethod(EntityHandle handle) - { - MethodDesc method = GetObject(handle) as MethodDesc; - if (method == null) - throw new BadImageFormatException("Method expected"); - return method; - } - - public FieldDesc GetField(EntityHandle handle) - { - FieldDesc field = GetObject(handle) as FieldDesc; - if (field == null) - throw new BadImageFormatException("Field expected"); - return field; - } - - public Object GetObject(EntityHandle handle) - { - IEntityHandleObject obj = _resolvedTokens.GetOrCreateValue(handle); - if (obj is EcmaObjectLookupWrapper) - { - return ((EcmaObjectLookupWrapper)obj).Object; - } - else - { - return obj; - } - } - - private Object ResolveMethodSpecification(MethodSpecificationHandle handle) - { - MethodSpecification methodSpecification = _metadataReader.GetMethodSpecification(handle); - - MethodDesc methodDef = GetMethod(methodSpecification.Method); - - BlobReader signatureReader = _metadataReader.GetBlobReader(methodSpecification.Signature); - EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); - - TypeDesc[] instantiation = parser.ParseMethodSpecSignature(); - return Context.GetInstantiatedMethod(methodDef, new Instantiation(instantiation)); - } - - private Object ResolveStandaloneSignature(StandaloneSignatureHandle handle) - { - StandaloneSignature signature = _metadataReader.GetStandaloneSignature(handle); - BlobReader signatureReader = _metadataReader.GetBlobReader(signature.Signature); - EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); - - MethodSignature methodSig = parser.ParseMethodSignature(); - return methodSig; - } - - private Object ResolveTypeSpecification(TypeSpecificationHandle handle) - { - TypeSpecification typeSpecification = _metadataReader.GetTypeSpecification(handle); - - BlobReader signatureReader = _metadataReader.GetBlobReader(typeSpecification.Signature); - EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); - - return parser.ParseType(); - } - - private Object ResolveMemberReference(MemberReferenceHandle handle) - { - MemberReference memberReference = _metadataReader.GetMemberReference(handle); - - Object parent = GetObject(memberReference.Parent); - - TypeDesc parentTypeDesc = parent as TypeDesc; - if (parentTypeDesc != null) - { - BlobReader signatureReader = _metadataReader.GetBlobReader(memberReference.Signature); - - EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); - - string name = _metadataReader.GetString(memberReference.Name); - - if (parser.IsFieldSignature) - { - FieldDesc field = parentTypeDesc.GetField(name); - if (field != null) - return field; - - ThrowHelper.ThrowMissingFieldException(parentTypeDesc, name); - } - else - { - MethodSignature sig = parser.ParseMethodSignature(); - TypeDesc typeDescToInspect = parentTypeDesc; - - // Try to resolve the name and signature in the current type, or any of the base types. - do - { - // TODO: handle substitutions - MethodDesc method = typeDescToInspect.GetMethod(name, sig); - if (method != null) - { - // If this resolved to one of the base types, make sure it's not a constructor. - // Instance constructors are not inherited. - if (typeDescToInspect != parentTypeDesc && method.IsConstructor) - break; - - return method; - } - typeDescToInspect = typeDescToInspect.BaseType; - } while (typeDescToInspect != null); - - ThrowHelper.ThrowMissingMethodException(parentTypeDesc, name, sig); - } - } - else if (parent is MethodDesc) - { - ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramVararg, (MethodDesc)parent); - } - else if (parent is ModuleDesc) - { - throw new NotImplementedException("MemberRef to a global function or variable."); - } - - throw new BadImageFormatException(); - } - - private Object ResolveTypeReference(TypeReferenceHandle handle) - { - TypeReference typeReference = _metadataReader.GetTypeReference(handle); - - Object resolutionScope = GetObject(typeReference.ResolutionScope); - - if (resolutionScope is ModuleDesc) - { - return ((ModuleDesc)(resolutionScope)).GetType(_metadataReader.GetString(typeReference.Namespace), _metadataReader.GetString(typeReference.Name)); - } - else - if (resolutionScope is MetadataType) - { - string typeName = _metadataReader.GetString(typeReference.Name); - if (!typeReference.Namespace.IsNil) - typeName = _metadataReader.GetString(typeReference.Namespace) + "." + typeName; - MetadataType result = ((MetadataType)(resolutionScope)).GetNestedType(typeName); - if (result != null) - return result; - - ThrowHelper.ThrowTypeLoadException(typeName, ((MetadataType)resolutionScope).Module); - } - - // TODO - throw new NotImplementedException(); - } - - private Object ResolveAssemblyReference(AssemblyReferenceHandle handle) - { - AssemblyReference assemblyReference = _metadataReader.GetAssemblyReference(handle); - - AssemblyName an = new AssemblyName(); - an.Name = _metadataReader.GetString(assemblyReference.Name); - an.Version = assemblyReference.Version; - - var publicKeyOrToken = _metadataReader.GetBlobBytes(assemblyReference.PublicKeyOrToken); - if ((assemblyReference.Flags & AssemblyFlags.PublicKey) != 0) - { - an.SetPublicKey(publicKeyOrToken); - } - else - { - an.SetPublicKeyToken(publicKeyOrToken); - } - - an.CultureName = _metadataReader.GetString(assemblyReference.Culture); - an.ContentType = GetContentTypeFromAssemblyFlags(assemblyReference.Flags); - - return Context.ResolveAssembly(an); - } - - private Object ResolveExportedType(ExportedTypeHandle handle) - { - ExportedType exportedType = _metadataReader.GetExportedType(handle); - - var implementation = GetObject(exportedType.Implementation); - if (implementation is ModuleDesc) - { - var module = (ModuleDesc)implementation; - string nameSpace = _metadataReader.GetString(exportedType.Namespace); - string name = _metadataReader.GetString(exportedType.Name); - return module.GetType(nameSpace, name); - } - else - if (implementation is MetadataType) - { - var type = (MetadataType)implementation; - string name = _metadataReader.GetString(exportedType.Name); - var nestedType = type.GetNestedType(name); - if (nestedType == null) - ThrowHelper.ThrowTypeLoadException(name, this); - return nestedType; - } - else - { - throw new BadImageFormatException("Unknown metadata token type for exported type"); - } - } - - public sealed override IEnumerable GetAllTypes() - { - foreach (var typeDefinitionHandle in _metadataReader.TypeDefinitions) - { - yield return (MetadataType)GetType(typeDefinitionHandle); - } - } - - public sealed override MetadataType GetGlobalModuleType() - { - int typeDefinitionsCount = _metadataReader.TypeDefinitions.Count; - if (typeDefinitionsCount == 0) - return null; - - return (MetadataType)GetType(MetadataTokens.EntityHandle(0x02000001 /* COR_GLOBAL_PARENT_TOKEN */)); - } - - protected static AssemblyContentType GetContentTypeFromAssemblyFlags(AssemblyFlags flags) - { - return (AssemblyContentType)(((int)flags & 0x0E00) >> 9); - } - - public string GetUserString(UserStringHandle userStringHandle) - { - // String literals are not cached - return _metadataReader.GetUserString(userStringHandle); - } - - public override string ToString() - { - ModuleDefinition moduleDefinition = _metadataReader.GetModuleDefinition(); - return _metadataReader.GetString(moduleDefinition.Name); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaSignatureParser.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaSignatureParser.cs deleted file mode 100644 index c4bfbfda8fb..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaSignatureParser.cs +++ /dev/null @@ -1,499 +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 System.Reflection.Metadata; -using System.Runtime.InteropServices; -using System.Diagnostics; -using System.Linq; - -using Internal.TypeSystem; -using System.Collections.Generic; - -namespace Internal.TypeSystem.Ecma -{ - public struct EcmaSignatureParser - { - private EcmaModule _module; - private BlobReader _reader; - - private Stack _indexStack; - private List _embeddedSignatureDataList; - - - public EcmaSignatureParser(EcmaModule module, BlobReader reader) - { - _module = module; - _reader = reader; - _indexStack = null; - _embeddedSignatureDataList = null; - } - - private TypeDesc GetWellKnownType(WellKnownType wellKnownType) - { - return _module.Context.GetWellKnownType(wellKnownType); - } - - private TypeDesc ParseType(SignatureTypeCode typeCode) - { - - if (_indexStack != null) - { - int was = _indexStack.Pop(); - _indexStack.Push(was + 1); - _indexStack.Push(0); - } - TypeDesc result = ParseTypeImpl(typeCode); - if (_indexStack != null) - { - _indexStack.Pop(); - } - return result; - } - - private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode) - { - // Switch on the type. - switch (typeCode) - { - case SignatureTypeCode.Void: - return GetWellKnownType(WellKnownType.Void); - case SignatureTypeCode.Boolean: - return GetWellKnownType(WellKnownType.Boolean); - case SignatureTypeCode.SByte: - return GetWellKnownType(WellKnownType.SByte); - case SignatureTypeCode.Byte: - return GetWellKnownType(WellKnownType.Byte); - case SignatureTypeCode.Int16: - return GetWellKnownType(WellKnownType.Int16); - case SignatureTypeCode.UInt16: - return GetWellKnownType(WellKnownType.UInt16); - case SignatureTypeCode.Int32: - return GetWellKnownType(WellKnownType.Int32); - case SignatureTypeCode.UInt32: - return GetWellKnownType(WellKnownType.UInt32); - case SignatureTypeCode.Int64: - return GetWellKnownType(WellKnownType.Int64); - case SignatureTypeCode.UInt64: - return GetWellKnownType(WellKnownType.UInt64); - case SignatureTypeCode.Single: - return GetWellKnownType(WellKnownType.Single); - case SignatureTypeCode.Double: - return GetWellKnownType(WellKnownType.Double); - case SignatureTypeCode.Char: - return GetWellKnownType(WellKnownType.Char); - case SignatureTypeCode.String: - return GetWellKnownType(WellKnownType.String); - case SignatureTypeCode.IntPtr: - return GetWellKnownType(WellKnownType.IntPtr); - case SignatureTypeCode.UIntPtr: - return GetWellKnownType(WellKnownType.UIntPtr); - case SignatureTypeCode.Object: - return GetWellKnownType(WellKnownType.Object); - case SignatureTypeCode.TypeHandle: - return _module.GetType(_reader.ReadTypeHandle()); - case SignatureTypeCode.SZArray: - return _module.Context.GetArrayType(ParseType()); - case SignatureTypeCode.Array: - { - var elementType = ParseType(); - var rank = _reader.ReadCompressedInteger(); - - // TODO: Bounds for multi-dimmensional arrays - var boundsCount = _reader.ReadCompressedInteger(); - for (int i = 0; i < boundsCount; i++) - _reader.ReadCompressedInteger(); - var lowerBoundsCount = _reader.ReadCompressedInteger(); - for (int j = 0; j < lowerBoundsCount; j++) - _reader.ReadCompressedInteger(); - - return _module.Context.GetArrayType(elementType, rank); - } - case SignatureTypeCode.ByReference: - return ParseType().MakeByRefType(); - case SignatureTypeCode.Pointer: - return _module.Context.GetPointerType(ParseType()); - case SignatureTypeCode.GenericTypeParameter: - return _module.Context.GetSignatureVariable(_reader.ReadCompressedInteger(), false); - case SignatureTypeCode.GenericMethodParameter: - return _module.Context.GetSignatureVariable(_reader.ReadCompressedInteger(), true); - case SignatureTypeCode.GenericTypeInstance: - { - TypeDesc typeDef = ParseType(); - MetadataType metadataTypeDef = typeDef as MetadataType; - if (metadataTypeDef == null) - throw new BadImageFormatException(); - - TypeDesc[] instance = new TypeDesc[_reader.ReadCompressedInteger()]; - for (int i = 0; i < instance.Length; i++) - instance[i] = ParseType(); - return _module.Context.GetInstantiatedType(metadataTypeDef, new Instantiation(instance)); - } - case SignatureTypeCode.TypedReference: - return GetWellKnownType(WellKnownType.TypedReference); - case SignatureTypeCode.FunctionPointer: - return _module.Context.GetFunctionPointerType(ParseMethodSignatureInternal(skipEmbeddedSignatureData: true)); - default: - throw new BadImageFormatException(); - } - } - - private SignatureTypeCode ParseTypeCode(bool skipPinned = true) - { - if (_indexStack != null) - { - int was = _indexStack.Pop(); - _indexStack.Push(was + 1); - _indexStack.Push(0); - } - SignatureTypeCode result = ParseTypeCodeImpl(skipPinned); - if (_indexStack != null) - { - _indexStack.Pop(); - } - return result; - } - - private SignatureTypeCode ParseTypeCodeImpl(bool skipPinned = true) - { - for (; ; ) - { - SignatureTypeCode typeCode = _reader.ReadSignatureTypeCode(); - - if (typeCode == SignatureTypeCode.RequiredModifier) - { - EntityHandle typeHandle = _reader.ReadTypeHandle(); - if (_embeddedSignatureDataList != null) - { - _embeddedSignatureDataList.Add(new EmbeddedSignatureData { index = string.Join(".", _indexStack), kind = EmbeddedSignatureDataKind.RequiredCustomModifier, type = _module.GetType(typeHandle) }); - } - continue; - } - - if (typeCode == SignatureTypeCode.OptionalModifier) - { - EntityHandle typeHandle = _reader.ReadTypeHandle(); - if (_embeddedSignatureDataList != null) - { - _embeddedSignatureDataList.Add(new EmbeddedSignatureData { index = string.Join(".", _indexStack), kind = EmbeddedSignatureDataKind.OptionalCustomModifier, type = _module.GetType(typeHandle) }); - } - continue; - } - - // TODO: treat PINNED in the signature same as modopts (it matters - // in signature matching - you can actually define overloads on this) - if (skipPinned && typeCode == SignatureTypeCode.Pinned) - { - continue; - } - - return typeCode; - } - } - - public TypeDesc ParseType() - { - if (_indexStack != null) - { - int was = _indexStack.Pop(); - _indexStack.Push(was + 1); - _indexStack.Push(0); - } - TypeDesc result = ParseTypeImpl(); - if (_indexStack != null) - { - _indexStack.Pop(); - } - return result; - } - - private TypeDesc ParseTypeImpl() - { - return ParseType(ParseTypeCode()); - } - - public bool IsFieldSignature - { - get - { - BlobReader peek = _reader; - return peek.ReadSignatureHeader().Kind == SignatureKind.Field; - } - } - - public MethodSignature ParseMethodSignature() - { - try - { - _indexStack = new Stack(); - _indexStack.Push(0); - _embeddedSignatureDataList = new List(); - return ParseMethodSignatureInternal(skipEmbeddedSignatureData: false); - } - finally - { - _indexStack = null; - _embeddedSignatureDataList = null; - } - - } - - private MethodSignature ParseMethodSignatureInternal(bool skipEmbeddedSignatureData) - { - if (_indexStack != null) - { - int was = _indexStack.Pop(); - _indexStack.Push(was + 1); - _indexStack.Push(0); - } - MethodSignature result = ParseMethodSignatureImpl(skipEmbeddedSignatureData); - if (_indexStack != null) - { - _indexStack.Pop(); - } - return result; - } - - private MethodSignature ParseMethodSignatureImpl(bool skipEmbeddedSignatureData) - { - SignatureHeader header = _reader.ReadSignatureHeader(); - - MethodSignatureFlags flags = 0; - - SignatureCallingConvention signatureCallConv = header.CallingConvention; - if (signatureCallConv != SignatureCallingConvention.Default) - { - // Verify that it is safe to convert CallingConvention to MethodSignatureFlags via a simple cast - Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionCdecl == (int)SignatureCallingConvention.CDecl); - Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionStdCall == (int)SignatureCallingConvention.StdCall); - Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionThisCall == (int)SignatureCallingConvention.ThisCall); - Debug.Assert((int)MethodSignatureFlags.CallingConventionVarargs == (int)SignatureCallingConvention.VarArgs); - - flags = (MethodSignatureFlags)signatureCallConv; - } - - if (!header.IsInstance) - flags |= MethodSignatureFlags.Static; - - int arity = header.IsGeneric ? _reader.ReadCompressedInteger() : 0; - - int count = _reader.ReadCompressedInteger(); - - TypeDesc returnType = ParseType(); - TypeDesc[] parameters; - - if (count > 0) - { - // Get all of the parameters. - parameters = new TypeDesc[count]; - for (int i = 0; i < count; i++) - { - parameters[i] = ParseType(); - } - } - else - { - parameters = TypeDesc.EmptyTypes; - } - - EmbeddedSignatureData[] embeddedSignatureDataArray = (_embeddedSignatureDataList == null || _embeddedSignatureDataList.Count == 0 || skipEmbeddedSignatureData) ? null : _embeddedSignatureDataList.ToArray(); - - return new MethodSignature(flags, arity, returnType, parameters, embeddedSignatureDataArray); - - } - - public PropertySignature ParsePropertySignature() - { - SignatureHeader header = _reader.ReadSignatureHeader(); - if (header.Kind != SignatureKind.Property) - throw new BadImageFormatException(); - - bool isStatic = !header.IsInstance; - - int count = _reader.ReadCompressedInteger(); - - TypeDesc returnType = ParseType(); - TypeDesc[] parameters; - - if (count > 0) - { - // Get all of the parameters. - parameters = new TypeDesc[count]; - for (int i = 0; i < count; i++) - { - parameters[i] = ParseType(); - } - } - else - { - parameters = TypeDesc.EmptyTypes; - } - - return new PropertySignature(isStatic, parameters, returnType); - } - - public TypeDesc ParseFieldSignature() - { - if (_reader.ReadSignatureHeader().Kind != SignatureKind.Field) - throw new BadImageFormatException(); - - return ParseType(); - } - - public LocalVariableDefinition[] ParseLocalsSignature() - { - if (_reader.ReadSignatureHeader().Kind != SignatureKind.LocalVariables) - throw new BadImageFormatException(); - - int count = _reader.ReadCompressedInteger(); - - LocalVariableDefinition[] locals; - - if (count > 0) - { - locals = new LocalVariableDefinition[count]; - for (int i = 0; i < count; i++) - { - bool isPinned = false; - - SignatureTypeCode typeCode = ParseTypeCode(skipPinned: false); - if (typeCode == SignatureTypeCode.Pinned) - { - isPinned = true; - typeCode = ParseTypeCode(); - } - - locals[i] = new LocalVariableDefinition(ParseType(typeCode), isPinned); - } - } - else - { - locals = Array.Empty(); - } - return locals; - } - - public TypeDesc[] ParseMethodSpecSignature() - { - if (_reader.ReadSignatureHeader().Kind != SignatureKind.MethodSpecification) - throw new BadImageFormatException(); - - int count = _reader.ReadCompressedInteger(); - - if (count <= 0) - throw new BadImageFormatException(); - - TypeDesc[] arguments = new TypeDesc[count]; - for (int i = 0; i < count; i++) - { - arguments[i] = ParseType(); - } - return arguments; - } - - public MarshalAsDescriptor ParseMarshalAsDescriptor() - { - Debug.Assert(_reader.RemainingBytes != 0); - - NativeTypeKind type = (NativeTypeKind)_reader.ReadByte(); - NativeTypeKind arraySubType = NativeTypeKind.Default; - uint? paramNum = null, numElem = null; - - switch (type) - { - case NativeTypeKind.Array: - { - if (_reader.RemainingBytes != 0) - { - arraySubType = (NativeTypeKind)_reader.ReadByte(); - } - - if (_reader.RemainingBytes != 0) - { - paramNum = (uint)_reader.ReadCompressedInteger(); - } - - if (_reader.RemainingBytes != 0) - { - numElem = (uint)_reader.ReadCompressedInteger(); - } - - if (_reader.RemainingBytes != 0) - { - int flag = _reader.ReadCompressedInteger(); - if (flag == 0) - { - paramNum = null; //paramNum is just a place holder so that numElem can be present - } - } - - } - break; - case NativeTypeKind.ByValArray: - { - if (_reader.RemainingBytes != 0) - { - numElem = (uint)_reader.ReadCompressedInteger(); - } - - if (_reader.RemainingBytes != 0) - { - arraySubType = (NativeTypeKind)_reader.ReadByte(); - } - } - break; - case NativeTypeKind.ByValTStr: - { - if (_reader.RemainingBytes != 0) - { - numElem = (uint)_reader.ReadCompressedInteger(); - } - } - break; - case NativeTypeKind.SafeArray: - { - // There's nobody to consume SafeArrays, so let's just parse the data - // to avoid asserting later. - - // Get optional VARTYPE for the element - if (_reader.RemainingBytes != 0) - { - _reader.ReadCompressedInteger(); - } - - // VARTYPE can be followed by optional type name - if (_reader.RemainingBytes != 0) - { - _reader.ReadSerializedString(); - } - } - break; - case NativeTypeKind.CustomMarshaler: - { - // There's nobody to consume CustomMarshaller, so let's just parse the data - // to avoid asserting later. - - // Read typelib guid - _reader.ReadSerializedString(); - - // Read native type name - _reader.ReadSerializedString(); - - // Read managed marshaler name - _reader.ReadSerializedString(); - - // Read cookie - _reader.ReadSerializedString(); - } - break; - default: - break; - } - - Debug.Assert(_reader.RemainingBytes == 0); - - return new MarshalAsDescriptor(type, arraySubType, paramNum, numElem); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs deleted file mode 100644 index 4a00ef9d71d..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs +++ /dev/null @@ -1,51 +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 System.Collections.Generic; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Threading; -using Debug = System.Diagnostics.Debug; - -using Internal.NativeFormat; - -namespace Internal.TypeSystem.Ecma -{ - /// - /// Override of MetadataType that uses actual Ecma335 metadata. - /// - public sealed partial class EcmaType - { - public override string DiagnosticName - { - get - { - try - { - return Name; - } - catch - { - return $"TypeDef({MetadataReader.GetToken(Handle):x8})"; - } - } - } - public override string DiagnosticNamespace - { - get - { - try - { - return Namespace; - } - catch - { - return ""; // If namespace throws, then Name will as well, and it will attach the token as the name instead. - } - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Interfaces.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Interfaces.cs deleted file mode 100644 index c118df190fc..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Interfaces.cs +++ /dev/null @@ -1,54 +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 System.Reflection; -using System.Reflection.Metadata; -using System.Threading; -using Debug = System.Diagnostics.Debug; - -using Internal.TypeSystem; - -namespace Internal.TypeSystem.Ecma -{ - // This file has implementations of the .Interfaces.cs logic from its base type. - - public sealed partial class EcmaType : MetadataType - { - private DefType[] _implementedInterfaces; - - public override DefType[] ExplicitlyImplementedInterfaces - { - get - { - if (_implementedInterfaces == null) - return InitializeImplementedInterfaces(); - return _implementedInterfaces; - } - } - - private DefType[] InitializeImplementedInterfaces() - { - var interfaceHandles = _typeDefinition.GetInterfaceImplementations(); - - int count = interfaceHandles.Count; - if (count == 0) - return (_implementedInterfaces = Array.Empty()); - - DefType[] implementedInterfaces = new DefType[count]; - int i = 0; - foreach (var interfaceHandle in interfaceHandles) - { - var interfaceImplementation = this.MetadataReader.GetInterfaceImplementation(interfaceHandle); - DefType interfaceType = _module.GetType(interfaceImplementation.Interface) as DefType; - if (interfaceType == null) - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, this); - - implementedInterfaces[i++] = interfaceType; - } - - return (_implementedInterfaces = implementedInterfaces); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.MethodImpls.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.MethodImpls.cs deleted file mode 100644 index 4348f6c8ed9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.MethodImpls.cs +++ /dev/null @@ -1,132 +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 System.Collections.Generic; -using System.Reflection; -using System.Reflection.Metadata; -using System.Threading; -using Debug = System.Diagnostics.Debug; - -using Internal.TypeSystem; - -namespace Internal.TypeSystem.Ecma -{ - // This file has implementations of the .MethodImpl.cs logic from its base type. - - public sealed partial class EcmaType : MetadataType - { - // Virtual function related functionality - public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string declName) - { - MetadataReader metadataReader = _module.MetadataReader; - var stringComparer = metadataReader.StringComparer; - ArrayBuilder foundRecords = new ArrayBuilder(); - - foreach (var methodImplHandle in _typeDefinition.GetMethodImplementations()) - { - MethodImplementation methodImpl = metadataReader.GetMethodImplementation(methodImplHandle); - - EntityHandle methodDeclCheckHandle = methodImpl.MethodDeclaration; - HandleKind methodDeclHandleKind = methodDeclCheckHandle.Kind; - - // We want to check that the method name matches before actually getting the MethodDesc. For MethodSpecifications - // we need to dereference that handle to the underlying member reference to look at name matching. - if (methodDeclHandleKind == HandleKind.MethodSpecification) - { - methodDeclCheckHandle = metadataReader.GetMethodSpecification((MethodSpecificationHandle)methodDeclCheckHandle).Method; - methodDeclHandleKind = methodDeclCheckHandle.Kind; - } - - bool foundRecord = false; - - switch (methodDeclHandleKind) - { - case HandleKind.MethodDefinition: - if (stringComparer.Equals(metadataReader.GetMethodDefinition((MethodDefinitionHandle)methodDeclCheckHandle).Name, declName)) - { - foundRecord = true; - } - break; - - case HandleKind.MemberReference: - if (stringComparer.Equals(metadataReader.GetMemberReference((MemberReferenceHandle)methodDeclCheckHandle).Name, declName)) - { - foundRecord = true; - } - break; - - default: - Debug.Fail("unexpected methodDeclHandleKind"); - break; - } - - if (foundRecord) - { - MethodImplRecord newRecord = new MethodImplRecord( - (MethodDesc)_module.GetObject(methodImpl.MethodDeclaration), - (MethodDesc)_module.GetObject(methodImpl.MethodBody)); - - foundRecords.Add(newRecord); - } - } - - if (foundRecords.Count != 0) - return foundRecords.ToArray(); - - return null; - } - - protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() - { - ArrayBuilder records = new ArrayBuilder(); - - MetadataReader metadataReader = _module.MetadataReader; - - foreach (var methodImplHandle in _typeDefinition.GetMethodImplementations()) - { - MethodImplementation methodImpl = metadataReader.GetMethodImplementation(methodImplHandle); - - EntityHandle methodDeclCheckHandle = methodImpl.MethodDeclaration; - HandleKind methodDeclHandleKind = methodDeclCheckHandle.Kind; - - // We want to check that the type is not an interface matches before actually getting the MethodDesc. - // For MethodSpecifications we need to dereference that handle to the underlying member reference to - // look at the owning type. - if (methodDeclHandleKind == HandleKind.MethodSpecification) - { - methodDeclCheckHandle = metadataReader.GetMethodSpecification((MethodSpecificationHandle)methodDeclCheckHandle).Method; - methodDeclHandleKind = methodDeclCheckHandle.Kind; - } - - MetadataType owningType = null; - switch (methodDeclHandleKind) - { - case HandleKind.MethodDefinition: - owningType = ((MethodDesc)_module.GetObject(methodDeclCheckHandle)).OwningType as MetadataType; - break; - - case HandleKind.MemberReference: - EntityHandle owningTypeHandle = metadataReader.GetMemberReference((MemberReferenceHandle)methodDeclCheckHandle).Parent; - owningType = _module.GetObject(owningTypeHandle) as MetadataType; - break; - - default: - Debug.Fail("unexpected methodDeclHandleKind"); - break; - } - - if (!owningType.IsInterface) - { - MethodImplRecord newRecord = new MethodImplRecord( - (MethodDesc)_module.GetObject(methodImpl.MethodDeclaration), - (MethodDesc)_module.GetObject(methodImpl.MethodBody)); - records.Add(newRecord); - } - } - - return records.ToArray(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Serialization.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Serialization.cs deleted file mode 100644 index 3ba6042c5de..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Serialization.cs +++ /dev/null @@ -1,19 +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.Reflection; - -namespace Internal.TypeSystem.Ecma -{ - partial class EcmaType - { - public override bool IsSerializable - { - get - { - return (_typeDefinition.Attributes & TypeAttributes.Serializable) != 0; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Sorting.cs deleted file mode 100644 index 246f36aa3f0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Sorting.cs +++ /dev/null @@ -1,24 +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.Reflection.Metadata.Ecma335; - -namespace Internal.TypeSystem.Ecma -{ - // Functionality related to determinstic ordering of types - partial class EcmaType - { - protected internal override int ClassCode => 1340416537; - - protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - var otherType = (EcmaType)other; - int result = _module.MetadataReader.GetToken(_handle) - otherType._module.MetadataReader.GetToken(otherType._handle); - if (result != 0) - return result; - - return _module.CompareTo(otherType._module); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.cs deleted file mode 100644 index 24cf0c8a43f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.cs +++ /dev/null @@ -1,598 +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 System.Collections.Generic; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Threading; -using Debug = System.Diagnostics.Debug; - -using Internal.NativeFormat; - -namespace Internal.TypeSystem.Ecma -{ - /// - /// Override of MetadataType that uses actual Ecma335 metadata. - /// - public sealed partial class EcmaType : MetadataType, EcmaModule.IEntityHandleObject - { - private EcmaModule _module; - private TypeDefinitionHandle _handle; - - private TypeDefinition _typeDefinition; - - // Cached values - private string _typeName; - private string _typeNamespace; - private TypeDesc[] _genericParameters; - private MetadataType _baseType; - private int _hashcode; - - internal EcmaType(EcmaModule module, TypeDefinitionHandle handle) - { - _module = module; - _handle = handle; - - _typeDefinition = module.MetadataReader.GetTypeDefinition(handle); - - _baseType = this; // Not yet initialized flag - -#if DEBUG - // Initialize name eagerly in debug builds for convenience - InitializeName(); - InitializeNamespace(); -#endif - } - - public override int GetHashCode() - { - if (_hashcode != 0) - return _hashcode; - return InitializeHashCode(); - } - - private int InitializeHashCode() - { - TypeDesc containingType = ContainingType; - if (containingType == null) - { - string ns = Namespace; - var hashCodeBuilder = new TypeHashingAlgorithms.HashCodeBuilder(ns); - if (ns.Length > 0) - hashCodeBuilder.Append("."); - hashCodeBuilder.Append(Name); - _hashcode = hashCodeBuilder.ToHashCode(); - } - else - { - _hashcode = TypeHashingAlgorithms.ComputeNestedTypeHashCode( - containingType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(Name)); - } - - return _hashcode; - } - - EntityHandle EcmaModule.IEntityHandleObject.Handle - { - get - { - return _handle; - } - } - - public override TypeSystemContext Context - { - get - { - return _module.Context; - } - } - - private void ComputeGenericParameters() - { - var genericParameterHandles = _typeDefinition.GetGenericParameters(); - int count = genericParameterHandles.Count; - if (count > 0) - { - TypeDesc[] genericParameters = new TypeDesc[count]; - int i = 0; - foreach (var genericParameterHandle in genericParameterHandles) - { - genericParameters[i++] = new EcmaGenericParameter(_module, genericParameterHandle); - } - Interlocked.CompareExchange(ref _genericParameters, genericParameters, null); - } - else - { - _genericParameters = TypeDesc.EmptyTypes; - } - } - - public override Instantiation Instantiation - { - get - { - if (_genericParameters == null) - ComputeGenericParameters(); - return new Instantiation(_genericParameters); - } - } - - public override ModuleDesc Module - { - get - { - return _module; - } - } - - public EcmaModule EcmaModule - { - get - { - return _module; - } - } - - public MetadataReader MetadataReader - { - get - { - return _module.MetadataReader; - } - } - - public TypeDefinitionHandle Handle - { - get - { - return _handle; - } - } - - private MetadataType InitializeBaseType() - { - var baseTypeHandle = _typeDefinition.BaseType; - if (baseTypeHandle.IsNil) - { - _baseType = null; - return null; - } - - var type = _module.GetType(baseTypeHandle) as MetadataType; - if (type == null) - { - // PREFER: "new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadBadFormat, this)" but the metadata is too broken - ThrowHelper.ThrowTypeLoadException(Namespace, Name, Module); - } - _baseType = type; - return type; - } - - public override DefType BaseType - { - get - { - if (_baseType == this) - return InitializeBaseType(); - return _baseType; - } - } - - public override MetadataType MetadataBaseType - { - get - { - if (_baseType == this) - return InitializeBaseType(); - return _baseType; - } - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = 0; - - if ((mask & TypeFlags.CategoryMask) != 0) - { - TypeDesc baseType = this.BaseType; - - if (baseType != null && baseType.IsWellKnownType(WellKnownType.ValueType)) - { - flags |= TypeFlags.ValueType; - } - else - if (baseType != null && baseType.IsWellKnownType(WellKnownType.Enum)) - { - flags |= TypeFlags.Enum; - } - else - { - if ((_typeDefinition.Attributes & TypeAttributes.Interface) != 0) - flags |= TypeFlags.Interface; - else - flags |= TypeFlags.Class; - } - - // All other cases are handled during TypeSystemContext intitialization - } - - if ((mask & TypeFlags.HasGenericVarianceComputed) != 0) - { - flags |= TypeFlags.HasGenericVarianceComputed; - - foreach (GenericParameterDesc genericParam in Instantiation) - { - if (genericParam.Variance != GenericVariance.None) - { - flags |= TypeFlags.HasGenericVariance; - break; - } - } - } - - if ((mask & TypeFlags.HasFinalizerComputed) != 0) - { - flags |= TypeFlags.HasFinalizerComputed; - - if (GetFinalizer() != null) - flags |= TypeFlags.HasFinalizer; - } - - if ((mask & TypeFlags.AttributeCacheComputed) != 0) - { - MetadataReader reader = MetadataReader; - MetadataStringComparer stringComparer = reader.StringComparer; - bool isValueType = IsValueType; - - flags |= TypeFlags.AttributeCacheComputed; - - foreach (CustomAttributeHandle attributeHandle in _typeDefinition.GetCustomAttributes()) - { - if (MetadataReader.GetAttributeNamespaceAndName(attributeHandle, out StringHandle namespaceHandle, out StringHandle nameHandle)) - { - if (isValueType && - stringComparer.Equals(nameHandle, "IsByRefLikeAttribute") && - stringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices")) - flags |= TypeFlags.IsByRefLike; - - if (stringComparer.Equals(nameHandle, "IntrinsicAttribute") && - stringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices")) - flags |= TypeFlags.IsIntrinsic; - } - } - } - - return flags; - } - - private string InitializeName() - { - var metadataReader = this.MetadataReader; - _typeName = metadataReader.GetString(_typeDefinition.Name); - return _typeName; - } - - public override string Name - { - get - { - if (_typeName == null) - return InitializeName(); - return _typeName; - } - } - - private string InitializeNamespace() - { - var metadataReader = this.MetadataReader; - _typeNamespace = metadataReader.GetString(_typeDefinition.Namespace); - return _typeNamespace; - } - - public override string Namespace - { - get - { - if (_typeNamespace == null) - return InitializeNamespace(); - return _typeNamespace; - } - } - - public override IEnumerable GetMethods() - { - foreach (var handle in _typeDefinition.GetMethods()) - { - yield return (MethodDesc)_module.GetObject(handle); - } - } - - public override MethodDesc GetMethod(string name, MethodSignature signature) - { - var metadataReader = this.MetadataReader; - var stringComparer = metadataReader.StringComparer; - - foreach (var handle in _typeDefinition.GetMethods()) - { - if (stringComparer.Equals(metadataReader.GetMethodDefinition(handle).Name, name)) - { - MethodDesc method = (MethodDesc)_module.GetObject(handle); - if (signature == null || signature.Equals(method.Signature)) - return method; - } - } - - return null; - } - - public override MethodDesc GetStaticConstructor() - { - var metadataReader = this.MetadataReader; - var stringComparer = metadataReader.StringComparer; - - foreach (var handle in _typeDefinition.GetMethods()) - { - var methodDefinition = metadataReader.GetMethodDefinition(handle); - if (methodDefinition.Attributes.IsRuntimeSpecialName() && - stringComparer.Equals(methodDefinition.Name, ".cctor")) - { - MethodDesc method = (MethodDesc)_module.GetObject(handle); - return method; - } - } - - return null; - } - - public override MethodDesc GetDefaultConstructor() - { - if (IsAbstract) - return null; - - MetadataReader metadataReader = this.MetadataReader; - MetadataStringComparer stringComparer = metadataReader.StringComparer; - - foreach (var handle in _typeDefinition.GetMethods()) - { - var methodDefinition = metadataReader.GetMethodDefinition(handle); - MethodAttributes attributes = methodDefinition.Attributes; - if (attributes.IsRuntimeSpecialName() && attributes.IsPublic() - && stringComparer.Equals(methodDefinition.Name, ".ctor")) - { - MethodDesc method = (MethodDesc)_module.GetObject(handle); - if (method.Signature.Length != 0) - continue; - - return method; - } - } - - return null; - } - - public override MethodDesc GetFinalizer() - { - // System.Object defines Finalize but doesn't use it, so we can determine that a type has a Finalizer - // by checking for a virtual method override that lands anywhere other than Object in the inheritance - // chain. - if (!HasBaseType) - return null; - - TypeDesc objectType = Context.GetWellKnownType(WellKnownType.Object); - MethodDesc decl = objectType.GetMethod("Finalize", null); - - if (decl != null) - { - MethodDesc impl = this.FindVirtualFunctionTargetMethodOnObjectType(decl); - if (impl == null) - { - // TODO: invalid input: the type doesn't derive from our System.Object - throw new TypeLoadException(this.GetFullName()); - } - - if (impl.OwningType != objectType) - { - return impl; - } - - return null; - } - - // Class library doesn't have finalizers - return null; - } - - public override IEnumerable GetFields() - { - foreach (var handle in _typeDefinition.GetFields()) - { - var field = (EcmaField)_module.GetObject(handle); - yield return field; - } - } - - public override FieldDesc GetField(string name) - { - var metadataReader = this.MetadataReader; - var stringComparer = metadataReader.StringComparer; - - foreach (var handle in _typeDefinition.GetFields()) - { - if (stringComparer.Equals(metadataReader.GetFieldDefinition(handle).Name, name)) - { - var field = (EcmaField)_module.GetObject(handle); - return field; - } - } - - return null; - } - - public override IEnumerable GetNestedTypes() - { - foreach (var handle in _typeDefinition.GetNestedTypes()) - { - yield return (MetadataType)_module.GetObject(handle); - } - } - - public override MetadataType GetNestedType(string name) - { - var metadataReader = this.MetadataReader; - var stringComparer = metadataReader.StringComparer; - - foreach (var handle in _typeDefinition.GetNestedTypes()) - { - bool nameMatched; - TypeDefinition type = metadataReader.GetTypeDefinition(handle); - if (type.Namespace.IsNil) - { - nameMatched = stringComparer.Equals(type.Name, name); - } - else - { - string typeName = metadataReader.GetString(type.Name); - typeName = metadataReader.GetString(type.Namespace) + "." + typeName; - nameMatched = typeName == name; - } - - if (nameMatched) - return (MetadataType)_module.GetObject(handle); - } - - return null; - } - - public TypeAttributes Attributes - { - get - { - return _typeDefinition.Attributes; - } - } - - public override DefType ContainingType - { - get - { - if (!_typeDefinition.Attributes.IsNested()) - return null; - - var handle = _typeDefinition.GetDeclaringType(); - return (DefType)_module.GetType(handle); - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return !MetadataReader.GetCustomAttributeHandle(_typeDefinition.GetCustomAttributes(), - attributeNamespace, attributeName).IsNil; - } - - public override ClassLayoutMetadata GetClassLayout() - { - TypeLayout layout = _typeDefinition.GetLayout(); - - ClassLayoutMetadata result; - result.PackingSize = layout.PackingSize; - result.Size = layout.Size; - - // Skip reading field offsets if this is not explicit layout - if (IsExplicitLayout) - { - var fieldDefinitionHandles = _typeDefinition.GetFields(); - var numInstanceFields = 0; - - foreach (var handle in fieldDefinitionHandles) - { - var fieldDefinition = MetadataReader.GetFieldDefinition(handle); - if ((fieldDefinition.Attributes & FieldAttributes.Static) != 0) - continue; - - numInstanceFields++; - } - - result.Offsets = new FieldAndOffset[numInstanceFields]; - - int index = 0; - foreach (var handle in fieldDefinitionHandles) - { - var fieldDefinition = MetadataReader.GetFieldDefinition(handle); - if ((fieldDefinition.Attributes & FieldAttributes.Static) != 0) - continue; - - // Note: GetOffset() returns -1 when offset was not set in the metadata - int specifiedOffset = fieldDefinition.GetOffset(); - result.Offsets[index] = - new FieldAndOffset((FieldDesc)_module.GetObject(handle), specifiedOffset == -1 ? FieldAndOffset.InvalidOffset : new LayoutInt(specifiedOffset)); - - index++; - } - } - else - result.Offsets = null; - - return result; - } - - public override bool IsExplicitLayout - { - get - { - return (_typeDefinition.Attributes & TypeAttributes.ExplicitLayout) != 0; - } - } - - public override bool IsSequentialLayout - { - get - { - return (_typeDefinition.Attributes & TypeAttributes.SequentialLayout) != 0; - } - } - - public override bool IsBeforeFieldInit - { - get - { - return (_typeDefinition.Attributes & TypeAttributes.BeforeFieldInit) != 0; - } - } - - public override bool IsModuleType - { - get - { - return _handle.Equals(MetadataTokens.TypeDefinitionHandle(0x00000001 /* COR_GLOBAL_PARENT_TOKEN */)); - } - } - - public override bool IsSealed - { - get - { - return (_typeDefinition.Attributes & TypeAttributes.Sealed) != 0; - } - } - - public override bool IsAbstract - { - get - { - return (_typeDefinition.Attributes & TypeAttributes.Abstract) != 0; - } - } - - public override PInvokeStringFormat PInvokeStringFormat - { - get - { - return (PInvokeStringFormat)(_typeDefinition.Attributes & TypeAttributes.StringFormatMask); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/IMetadataStringDecoderProvider.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/IMetadataStringDecoderProvider.cs deleted file mode 100644 index 5c9fc98e928..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/IMetadataStringDecoderProvider.cs +++ /dev/null @@ -1,18 +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 System.Reflection.Metadata; - -namespace Internal.TypeSystem.Ecma -{ - /// - /// Interface implemented by TypeSystemContext to provide MetadataStringDecoder - /// instance for MetadataReaders created by the type system. - /// - public interface IMetadataStringDecoderProvider - { - MetadataStringDecoder GetMetadataStringDecoder(); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/MetadataExtensions.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/MetadataExtensions.cs deleted file mode 100644 index bbe4eed38d8..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/MetadataExtensions.cs +++ /dev/null @@ -1,286 +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.Collections.Generic; -using System.Reflection; -using System.Reflection.Metadata; -using System.Runtime.InteropServices; - -namespace Internal.TypeSystem.Ecma -{ - public static class MetadataExtensions - { - public static CustomAttributeValue? GetDecodedCustomAttribute(this EcmaType This, - string attributeNamespace, string attributeName) - { - var metadataReader = This.MetadataReader; - - var attributeHandle = metadataReader.GetCustomAttributeHandle(metadataReader.GetTypeDefinition(This.Handle).GetCustomAttributes(), - attributeNamespace, attributeName); - - if (attributeHandle.IsNil) - return null; - - return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.EcmaModule)); - } - - public static CustomAttributeValue? GetDecodedCustomAttribute(this EcmaMethod This, - string attributeNamespace, string attributeName) - { - var metadataReader = This.MetadataReader; - - var attributeHandle = metadataReader.GetCustomAttributeHandle(metadataReader.GetMethodDefinition(This.Handle).GetCustomAttributes(), - attributeNamespace, attributeName); - - if (attributeHandle.IsNil) - return null; - - return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.Module)); - } - - public static IEnumerable> GetDecodedCustomAttributes(this EcmaMethod This, - string attributeNamespace, string attributeName) - { - var metadataReader = This.MetadataReader; - var attributeHandles = metadataReader.GetMethodDefinition(This.Handle).GetCustomAttributes(); - foreach (var attributeHandle in attributeHandles) - { - if (IsEqualCustomAttributeName(attributeHandle, metadataReader, attributeNamespace, attributeName)) - { - yield return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.Module)); - } - } - } - - public static CustomAttributeValue? GetDecodedCustomAttribute(this EcmaField This, - string attributeNamespace, string attributeName) - { - var metadataReader = This.MetadataReader; - - var attributeHandle = metadataReader.GetCustomAttributeHandle(metadataReader.GetFieldDefinition(This.Handle).GetCustomAttributes(), - attributeNamespace, attributeName); - - if (attributeHandle.IsNil) - return null; - - return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.Module)); - } - - public static IEnumerable> GetDecodedCustomAttributes(this EcmaField This, - string attributeNamespace, string attributeName) - { - var metadataReader = This.MetadataReader; - var attributeHandles = metadataReader.GetFieldDefinition(This.Handle).GetCustomAttributes(); - foreach (var attributeHandle in attributeHandles) - { - if (IsEqualCustomAttributeName(attributeHandle, metadataReader, attributeNamespace, attributeName)) - { - yield return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This.Module)); - } - } - } - - public static IEnumerable> GetDecodedCustomAttributes(this EcmaAssembly This, - string attributeNamespace, string attributeName) - { - var metadataReader = This.MetadataReader; - var attributeHandles = metadataReader.GetAssemblyDefinition().GetCustomAttributes(); - foreach (var attributeHandle in attributeHandles) - { - if (IsEqualCustomAttributeName(attributeHandle, metadataReader, attributeNamespace, attributeName)) - { - yield return metadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(This)); - } - } - } - - public static CustomAttributeHandle GetCustomAttributeHandle(this MetadataReader metadataReader, CustomAttributeHandleCollection customAttributes, - string attributeNamespace, string attributeName) - { - foreach (var attributeHandle in customAttributes) - { - if (IsEqualCustomAttributeName(attributeHandle, metadataReader, attributeNamespace, attributeName)) - { - return attributeHandle; - } - } - - return default(CustomAttributeHandle); - } - - private static bool IsEqualCustomAttributeName(CustomAttributeHandle attributeHandle, MetadataReader metadataReader, - string attributeNamespace, string attributeName) - { - StringHandle namespaceHandle, nameHandle; - if (!metadataReader.GetAttributeNamespaceAndName(attributeHandle, out namespaceHandle, out nameHandle)) - return false; - - return metadataReader.StringComparer.Equals(namespaceHandle, attributeNamespace) - && metadataReader.StringComparer.Equals(nameHandle, attributeName); - } - - public static bool GetAttributeNamespaceAndName(this MetadataReader metadataReader, CustomAttributeHandle attributeHandle, - out StringHandle namespaceHandle, out StringHandle nameHandle) - { - EntityHandle attributeType, attributeCtor; - if (!GetAttributeTypeAndConstructor(metadataReader, attributeHandle, out attributeType, out attributeCtor)) - { - namespaceHandle = default(StringHandle); - nameHandle = default(StringHandle); - return false; - } - - return GetAttributeTypeNamespaceAndName(metadataReader, attributeType, out namespaceHandle, out nameHandle); - } - - public static bool GetAttributeTypeAndConstructor(this MetadataReader metadataReader, CustomAttributeHandle attributeHandle, - out EntityHandle attributeType, out EntityHandle attributeCtor) - { - attributeCtor = metadataReader.GetCustomAttribute(attributeHandle).Constructor; - - if (attributeCtor.Kind == HandleKind.MemberReference) - { - attributeType = metadataReader.GetMemberReference((MemberReferenceHandle)attributeCtor).Parent; - return true; - } - else if (attributeCtor.Kind == HandleKind.MethodDefinition) - { - attributeType = metadataReader.GetMethodDefinition((MethodDefinitionHandle)attributeCtor).GetDeclaringType(); - return true; - } - else - { - // invalid metadata - attributeType = default(EntityHandle); - return false; - } - } - - public static bool GetAttributeTypeNamespaceAndName(this MetadataReader metadataReader, EntityHandle attributeType, - out StringHandle namespaceHandle, out StringHandle nameHandle) - { - namespaceHandle = default(StringHandle); - nameHandle = default(StringHandle); - - if (attributeType.Kind == HandleKind.TypeReference) - { - TypeReference typeRefRow = metadataReader.GetTypeReference((TypeReferenceHandle)attributeType); - HandleKind handleType = typeRefRow.ResolutionScope.Kind; - - // Nested type? - if (handleType == HandleKind.TypeReference || handleType == HandleKind.TypeDefinition) - return false; - - nameHandle = typeRefRow.Name; - namespaceHandle = typeRefRow.Namespace; - return true; - } - else if (attributeType.Kind == HandleKind.TypeDefinition) - { - var def = metadataReader.GetTypeDefinition((TypeDefinitionHandle)attributeType); - - // Nested type? - if (IsNested(def.Attributes)) - return false; - - nameHandle = def.Name; - namespaceHandle = def.Namespace; - return true; - } - else - { - // unsupported metadata - return false; - } - } - - public static PInvokeFlags GetDelegatePInvokeFlags(this EcmaType type) - { - PInvokeFlags flags = new PInvokeFlags(); - - if (!type.IsDelegate) - { - return flags; - } - - var customAttributeValue = type.GetDecodedCustomAttribute( - "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute"); - - if (customAttributeValue == null) - { - return flags; - } - - if (!customAttributeValue.HasValue) - { - return flags; - } - - if (customAttributeValue.Value.FixedArguments.Length == 1) - { - CallingConvention callingConvention = (CallingConvention)customAttributeValue.Value.FixedArguments[0].Value; - - switch (callingConvention) - { - case CallingConvention.StdCall: - flags.UnmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConventionStdCall; - break; - case CallingConvention.Cdecl: - flags.UnmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConventionCdecl; - break; - case CallingConvention.ThisCall: - flags.UnmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConventionThisCall; - break; - case CallingConvention.Winapi: - flags.UnmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConventionStdCall; - break; - } - } - - foreach (var namedArgument in customAttributeValue.Value.NamedArguments) - { - if (namedArgument.Name == "CharSet") - { - flags.CharSet = (CharSet)namedArgument.Value; - } - else if (namedArgument.Name == "BestFitMapping") - { - flags.BestFitMapping = (bool)namedArgument.Value; - } - else if (namedArgument.Name == "SetLastError") - { - flags.SetLastError = (bool)namedArgument.Value; - } - else if (namedArgument.Name == "ThrowOnUnmappableChar") - { - flags.ThrowOnUnmappableChar = (bool)namedArgument.Value; - } - } - return flags; - } - - // This mask is the fastest way to check if a type is nested from its flags, - // but it should not be added to the BCL enum as its semantics can be misleading. - // Consider, for example, that (NestedFamANDAssem & NestedMask) == NestedFamORAssem. - // Only comparison of the masked value to 0 is meaningful, which is different from - // the other masks in the enum. - private const TypeAttributes NestedMask = (TypeAttributes)0x00000006; - - public static bool IsNested(this TypeAttributes flags) - { - return (flags & NestedMask) != 0; - } - - public static bool IsRuntimeSpecialName(this MethodAttributes flags) - { - return (flags & (MethodAttributes.SpecialName | MethodAttributes.RTSpecialName)) - == (MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); - } - - public static bool IsPublic(this MethodAttributes flags) - { - return (flags & MethodAttributes.MemberAccessMask) == MethodAttributes.Public; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/PrimitiveTypeProvider.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/PrimitiveTypeProvider.cs deleted file mode 100644 index ff9bea5afb7..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/PrimitiveTypeProvider.cs +++ /dev/null @@ -1,79 +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 System.Reflection.Metadata; - -namespace Internal.TypeSystem.Ecma -{ - public static class PrimitiveTypeProvider - { - public static TypeDesc GetPrimitiveType(TypeSystemContext context, PrimitiveTypeCode typeCode) - { - WellKnownType wkt; - - switch (typeCode) - { - case PrimitiveTypeCode.Boolean: - wkt = WellKnownType.Boolean; - break; - case PrimitiveTypeCode.Byte: - wkt = WellKnownType.Byte; - break; - case PrimitiveTypeCode.Char: - wkt = WellKnownType.Char; - break; - case PrimitiveTypeCode.Double: - wkt = WellKnownType.Double; - break; - case PrimitiveTypeCode.Int16: - wkt = WellKnownType.Int16; - break; - case PrimitiveTypeCode.Int32: - wkt = WellKnownType.Int32; - break; - case PrimitiveTypeCode.Int64: - wkt = WellKnownType.Int64; - break; - case PrimitiveTypeCode.IntPtr: - wkt = WellKnownType.IntPtr; - break; - case PrimitiveTypeCode.Object: - wkt = WellKnownType.Object; - break; - case PrimitiveTypeCode.SByte: - wkt = WellKnownType.SByte; - break; - case PrimitiveTypeCode.Single: - wkt = WellKnownType.Single; - break; - case PrimitiveTypeCode.String: - wkt = WellKnownType.String; - break; - case PrimitiveTypeCode.UInt16: - wkt = WellKnownType.UInt16; - break; - case PrimitiveTypeCode.UInt32: - wkt = WellKnownType.UInt32; - break; - case PrimitiveTypeCode.UInt64: - wkt = WellKnownType.UInt64; - break; - case PrimitiveTypeCode.UIntPtr: - wkt = WellKnownType.UIntPtr; - break; - case PrimitiveTypeCode.Void: - wkt = WellKnownType.Void; - break; - case PrimitiveTypeCode.TypedReference: - wkt = WellKnownType.TypedReference; - break; - default: - throw new BadImageFormatException(); - } - - return context.GetWellKnownType(wkt); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/PdbSymbolReader.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/PdbSymbolReader.cs deleted file mode 100644 index c35c1490a1e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/PdbSymbolReader.cs +++ /dev/null @@ -1,21 +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 System.Collections.Generic; - -using Internal.IL; - -namespace Internal.TypeSystem.Ecma -{ - /// - /// Abstraction for reading Pdb files - /// - public abstract class PdbSymbolReader : IDisposable - { - public abstract IEnumerable GetSequencePointsForMethod(int methodToken); - public abstract IEnumerable GetLocalVariableNamesForMethod(int methodToken); - public abstract void Dispose(); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/PortablePdbSymbolReader.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/PortablePdbSymbolReader.cs deleted file mode 100644 index 4faecf8a7c3..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/PortablePdbSymbolReader.cs +++ /dev/null @@ -1,154 +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 System.Collections.Generic; -using System.IO; -using System.IO.MemoryMappedFiles; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; - -using Internal.IL; - -namespace Internal.TypeSystem.Ecma -{ - /// - /// Provides PdbSymbolReader for portable PDB via System.Reflection.Metadata - /// - public sealed class PortablePdbSymbolReader : PdbSymbolReader - { - private static unsafe MetadataReader TryOpenMetadataFile(string filePath, MetadataStringDecoder stringDecoder, out MemoryMappedViewAccessor mappedViewAccessor) - { - FileStream fileStream = null; - MemoryMappedFile mappedFile = null; - MemoryMappedViewAccessor accessor = null; - try - { - // Create stream because CreateFromFile(string, ...) uses FileShare.None which is too strict - fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false); - mappedFile = MemoryMappedFile.CreateFromFile( - fileStream, null, fileStream.Length, MemoryMappedFileAccess.Read, HandleInheritability.None, true); - - accessor = mappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); - - var safeBuffer = accessor.SafeMemoryMappedViewHandle; - - // Check whether this is a real metadata file to avoid thrown and caught exceptions - // for non-portable .pdbs - if (safeBuffer.Read(0) != 'B' || // COR20MetadataSignature - safeBuffer.Read(1) != 'S' || - safeBuffer.Read(2) != 'J' || - safeBuffer.Read(3) != 'B') - { - mappedViewAccessor = null; - return null; - } - - var metadataReader = new MetadataReader((byte*)safeBuffer.DangerousGetHandle(), (int)safeBuffer.ByteLength, MetadataReaderOptions.Default, stringDecoder); - - // MemoryMappedFile does not need to be kept around. MemoryMappedViewAccessor is enough. - - mappedViewAccessor = accessor; - accessor = null; - - return metadataReader; - } - finally - { - if (accessor != null) - accessor.Dispose(); - if (mappedFile != null) - mappedFile.Dispose(); - if (fileStream != null) - fileStream.Dispose(); - } - } - - public static PdbSymbolReader TryOpen(string pdbFilename, MetadataStringDecoder stringDecoder) - { - MemoryMappedViewAccessor mappedViewAccessor; - MetadataReader reader = TryOpenMetadataFile(pdbFilename, stringDecoder, out mappedViewAccessor); - if (reader == null) - return null; - - return new PortablePdbSymbolReader(reader, mappedViewAccessor); - } - - private MetadataReader _reader; - private MemoryMappedViewAccessor _mappedViewAccessor; - - private PortablePdbSymbolReader(MetadataReader reader, MemoryMappedViewAccessor mappedViewAccessor) - { - _reader = reader; - _mappedViewAccessor = mappedViewAccessor; - } - - public override void Dispose() - { - _mappedViewAccessor.Dispose(); - } - - public override IEnumerable GetSequencePointsForMethod(int methodToken) - { - var debugInformationHandle = ((MethodDefinitionHandle)MetadataTokens.EntityHandle(methodToken)).ToDebugInformationHandle(); - - var debugInformation = _reader.GetMethodDebugInformation(debugInformationHandle); - - var sequencePoints = debugInformation.GetSequencePoints(); - - foreach (var sequencePoint in sequencePoints) - { - if (sequencePoint.StartLine == 0xFEEFEE) - continue; - - var url = _reader.GetString(_reader.GetDocument(sequencePoint.Document).Name); - - yield return new ILSequencePoint(sequencePoint.Offset, url, sequencePoint.StartLine); - } - } - - // - // Gather the local details in a scope and then recurse to child scopes - // - private void ProbeScopeForLocals(List variables, LocalScopeHandle localScopeHandle) - { - var localScope = _reader.GetLocalScope(localScopeHandle); - - foreach (var localVariableHandle in localScope.GetLocalVariables()) - { - var localVariable = _reader.GetLocalVariable(localVariableHandle); - - var name = _reader.GetString(localVariable.Name); - bool compilerGenerated = (localVariable.Attributes & LocalVariableAttributes.DebuggerHidden) != 0; - - variables.Add(new ILLocalVariable(localVariable.Index, name, compilerGenerated)); - } - - var children = localScope.GetChildren(); - while (children.MoveNext()) - { - ProbeScopeForLocals(variables, children.Current); - } - } - - // - // Recursively scan the scopes for a method stored in a PDB and gather the local slots - // and names for all of them. This assumes a CSC-like compiler that doesn't re-use - // local slots in the same method across scopes. - // - public override IEnumerable GetLocalVariableNamesForMethod(int methodToken) - { - var debugInformationHandle = MetadataTokens.MethodDefinitionHandle(methodToken).ToDebugInformationHandle(); - - var localScopes = _reader.GetLocalScopes(debugInformationHandle); - - var variables = new List(); - foreach (var localScopeHandle in localScopes) - { - ProbeScopeForLocals(variables, localScopeHandle); - } - return variables; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/UnmanagedPdbSymbolReader.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/UnmanagedPdbSymbolReader.cs deleted file mode 100644 index 5dc82b12ad6..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/SymbolReader/UnmanagedPdbSymbolReader.cs +++ /dev/null @@ -1,283 +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 System.Collections.Generic; -using System.Runtime.InteropServices; - -using Microsoft.DiaSymReader; - -using Internal.IL; - -namespace Internal.TypeSystem.Ecma -{ - /// - /// Provides PdbSymbolReader via unmanaged SymBinder from full .NET Framework - /// - public sealed class UnmanagedPdbSymbolReader : PdbSymbolReader - { - [DllImport("mscoree.dll")] - private static extern int CLRCreateInstance([In] ref Guid clsid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out ICLRMetaHost ppInterface); - - [Guid("d332db9e-b9b3-4125-8207-a14884f53216")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [ComVisible(true)] - interface ICLRMetaHost - { - [PreserveSig] - int GetRuntime([In, MarshalAs(UnmanagedType.LPWStr)] String pwzVersion, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out ICLRRuntimeInfo ppRuntime); - - // Don't need any other methods. - } - - [Guid("bd39d1d2-ba2f-486a-89b0-b4b0cb466891")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [ComVisible(true)] - interface ICLRRuntimeInfo - { - void GetVersionString_Placeholder(); - void GetRuntimeDirectory_Placeholder(); - void IsLoaded_Placeholder(); - void LoadErrorString_Placeholder(); - void LoadLibrary_Placeholder(); - void GetProcAddress_Placeholder(); - - [PreserveSig] - int GetInterface([In] ref Guid rclsid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out Object ppUnk); - - void IsLoadable_Placeholder(); - void SetDefaultStartupFlags_Placeholder(); - void GetDefaultStartupFlags_Placeholder(); - - [PreserveSig] - int BindAsLegacyV2Runtime(); - - // Don't need any other methods. - } - - [Guid("809c652e-7396-11d2-9771-00a0c9b4d50c")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [ComVisible(true)] - private interface IMetaDataDispenser - { - void DefineScope_Placeholder(); - - [PreserveSig] - int OpenScope([In, MarshalAs(UnmanagedType.LPWStr)] String szScope, [In] Int32 dwOpenFlags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out Object punk); - - // Don't need any other methods. - } - - [DllImport("ole32.dll")] - private static extern int CoCreateInstance(ref Guid rclsid, IntPtr pUnkOuter, - Int32 dwClsContext, - ref Guid riid, - [MarshalAs(UnmanagedType.Interface)] out object ppv); - - private void ThrowExceptionForHR(int hr) - { - Marshal.ThrowExceptionForHR(hr, new IntPtr(-1)); - } - - static UnmanagedPdbSymbolReader() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - try - { - Guid IID_IUnknown = new Guid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); - - ICLRMetaHost objMetaHost; - Guid CLSID_CLRMetaHost = new Guid(0x9280188d, 0x0e8e, 0x4867, 0xb3, 0x0c, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde); - Guid IID_CLRMetaHost = new Guid(0xd332db9e, 0xb9b3, 0x4125, 0x82, 0x07, 0xa1, 0x48, 0x84, 0xf5, 0x32, 0x16); - if (CLRCreateInstance(ref CLSID_CLRMetaHost, ref IID_CLRMetaHost, out objMetaHost) < 0) - return; - - ICLRRuntimeInfo objRuntime; - Guid IID_CLRRuntimeInfo = new Guid(0xbd39d1d2, 0xba2f, 0x486a, 0x89, 0xb0, 0xb4, 0xb0, 0xcb, 0x46, 0x68, 0x91); - if (objMetaHost.GetRuntime("v4.0.30319", ref IID_CLRRuntimeInfo, out objRuntime) < 0) - return; - - // To get everything from the v4 runtime - objRuntime.BindAsLegacyV2Runtime(); - - // Create a COM Metadata dispenser - object objDispenser; - Guid CLSID_CorMetaDataDispenser = new Guid(0xe5cb7a31, 0x7512, 0x11d2, 0x89, 0xce, 0x00, 0x80, 0xc7, 0x92, 0xe5, 0xd8); - if (objRuntime.GetInterface(ref CLSID_CorMetaDataDispenser, ref IID_IUnknown, out objDispenser) < 0) - return; - s_metadataDispenser = (IMetaDataDispenser)objDispenser; - - // Create a SymBinder - object objBinder; - Guid CLSID_CorSymBinder = new Guid(0x0a29ff9e, 0x7f9c, 0x4437, 0x8b, 0x11, 0xf4, 0x24, 0x49, 0x1e, 0x39, 0x31); - if (CoCreateInstance(ref CLSID_CorSymBinder, - IntPtr.Zero, // pUnkOuter - 1, // CLSCTX_INPROC_SERVER - ref IID_IUnknown, - out objBinder) < 0) - return; - s_symBinder = (ISymUnmanagedBinder)objBinder; - } - catch - { - } - } - } - - private static IMetaDataDispenser s_metadataDispenser; - private static ISymUnmanagedBinder s_symBinder; - - public static PdbSymbolReader TryOpenSymbolReaderForMetadataFile(string metadataFileName, string searchPath) - { - try - { - if (s_metadataDispenser == null || s_symBinder == null) - return null; - - Guid IID_IMetaDataImport = new Guid(0x7dac8207, 0xd3ae, 0x4c75, 0x9b, 0x67, 0x92, 0x80, 0x1a, 0x49, 0x7d, 0x44); - - // Open an metadata importer on the given filename. We'll end up passing this importer straight - // through to the Binder. - object objImporter; - if (s_metadataDispenser.OpenScope(metadataFileName, 0x00000010 /* read only */, ref IID_IMetaDataImport, out objImporter) < 0) - return null; - - ISymUnmanagedReader reader; - if (s_symBinder.GetReaderForFile(objImporter, metadataFileName, searchPath, out reader) < 0) - return null; - - return new UnmanagedPdbSymbolReader(reader); - } - catch - { - return null; - } - } - - private ISymUnmanagedReader _symUnmanagedReader; - - private UnmanagedPdbSymbolReader(ISymUnmanagedReader symUnmanagedReader) - { - _symUnmanagedReader = symUnmanagedReader; - } - - public override void Dispose() - { - Marshal.ReleaseComObject(_symUnmanagedReader); - } - - private Dictionary _urlCache; - - private string GetUrl(ISymUnmanagedDocument doc) - { - lock (this) - { - if (_urlCache == null) - _urlCache = new Dictionary(); - - string url; - if (_urlCache.TryGetValue(doc, out url)) - return url; - - int urlLength; - ThrowExceptionForHR(doc.GetUrl(0, out urlLength, null)); - - // urlLength includes terminating '\0' - char[] urlBuffer = new char[urlLength]; - ThrowExceptionForHR(doc.GetUrl(urlLength, out urlLength, urlBuffer)); - - url = new string(urlBuffer, 0, urlLength - 1); - _urlCache.Add(doc, url); - return url; - } - } - - public override IEnumerable GetSequencePointsForMethod(int methodToken) - { - ISymUnmanagedMethod symbolMethod; - if (_symUnmanagedReader.GetMethod(methodToken, out symbolMethod) < 0) - yield break; - - int count; - ThrowExceptionForHR(symbolMethod.GetSequencePointCount(out count)); - - ISymUnmanagedDocument[] docs = new ISymUnmanagedDocument[count]; - int[] lineNumbers = new int[count]; - int[] ilOffsets = new int[count]; - - ThrowExceptionForHR(symbolMethod.GetSequencePoints(count, out count, ilOffsets, docs, lineNumbers, null, null, null)); - - for (int i = 0; i < count; i++) - { - if (lineNumbers[i] == 0xFEEFEE) - continue; - - yield return new ILSequencePoint(ilOffsets[i], GetUrl(docs[i]), lineNumbers[i]); - } - } - - // - // Gather the local details in a scope and then recurse to child scopes - // - private void ProbeScopeForLocals(List variables, ISymUnmanagedScope scope) - { - int localCount; - ThrowExceptionForHR(scope.GetLocalCount(out localCount)); - - ISymUnmanagedVariable[] locals = new ISymUnmanagedVariable[localCount]; - ThrowExceptionForHR(scope.GetLocals(localCount, out localCount, locals)); - - for (int i = 0; i < localCount; i++) - { - var local = locals[i]; - - int slot; - ThrowExceptionForHR(local.GetAddressField1(out slot)); - - int nameLength; - ThrowExceptionForHR(local.GetName(0, out nameLength, null)); - - // nameLength includes terminating '\0' - char[] nameBuffer = new char[nameLength]; - ThrowExceptionForHR(local.GetName(nameLength, out nameLength, nameBuffer)); - - int attributes; - ThrowExceptionForHR(local.GetAttributes(out attributes)); - - variables.Add(new ILLocalVariable(slot, new String(nameBuffer, 0, nameLength - 1), (attributes & 0x1) != 0)); - } - - int childrenCount; - ThrowExceptionForHR(scope.GetChildren(0, out childrenCount, null)); - - ISymUnmanagedScope[] children = new ISymUnmanagedScope[childrenCount]; - ThrowExceptionForHR(scope.GetChildren(childrenCount, out childrenCount, children)); - - for (int i = 0; i < childrenCount; i++) - { - ProbeScopeForLocals(variables, children[i]); - } - } - - // - // Recursively scan the scopes for a method stored in a PDB and gather the local slots - // and names for all of them. This assumes a CSC-like compiler that doesn't re-use - // local slots in the same method across scopes. - // - public override IEnumerable GetLocalVariableNamesForMethod(int methodToken) - { - ISymUnmanagedMethod symbolMethod; - if (_symUnmanagedReader.GetMethod(methodToken, out symbolMethod) < 0) - return null; - - ISymUnmanagedScope rootScope; - ThrowExceptionForHR(symbolMethod.GetRootScope(out rootScope)); - - var variables = new List(); - ProbeScopeForLocals(variables, rootScope); - return variables; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/EcmaMethodIL.Symbols.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/EcmaMethodIL.Symbols.cs deleted file mode 100644 index 35b7c22e496..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/EcmaMethodIL.Symbols.cs +++ /dev/null @@ -1,75 +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.Collections.Generic; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; - -using Internal.TypeSystem.Ecma; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL -{ - // Pluggable file that adds PDB handling functionality to EcmaMethodIL - partial class EcmaMethodIL - { - public override MethodDebugInformation GetDebugInfo() - { - if (_method.Module.PdbReader != null) - { - return new EcmaMethodDebugInformation(_method); - } - - return MethodDebugInformation.None; - } - } - - /// - /// Represents debugging information about a method backed by ECMA-335 metadata. - /// - public sealed class EcmaMethodDebugInformation : MethodDebugInformation - { - private EcmaMethod _method; - - public EcmaMethodDebugInformation(EcmaMethod method) - { - Debug.Assert(method.Module.PdbReader != null); - _method = method; - } - - public override IEnumerable GetSequencePoints() - { - return _method.Module.PdbReader.GetSequencePointsForMethod(MetadataTokens.GetToken(_method.Handle)); - } - - public override IEnumerable GetLocalVariables() - { - return _method.Module.PdbReader.GetLocalVariableNamesForMethod(MetadataTokens.GetToken(_method.Handle)); - } - - public override IEnumerable GetParameterNames() - { - ParameterHandleCollection parameters = _method.MetadataReader.GetMethodDefinition(_method.Handle).GetParameters(); - - if (!_method.Signature.IsStatic) - { - // TODO: this name might conflict with a parameter name or a local name. We need something unique. - yield return "___this"; - } - - // TODO: The Params table is allowed to have holes in it. This expect all parameters to be present. - foreach (var parameterHandle in parameters) - { - Parameter p = _method.MetadataReader.GetParameter(parameterHandle); - - // Parameter with sequence number 0 refers to the return parameter - if (p.SequenceNumber == 0) - continue; - - yield return _method.MetadataReader.GetString(p.Name); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/EcmaMethodIL.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/EcmaMethodIL.cs deleted file mode 100644 index f15b86762fd..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/EcmaMethodIL.cs +++ /dev/null @@ -1,146 +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 System.Collections.Immutable; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; - -using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; - -namespace Internal.IL -{ - public sealed partial class EcmaMethodIL : MethodIL - { - private readonly EcmaModule _module; - private readonly EcmaMethod _method; - private readonly MethodBodyBlock _methodBody; - - // Cached values - private byte[] _ilBytes; - private LocalVariableDefinition[] _locals; - private ILExceptionRegion[] _ilExceptionRegions; - - // TODO: Remove: Workaround for missing ClearInitLocals transforms in CoreRT CoreLib - private readonly bool _clearInitLocals; - - public static EcmaMethodIL Create(EcmaMethod method, bool clearInitLocals = false) - { - var rva = method.MetadataReader.GetMethodDefinition(method.Handle).RelativeVirtualAddress; - if (rva == 0) - return null; - return new EcmaMethodIL(method, rva, clearInitLocals); - } - - private EcmaMethodIL(EcmaMethod method, int rva, bool clearInitLocals) - { - _method = method; - _module = method.Module; - _methodBody = _module.PEReader.GetMethodBody(rva); - - _clearInitLocals = clearInitLocals; - } - - public EcmaModule Module - { - get - { - return _module; - } - } - - public override MethodDesc OwningMethod - { - get - { - return _method; - } - } - - public override byte[] GetILBytes() - { - if (_ilBytes != null) - return _ilBytes; - - byte[] ilBytes = _methodBody.GetILBytes(); - return (_ilBytes = ilBytes); - } - - public override bool IsInitLocals - { - get - { - return !_clearInitLocals && _methodBody.LocalVariablesInitialized; - } - } - - public override int MaxStack - { - get - { - return _methodBody.MaxStack; - } - } - - public override LocalVariableDefinition[] GetLocals() - { - if (_locals != null) - return _locals; - - var metadataReader = _module.MetadataReader; - var localSignature = _methodBody.LocalSignature; - if (localSignature.IsNil) - return Array.Empty(); - BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetStandaloneSignature(localSignature).Signature); - - EcmaSignatureParser parser = new EcmaSignatureParser(_module, signatureReader); - LocalVariableDefinition[] locals = parser.ParseLocalsSignature(); - return (_locals = locals); - } - - public override ILExceptionRegion[] GetExceptionRegions() - { - if (_ilExceptionRegions != null) - return _ilExceptionRegions; - - ImmutableArray exceptionRegions = _methodBody.ExceptionRegions; - ILExceptionRegion[] ilExceptionRegions; - - int length = exceptionRegions.Length; - if (length == 0) - { - ilExceptionRegions = Array.Empty(); - } - else - { - ilExceptionRegions = new ILExceptionRegion[length]; - for (int i = 0; i < length; i++) - { - var exceptionRegion = exceptionRegions[i]; - - ilExceptionRegions[i] = new ILExceptionRegion( - (ILExceptionRegionKind)exceptionRegion.Kind, // assumes that ILExceptionRegionKind and ExceptionRegionKind enums are in sync - exceptionRegion.TryOffset, - exceptionRegion.TryLength, - exceptionRegion.HandlerOffset, - exceptionRegion.HandlerLength, - MetadataTokens.GetToken(exceptionRegion.CatchType), - exceptionRegion.FilterOffset); - } - } - - return (_ilExceptionRegions = ilExceptionRegions); - } - - public override object GetObject(int token) - { - // UserStrings cannot be wrapped in EntityHandle - if ((token & 0xFF000000) == 0x70000000) - return _module.GetUserString(MetadataTokens.UserStringHandle(token)); - - return _module.GetObject(MetadataTokens.EntityHandle(token)); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/HelperExtensions.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/HelperExtensions.cs deleted file mode 100644 index 682dab4f04b..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/HelperExtensions.cs +++ /dev/null @@ -1,112 +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.TypeSystem; -using Internal.IL.Stubs; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL -{ - internal static class HelperExtensions - { - public static MetadataType GetHelperType(this TypeSystemContext context, string name) - { - MetadataType helperType = context.SystemModule.GetKnownType("Internal.Runtime.CompilerHelpers", name); - return helperType; - } - - public static MethodDesc GetHelperEntryPoint(this TypeSystemContext context, string typeName, string methodName) - { - MetadataType helperType = context.GetHelperType(typeName); - MethodDesc helperMethod = helperType.GetKnownMethod(methodName, null); - return helperMethod; - } - - /// - /// Emits a call to a throw helper. Use this to emit calls to static parameterless methods that don't return. - /// The advantage of using this extension method is that you don't have to deal with what code to emit after - /// the call (e.g. do you need to make sure the stack is balanced?). - /// - public static void EmitCallThrowHelper(this ILCodeStream codeStream, ILEmitter emitter, MethodDesc method) - { - Debug.Assert(method.Signature.Length == 0 && method.Signature.IsStatic); - - // Emit a call followed by a branch to the call. - - // We are emitting this instead of emitting a tight loop that jumps to itself - // so that the JIT doesn't generate extra GC checks within the loop. - - ILCodeLabel label = emitter.NewCodeLabel(); - codeStream.EmitLabel(label); - codeStream.Emit(ILOpcode.call, emitter.NewToken(method)); - codeStream.Emit(ILOpcode.br, label); - } - - /// - /// Retrieves a method on that is well known to the compiler. - /// Throws an exception if the method doesn't exist. - /// - public static MethodDesc GetKnownMethod(this TypeDesc type, string name, MethodSignature signature) - { - MethodDesc method = type.GetMethod(name, signature); - if (method == null) - { - throw new InvalidOperationException(String.Format("Expected method '{0}' not found on type '{1}'", name, type)); - } - - return method; - } - - /// - /// Retrieves a field on that is well known to the compiler. - /// Throws an exception if the field doesn't exist. - /// - public static FieldDesc GetKnownField(this TypeDesc type, string name) - { - FieldDesc field = type.GetField(name); - if (field == null) - { - throw new InvalidOperationException(String.Format("Expected field '{0}' not found on type '{1}'", name, type)); - } - - return field; - } - - /// - /// Retrieves a nested type on that is well known to the compiler. - /// Throws an exception if the nested type doesn't exist. - /// - 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; - } - - /// - /// Retrieves a namespace type in that is well known to the compiler. - /// Throws an exception if the type doesn't exist. - /// - public static MetadataType GetKnownType(this ModuleDesc module, string @namespace, string name) - { - MetadataType type = module.GetType(@namespace, name, false); - if (type == null) - { - throw new InvalidOperationException( - String.Format("Expected type '{0}' not found in module '{1}'", - @namespace.Length > 0 ? String.Concat(@namespace, ".", name) : name, - module)); - } - - return type; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILDisassembler.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILDisassembler.cs deleted file mode 100644 index c7fb70f6e8e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILDisassembler.cs +++ /dev/null @@ -1,633 +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 System.Text; - -using Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL -{ - // Known shortcomings: - // - Escaping identifier names is missing (special characters and ILASM identifier names) - // - Array bounds in signatures missing - // - Custom modifiers and PINNED constraint not decoded in signatures - // - Calling conventions in signatures not decoded - // - Vararg signatures - // - Floating point numbers are not represented in roundtrippable format - - /// - /// Helper struct to disassemble IL instructions into a textual representation. - /// - public struct ILDisassembler - { - private byte[] _ilBytes; - private MethodIL _methodIL; - private ILTypeNameFormatter _typeNameFormatter; - private int _currentOffset; - - public ILDisassembler(MethodIL methodIL) - { - _methodIL = methodIL; - _ilBytes = methodIL.GetILBytes(); - _currentOffset = 0; - _typeNameFormatter = null; - } - - #region Type/member/signature name formatting - private ILTypeNameFormatter TypeNameFormatter - { - get - { - if (_typeNameFormatter == null) - { - // Find the owning module so that the type name formatter can remove - // redundant assembly name qualifiers in type names. - TypeDesc owningTypeDefinition = _methodIL.OwningMethod.OwningType; - ModuleDesc owningModule = owningTypeDefinition is MetadataType ? - ((MetadataType)owningTypeDefinition).Module : null; - - _typeNameFormatter = new ILTypeNameFormatter(owningModule); - } - return _typeNameFormatter; - } - } - - public void AppendType(StringBuilder sb, TypeDesc type, bool forceValueClassPrefix = true) - { - // Types referenced from the IL show as instantiated over generic parameter. - // E.g. "initobj !0" becomes "initobj !T" - TypeDesc typeInContext = type.InstantiateSignature( - _methodIL.OwningMethod.OwningType.Instantiation, _methodIL.OwningMethod.Instantiation); - if (typeInContext.HasInstantiation || forceValueClassPrefix) - this.TypeNameFormatter.AppendNameWithValueClassPrefix(sb, typeInContext); - else - this.TypeNameFormatter.AppendName(sb, typeInContext); - } - - private void AppendOwningType(StringBuilder sb, TypeDesc type) - { - // Special case primitive types: we don't want to use short names here - if (type.IsPrimitive || type.IsString || type.IsObject) - _typeNameFormatter.AppendNameForNamespaceTypeWithoutAliases(sb, (MetadataType)type); - else - AppendType(sb, type, false); - } - - private void AppendMethodSignature(StringBuilder sb, MethodDesc method) - { - // If this is an instantiated generic method, the formatted signature should - // be uninstantiated (e.g. "void Foo::Bar(!!0 param)", not "void Foo::Bar(int param)") - MethodSignature signature = method.GetMethodDefinition().Signature; - - AppendSignaturePrefix(sb, signature); - sb.Append(' '); - AppendOwningType(sb, method.OwningType); - sb.Append("::"); - sb.Append(method.Name); - - if (method.HasInstantiation) - { - sb.Append('<'); - - for (int i = 0; i < method.Instantiation.Length; i++) - { - if (i != 0) - sb.Append(", "); - _typeNameFormatter.AppendNameWithValueClassPrefix(sb, method.Instantiation[i]); - } - - sb.Append('>'); - } - - sb.Append('('); - AppendSignatureArgumentList(sb, signature); - sb.Append(')'); - } - - private void AppendMethodSignature(StringBuilder sb, MethodSignature signature) - { - AppendSignaturePrefix(sb, signature); - sb.Append('('); - AppendSignatureArgumentList(sb, signature); - sb.Append(')'); - } - - private void AppendSignaturePrefix(StringBuilder sb, MethodSignature signature) - { - if (!signature.IsStatic) - sb.Append("instance "); - - this.TypeNameFormatter.AppendNameWithValueClassPrefix(sb, signature.ReturnType); - } - - private void AppendSignatureArgumentList(StringBuilder sb, MethodSignature signature) - { - for (int i = 0; i < signature.Length; i++) - { - if (i != 0) - sb.Append(", "); - - this.TypeNameFormatter.AppendNameWithValueClassPrefix(sb, signature[i]); - } - } - - private void AppendFieldSignature(StringBuilder sb, FieldDesc field) - { - this.TypeNameFormatter.AppendNameWithValueClassPrefix(sb, field.FieldType); - sb.Append(' '); - AppendOwningType(sb, field.OwningType); - sb.Append("::"); - sb.Append(field.Name); - } - - private void AppendStringLiteral(StringBuilder sb, string s) - { - sb.Append('"'); - for (int i = 0; i < s.Length; i++) - { - if (s[i] == '\\') - sb.Append("\\\\"); - else if (s[i] == '\t') - sb.Append("\\t"); - else if (s[i] == '"') - sb.Append("\\\""); - else if (s[i] == '\n') - sb.Append("\\n"); - else - sb.Append(s[i]); - } - sb.Append('"'); - } - - private void AppendToken(StringBuilder sb, int token) - { - object obj = _methodIL.GetObject(token); - if (obj is MethodDesc) - AppendMethodSignature(sb, (MethodDesc)obj); - else if (obj is FieldDesc) - AppendFieldSignature(sb, (FieldDesc)obj); - else if (obj is MethodSignature) - AppendMethodSignature(sb, (MethodSignature)obj); - else if (obj is TypeDesc) - AppendType(sb, (TypeDesc)obj, false); - else - { - Debug.Assert(obj is string, "NYI: " + obj.GetType()); - AppendStringLiteral(sb, (string)obj); - } - } - #endregion - - #region Instruction decoding - private byte ReadILByte() - { - return _ilBytes[_currentOffset++]; - } - - private UInt16 ReadILUInt16() - { - UInt16 val = (UInt16)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8)); - _currentOffset += 2; - return val; - } - - private UInt32 ReadILUInt32() - { - UInt32 val = (UInt32)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8) + (_ilBytes[_currentOffset + 2] << 16) + (_ilBytes[_currentOffset + 3] << 24)); - _currentOffset += 4; - return val; - } - - private int ReadILToken() - { - return (int)ReadILUInt32(); - } - - private ulong ReadILUInt64() - { - ulong value = ReadILUInt32(); - value |= (((ulong)ReadILUInt32()) << 32); - return value; - } - - private unsafe float ReadILFloat() - { - uint value = ReadILUInt32(); - return *(float*)(&value); - } - - private unsafe double ReadILDouble() - { - ulong value = ReadILUInt64(); - return *(double*)(&value); - } - - public static void AppendOffset(StringBuilder sb, int offset) - { - sb.Append("IL_"); - sb.AppendFormat("{0:X4}", offset); - } - - private static void PadForInstructionArgument(StringBuilder sb) - { - if (sb.Length < 22) - sb.Append(' ', 22 - sb.Length); - else - sb.Append(' '); - } - - public bool HasNextInstruction - { - get - { - return _currentOffset < _ilBytes.Length; - } - } - - public int Offset - { - get - { - return _currentOffset; - } - } - - public int CodeSize - { - get - { - return _ilBytes.Length; - } - } - - public string GetNextInstruction() - { - StringBuilder decodedInstruction = new StringBuilder(); - AppendOffset(decodedInstruction, _currentOffset); - decodedInstruction.Append(": "); - - again: - - ILOpcode opCode = (ILOpcode)ReadILByte(); - if (opCode == ILOpcode.prefix1) - { - opCode = (ILOpcode)(0x100 + ReadILByte()); - } - - // Quick and dirty way to get the opcode name is to convert the enum value to string. - // We need some adjustments though. - string opCodeString = opCode.ToString().Replace("_", "."); - if (opCodeString.EndsWith(".")) - opCodeString = opCodeString.Substring(0, opCodeString.Length - 1); - - decodedInstruction.Append(opCodeString); - - switch (opCode) - { - case ILOpcode.ldarg_s: - case ILOpcode.ldarga_s: - case ILOpcode.starg_s: - case ILOpcode.ldloc_s: - case ILOpcode.ldloca_s: - case ILOpcode.stloc_s: - case ILOpcode.ldc_i4_s: - PadForInstructionArgument(decodedInstruction); - decodedInstruction.Append(ReadILByte().ToStringInvariant()); - return decodedInstruction.ToString(); - - case ILOpcode.unaligned: - decodedInstruction.Append(' '); - decodedInstruction.Append(ReadILByte().ToStringInvariant()); - decodedInstruction.Append(' '); - goto again; - - case ILOpcode.ldarg: - case ILOpcode.ldarga: - case ILOpcode.starg: - case ILOpcode.ldloc: - case ILOpcode.ldloca: - case ILOpcode.stloc: - PadForInstructionArgument(decodedInstruction); - decodedInstruction.Append(ReadILUInt16().ToStringInvariant()); - return decodedInstruction.ToString(); - - case ILOpcode.ldc_i4: - PadForInstructionArgument(decodedInstruction); - decodedInstruction.Append(ReadILUInt32().ToStringInvariant()); - return decodedInstruction.ToString(); - - case ILOpcode.ldc_r4: - PadForInstructionArgument(decodedInstruction); - decodedInstruction.Append(ReadILFloat().ToStringInvariant()); - return decodedInstruction.ToString(); - - case ILOpcode.ldc_i8: - PadForInstructionArgument(decodedInstruction); - decodedInstruction.Append(ReadILUInt64().ToStringInvariant()); - return decodedInstruction.ToString(); - - case ILOpcode.ldc_r8: - PadForInstructionArgument(decodedInstruction); - decodedInstruction.Append(ReadILDouble().ToStringInvariant()); - return decodedInstruction.ToString(); - - case ILOpcode.jmp: - case ILOpcode.call: - case ILOpcode.calli: - case ILOpcode.callvirt: - case ILOpcode.cpobj: - case ILOpcode.ldobj: - case ILOpcode.ldstr: - case ILOpcode.newobj: - case ILOpcode.castclass: - case ILOpcode.isinst: - case ILOpcode.unbox: - case ILOpcode.ldfld: - case ILOpcode.ldflda: - case ILOpcode.stfld: - case ILOpcode.ldsfld: - case ILOpcode.ldsflda: - case ILOpcode.stsfld: - case ILOpcode.stobj: - case ILOpcode.box: - case ILOpcode.newarr: - case ILOpcode.ldelema: - case ILOpcode.ldelem: - case ILOpcode.stelem: - case ILOpcode.unbox_any: - case ILOpcode.refanyval: - case ILOpcode.mkrefany: - case ILOpcode.ldtoken: - case ILOpcode.ldftn: - case ILOpcode.ldvirtftn: - case ILOpcode.initobj: - case ILOpcode.constrained: - case ILOpcode.sizeof_: - PadForInstructionArgument(decodedInstruction); - AppendToken(decodedInstruction, ReadILToken()); - return decodedInstruction.ToString(); - - case ILOpcode.br_s: - case ILOpcode.leave_s: - case ILOpcode.brfalse_s: - case ILOpcode.brtrue_s: - case ILOpcode.beq_s: - case ILOpcode.bge_s: - case ILOpcode.bgt_s: - case ILOpcode.ble_s: - case ILOpcode.blt_s: - case ILOpcode.bne_un_s: - case ILOpcode.bge_un_s: - case ILOpcode.bgt_un_s: - case ILOpcode.ble_un_s: - case ILOpcode.blt_un_s: - PadForInstructionArgument(decodedInstruction); - AppendOffset(decodedInstruction, (sbyte)ReadILByte() + _currentOffset); - return decodedInstruction.ToString(); - - case ILOpcode.br: - case ILOpcode.leave: - case ILOpcode.brfalse: - case ILOpcode.brtrue: - case ILOpcode.beq: - case ILOpcode.bge: - case ILOpcode.bgt: - case ILOpcode.ble: - case ILOpcode.blt: - case ILOpcode.bne_un: - case ILOpcode.bge_un: - case ILOpcode.bgt_un: - case ILOpcode.ble_un: - case ILOpcode.blt_un: - PadForInstructionArgument(decodedInstruction); - AppendOffset(decodedInstruction, (int)ReadILUInt32() + _currentOffset); - return decodedInstruction.ToString(); - - case ILOpcode.switch_: - { - decodedInstruction.Clear(); - decodedInstruction.Append("switch ("); - uint count = ReadILUInt32(); - int jmpBase = _currentOffset + (int)(4 * count); - for (uint i = 0; i < count; i++) - { - if (i != 0) - decodedInstruction.Append(", "); - int delta = (int)ReadILUInt32(); - AppendOffset(decodedInstruction, jmpBase + delta); - } - decodedInstruction.Append(")"); - return decodedInstruction.ToString(); - } - - default: - return decodedInstruction.ToString(); - } - } - #endregion - - #region Helpers - public class ILTypeNameFormatter : TypeNameFormatter - { - private ModuleDesc _thisModule; - - public ILTypeNameFormatter(ModuleDesc thisModule) - { - _thisModule = thisModule; - } - - public void AppendNameWithValueClassPrefix(StringBuilder sb, TypeDesc type) - { - if (!type.IsSignatureVariable - && type.IsDefType - && !type.IsPrimitive - && !type.IsObject - && !type.IsString) - { - string prefix = type.IsValueType ? "valuetype " : "class "; - sb.Append(prefix); - AppendName(sb, type); - } - else - { - AppendName(sb, type); - } - } - - public override void AppendName(StringBuilder sb, PointerType type) - { - AppendNameWithValueClassPrefix(sb, type.ParameterType); - sb.Append('*'); - } - - public override void AppendName(StringBuilder sb, FunctionPointerType type) - { - MethodSignature signature = type.Signature; - - sb.Append("method "); - - if (!signature.IsStatic) - sb.Append("instance "); - - // TODO: rest of calling conventions - - AppendName(sb, signature.ReturnType); - - sb.Append(" *("); - for (int i = 0; i < signature.Length; i++) - { - if (i > 0) - sb.Append(", "); - AppendName(sb, signature[i]); - } - sb.Append(')'); - } - - public override void AppendName(StringBuilder sb, SignatureMethodVariable type) - { - sb.Append("!!"); - sb.Append(type.Index.ToStringInvariant()); - } - - public override void AppendName(StringBuilder sb, SignatureTypeVariable type) - { - sb.Append("!"); - sb.Append(type.Index.ToStringInvariant()); - } - - public override void AppendName(StringBuilder sb, GenericParameterDesc type) - { - string prefix = type.Kind == GenericParameterKind.Type ? "!" : "!!"; - sb.Append(prefix); - sb.Append(type.Name); - } - - protected override void AppendNameForInstantiatedType(StringBuilder sb, DefType type) - { - AppendName(sb, type.GetTypeDefinition()); - sb.Append('<'); - - for (int i = 0; i < type.Instantiation.Length; i++) - { - if (i > 0) - sb.Append(", "); - AppendNameWithValueClassPrefix(sb, type.Instantiation[i]); - } - - sb.Append('>'); - } - - public override void AppendName(StringBuilder sb, ByRefType type) - { - AppendNameWithValueClassPrefix(sb, type.ParameterType); - sb.Append('&'); - } - - public override void AppendName(StringBuilder sb, ArrayType type) - { - AppendNameWithValueClassPrefix(sb, type.ElementType); - sb.Append('['); - sb.Append(',', type.Rank - 1); - sb.Append(']'); - } - - protected override void AppendNameForNamespaceType(StringBuilder sb, DefType type) - { - switch (type.Category) - { - case TypeFlags.Void: - sb.Append("void"); - return; - case TypeFlags.Boolean: - sb.Append("bool"); - return; - case TypeFlags.Char: - sb.Append("char"); - return; - case TypeFlags.SByte: - sb.Append("int8"); - return; - case TypeFlags.Byte: - sb.Append("uint8"); - return; - case TypeFlags.Int16: - sb.Append("int16"); - return; - case TypeFlags.UInt16: - sb.Append("uint16"); - return; - case TypeFlags.Int32: - sb.Append("int32"); - return; - case TypeFlags.UInt32: - sb.Append("uint32"); - return; - case TypeFlags.Int64: - sb.Append("int64"); - return; - case TypeFlags.UInt64: - sb.Append("uint64"); - return; - case TypeFlags.IntPtr: - sb.Append("native int"); - return; - case TypeFlags.UIntPtr: - sb.Append("native uint"); - return; - case TypeFlags.Single: - sb.Append("float32"); - return; - case TypeFlags.Double: - sb.Append("float64"); - return; - } - - if (type.IsString) - { - sb.Append("string"); - return; - } - - if (type.IsObject) - { - sb.Append("object"); - return; - } - - AppendNameForNamespaceTypeWithoutAliases(sb, type); - } - public void AppendNameForNamespaceTypeWithoutAliases(StringBuilder sb, DefType type) - { - ModuleDesc owningModule = (type as MetadataType)?.Module; - if (owningModule != null && owningModule != _thisModule) - { - Debug.Assert(owningModule is IAssemblyDesc); - string owningModuleName = ((IAssemblyDesc)owningModule).GetName().Name; - sb.Append('['); - sb.Append(owningModuleName); - sb.Append(']'); - } - - string ns = type.Namespace; - if (ns.Length > 0) - { - sb.Append(ns); - sb.Append('.'); - } - sb.Append(type.Name); - } - - protected override void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType) - { - AppendName(sb, containingType); - sb.Append('/'); - sb.Append(nestedType.Name); - } - } - #endregion - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILOpcode.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILOpcode.cs deleted file mode 100644 index e031553f537..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILOpcode.cs +++ /dev/null @@ -1,235 +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; - -namespace Internal.IL -{ - /// - /// An enumeration of all of the operation codes that are used in the CLI Common Intermediate Language. - /// - public enum ILOpcode - { - nop = 0x00, - break_ = 0x01, - ldarg_0 = 0x02, - ldarg_1 = 0x03, - ldarg_2 = 0x04, - ldarg_3 = 0x05, - ldloc_0 = 0x06, - ldloc_1 = 0x07, - ldloc_2 = 0x08, - ldloc_3 = 0x09, - stloc_0 = 0x0a, - stloc_1 = 0x0b, - stloc_2 = 0x0c, - stloc_3 = 0x0d, - ldarg_s = 0x0e, - ldarga_s = 0x0f, - starg_s = 0x10, - ldloc_s = 0x11, - ldloca_s = 0x12, - stloc_s = 0x13, - ldnull = 0x14, - ldc_i4_m1 = 0x15, - ldc_i4_0 = 0x16, - ldc_i4_1 = 0x17, - ldc_i4_2 = 0x18, - ldc_i4_3 = 0x19, - ldc_i4_4 = 0x1a, - ldc_i4_5 = 0x1b, - ldc_i4_6 = 0x1c, - ldc_i4_7 = 0x1d, - ldc_i4_8 = 0x1e, - ldc_i4_s = 0x1f, - ldc_i4 = 0x20, - ldc_i8 = 0x21, - ldc_r4 = 0x22, - ldc_r8 = 0x23, - dup = 0x25, - pop = 0x26, - jmp = 0x27, - call = 0x28, - calli = 0x29, - ret = 0x2a, - br_s = 0x2b, - brfalse_s = 0x2c, - brtrue_s = 0x2d, - beq_s = 0x2e, - bge_s = 0x2f, - bgt_s = 0x30, - ble_s = 0x31, - blt_s = 0x32, - bne_un_s = 0x33, - bge_un_s = 0x34, - bgt_un_s = 0x35, - ble_un_s = 0x36, - blt_un_s = 0x37, - br = 0x38, - brfalse = 0x39, - brtrue = 0x3a, - beq = 0x3b, - bge = 0x3c, - bgt = 0x3d, - ble = 0x3e, - blt = 0x3f, - bne_un = 0x40, - bge_un = 0x41, - bgt_un = 0x42, - ble_un = 0x43, - blt_un = 0x44, - switch_ = 0x45, - ldind_i1 = 0x46, - ldind_u1 = 0x47, - ldind_i2 = 0x48, - ldind_u2 = 0x49, - ldind_i4 = 0x4a, - ldind_u4 = 0x4b, - ldind_i8 = 0x4c, - ldind_i = 0x4d, - ldind_r4 = 0x4e, - ldind_r8 = 0x4f, - ldind_ref = 0x50, - stind_ref = 0x51, - stind_i1 = 0x52, - stind_i2 = 0x53, - stind_i4 = 0x54, - stind_i8 = 0x55, - stind_r4 = 0x56, - stind_r8 = 0x57, - add = 0x58, - sub = 0x59, - mul = 0x5a, - div = 0x5b, - div_un = 0x5c, - rem = 0x5d, - rem_un = 0x5e, - and = 0x5f, - or = 0x60, - xor = 0x61, - shl = 0x62, - shr = 0x63, - shr_un = 0x64, - neg = 0x65, - not = 0x66, - conv_i1 = 0x67, - conv_i2 = 0x68, - conv_i4 = 0x69, - conv_i8 = 0x6a, - conv_r4 = 0x6b, - conv_r8 = 0x6c, - conv_u4 = 0x6d, - conv_u8 = 0x6e, - callvirt = 0x6f, - cpobj = 0x70, - ldobj = 0x71, - ldstr = 0x72, - newobj = 0x73, - castclass = 0x74, - isinst = 0x75, - conv_r_un = 0x76, - unbox = 0x79, - throw_ = 0x7a, - ldfld = 0x7b, - ldflda = 0x7c, - stfld = 0x7d, - ldsfld = 0x7e, - ldsflda = 0x7f, - stsfld = 0x80, - stobj = 0x81, - conv_ovf_i1_un = 0x82, - conv_ovf_i2_un = 0x83, - conv_ovf_i4_un = 0x84, - conv_ovf_i8_un = 0x85, - conv_ovf_u1_un = 0x86, - conv_ovf_u2_un = 0x87, - conv_ovf_u4_un = 0x88, - conv_ovf_u8_un = 0x89, - conv_ovf_i_un = 0x8a, - conv_ovf_u_un = 0x8b, - box = 0x8c, - newarr = 0x8d, - ldlen = 0x8e, - ldelema = 0x8f, - ldelem_i1 = 0x90, - ldelem_u1 = 0x91, - ldelem_i2 = 0x92, - ldelem_u2 = 0x93, - ldelem_i4 = 0x94, - ldelem_u4 = 0x95, - ldelem_i8 = 0x96, - ldelem_i = 0x97, - ldelem_r4 = 0x98, - ldelem_r8 = 0x99, - ldelem_ref = 0x9a, - stelem_i = 0x9b, - stelem_i1 = 0x9c, - stelem_i2 = 0x9d, - stelem_i4 = 0x9e, - stelem_i8 = 0x9f, - stelem_r4 = 0xa0, - stelem_r8 = 0xa1, - stelem_ref = 0xa2, - ldelem = 0xa3, - stelem = 0xa4, - unbox_any = 0xa5, - conv_ovf_i1 = 0xb3, - conv_ovf_u1 = 0xb4, - conv_ovf_i2 = 0xb5, - conv_ovf_u2 = 0xb6, - conv_ovf_i4 = 0xb7, - conv_ovf_u4 = 0xb8, - conv_ovf_i8 = 0xb9, - conv_ovf_u8 = 0xba, - refanyval = 0xc2, - ckfinite = 0xc3, - mkrefany = 0xc6, - ldtoken = 0xd0, - conv_u2 = 0xd1, - conv_u1 = 0xd2, - conv_i = 0xd3, - conv_ovf_i = 0xd4, - conv_ovf_u = 0xd5, - add_ovf = 0xd6, - add_ovf_un = 0xd7, - mul_ovf = 0xd8, - mul_ovf_un = 0xd9, - sub_ovf = 0xda, - sub_ovf_un = 0xdb, - endfinally = 0xdc, - leave = 0xdd, - leave_s = 0xde, - stind_i = 0xdf, - conv_u = 0xe0, - prefix1 = 0xfe, - arglist = 0x100, - ceq = 0x101, - cgt = 0x102, - cgt_un = 0x103, - clt = 0x104, - clt_un = 0x105, - ldftn = 0x106, - ldvirtftn = 0x107, - ldarg = 0x109, - ldarga = 0x10a, - starg = 0x10b, - ldloc = 0x10c, - ldloca = 0x10d, - stloc = 0x10e, - localloc = 0x10f, - endfilter = 0x111, - unaligned = 0x112, - volatile_ = 0x113, - tail = 0x114, - initobj = 0x115, - constrained = 0x116, - cpblk = 0x117, - initblk = 0x118, - no = 0x119, - rethrow = 0x11a, - sizeof_ = 0x11c, - refanytype = 0x11d, - readonly_ = 0x11e, - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILOpcodeHelper.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILOpcodeHelper.cs deleted file mode 100644 index b051e205f08..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILOpcodeHelper.cs +++ /dev/null @@ -1,328 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.IL -{ - public static class ILOpcodeHelper - { - private const byte VariableSize = 0xFF; - private const byte Invalid = 0xFE; - - /// - /// Gets the size, in bytes, of the opcode and its arguments. - /// Note: if '' is , - /// the caller must handle it differently as that opcode is variable sized. - /// - public static int GetSize(this ILOpcode opcode) - { - Debug.Assert((uint)opcode < (uint)s_opcodeSizes.Length); - byte result = s_opcodeSizes[(int)opcode]; - Debug.Assert(result != VariableSize); - Debug.Assert(result != Invalid); - return result; - } - - /// - /// Returns true if '' is a valid opcode. - /// - public static bool IsValid(this ILOpcode opcode) - { - return (uint)opcode < (uint)s_opcodeSizes.Length - && s_opcodeSizes[(int)opcode] != Invalid; - } - - private static readonly byte[] s_opcodeSizes = new byte[] - { - 1, // nop = 0x00, - 1, // break_ = 0x01, - 1, // ldarg_0 = 0x02, - 1, // ldarg_1 = 0x03, - 1, // ldarg_2 = 0x04, - 1, // ldarg_3 = 0x05, - 1, // ldloc_0 = 0x06, - 1, // ldloc_1 = 0x07, - 1, // ldloc_2 = 0x08, - 1, // ldloc_3 = 0x09, - 1, // stloc_0 = 0x0a, - 1, // stloc_1 = 0x0b, - 1, // stloc_2 = 0x0c, - 1, // stloc_3 = 0x0d, - 2, // ldarg_s = 0x0e, - 2, // ldarga_s = 0x0f, - 2, // starg_s = 0x10, - 2, // ldloc_s = 0x11, - 2, // ldloca_s = 0x12, - 2, // stloc_s = 0x13, - 1, // ldnull = 0x14, - 1, // ldc_i4_m1 = 0x15, - 1, // ldc_i4_0 = 0x16, - 1, // ldc_i4_1 = 0x17, - 1, // ldc_i4_2 = 0x18, - 1, // ldc_i4_3 = 0x19, - 1, // ldc_i4_4 = 0x1a, - 1, // ldc_i4_5 = 0x1b, - 1, // ldc_i4_6 = 0x1c, - 1, // ldc_i4_7 = 0x1d, - 1, // ldc_i4_8 = 0x1e, - 2, // ldc_i4_s = 0x1f, - 5, // ldc_i4 = 0x20, - 9, // ldc_i8 = 0x21, - 5, // ldc_r4 = 0x22, - 9, // ldc_r8 = 0x23, - Invalid, // = 0x24, - 1, // dup = 0x25, - 1, // pop = 0x26, - 5, // jmp = 0x27, - 5, // call = 0x28, - 5, // calli = 0x29, - 1, // ret = 0x2a, - 2, // br_s = 0x2b, - 2, // brfalse_s = 0x2c, - 2, // brtrue_s = 0x2d, - 2, // beq_s = 0x2e, - 2, // bge_s = 0x2f, - 2, // bgt_s = 0x30, - 2, // ble_s = 0x31, - 2, // blt_s = 0x32, - 2, // bne_un_s = 0x33, - 2, // bge_un_s = 0x34, - 2, // bgt_un_s = 0x35, - 2, // ble_un_s = 0x36, - 2, // blt_un_s = 0x37, - 5, // br = 0x38, - 5, // brfalse = 0x39, - 5, // brtrue = 0x3a, - 5, // beq = 0x3b, - 5, // bge = 0x3c, - 5, // bgt = 0x3d, - 5, // ble = 0x3e, - 5, // blt = 0x3f, - 5, // bne_un = 0x40, - 5, // bge_un = 0x41, - 5, // bgt_un = 0x42, - 5, // ble_un = 0x43, - 5, // blt_un = 0x44, - VariableSize, // switch_ = 0x45, - 1, // ldind_i1 = 0x46, - 1, // ldind_u1 = 0x47, - 1, // ldind_i2 = 0x48, - 1, // ldind_u2 = 0x49, - 1, // ldind_i4 = 0x4a, - 1, // ldind_u4 = 0x4b, - 1, // ldind_i8 = 0x4c, - 1, // ldind_i = 0x4d, - 1, // ldind_r4 = 0x4e, - 1, // ldind_r8 = 0x4f, - 1, // ldind_ref = 0x50, - 1, // stind_ref = 0x51, - 1, // stind_i1 = 0x52, - 1, // stind_i2 = 0x53, - 1, // stind_i4 = 0x54, - 1, // stind_i8 = 0x55, - 1, // stind_r4 = 0x56, - 1, // stind_r8 = 0x57, - 1, // add = 0x58, - 1, // sub = 0x59, - 1, // mul = 0x5a, - 1, // div = 0x5b, - 1, // div_un = 0x5c, - 1, // rem = 0x5d, - 1, // rem_un = 0x5e, - 1, // and = 0x5f, - 1, // or = 0x60, - 1, // xor = 0x61, - 1, // shl = 0x62, - 1, // shr = 0x63, - 1, // shr_un = 0x64, - 1, // neg = 0x65, - 1, // not = 0x66, - 1, // conv_i1 = 0x67, - 1, // conv_i2 = 0x68, - 1, // conv_i4 = 0x69, - 1, // conv_i8 = 0x6a, - 1, // conv_r4 = 0x6b, - 1, // conv_r8 = 0x6c, - 1, // conv_u4 = 0x6d, - 1, // conv_u8 = 0x6e, - 5, // callvirt = 0x6f, - 5, // cpobj = 0x70, - 5, // ldobj = 0x71, - 5, // ldstr = 0x72, - 5, // newobj = 0x73, - 5, // castclass = 0x74, - 5, // isinst = 0x75, - 1, // conv_r_un = 0x76, - Invalid, // = 0x77, - Invalid, // = 0x78, - 5, // unbox = 0x79, - 1, // throw_ = 0x7a, - 5, // ldfld = 0x7b, - 5, // ldflda = 0x7c, - 5, // stfld = 0x7d, - 5, // ldsfld = 0x7e, - 5, // ldsflda = 0x7f, - 5, // stsfld = 0x80, - 5, // stobj = 0x81, - 1, // conv_ovf_i1_un = 0x82, - 1, // conv_ovf_i2_un = 0x83, - 1, // conv_ovf_i4_un = 0x84, - 1, // conv_ovf_i8_un = 0x85, - 1, // conv_ovf_u1_un = 0x86, - 1, // conv_ovf_u2_un = 0x87, - 1, // conv_ovf_u4_un = 0x88, - 1, // conv_ovf_u8_un = 0x89, - 1, // conv_ovf_i_un = 0x8a, - 1, // conv_ovf_u_un = 0x8b, - 5, // box = 0x8c, - 5, // newarr = 0x8d, - 1, // ldlen = 0x8e, - 5, // ldelema = 0x8f, - 1, // ldelem_i1 = 0x90, - 1, // ldelem_u1 = 0x91, - 1, // ldelem_i2 = 0x92, - 1, // ldelem_u2 = 0x93, - 1, // ldelem_i4 = 0x94, - 1, // ldelem_u4 = 0x95, - 1, // ldelem_i8 = 0x96, - 1, // ldelem_i = 0x97, - 1, // ldelem_r4 = 0x98, - 1, // ldelem_r8 = 0x99, - 1, // ldelem_ref = 0x9a, - 1, // stelem_i = 0x9b, - 1, // stelem_i1 = 0x9c, - 1, // stelem_i2 = 0x9d, - 1, // stelem_i4 = 0x9e, - 1, // stelem_i8 = 0x9f, - 1, // stelem_r4 = 0xa0, - 1, // stelem_r8 = 0xa1, - 1, // stelem_ref = 0xa2, - 5, // ldelem = 0xa3, - 5, // stelem = 0xa4, - 5, // unbox_any = 0xa5, - Invalid, // = 0xa6, - Invalid, // = 0xa7, - Invalid, // = 0xa8, - Invalid, // = 0xa9, - Invalid, // = 0xaa, - Invalid, // = 0xab, - Invalid, // = 0xac, - Invalid, // = 0xad, - Invalid, // = 0xae, - Invalid, // = 0xaf, - Invalid, // = 0xb0, - Invalid, // = 0xb1, - Invalid, // = 0xb2, - 1, // conv_ovf_i1 = 0xb3, - 1, // conv_ovf_u1 = 0xb4, - 1, // conv_ovf_i2 = 0xb5, - 1, // conv_ovf_u2 = 0xb6, - 1, // conv_ovf_i4 = 0xb7, - 1, // conv_ovf_u4 = 0xb8, - 1, // conv_ovf_i8 = 0xb9, - 1, // conv_ovf_u8 = 0xba, - Invalid, // = 0xbb, - Invalid, // = 0xbc, - Invalid, // = 0xbd, - Invalid, // = 0xbe, - Invalid, // = 0xbf, - Invalid, // = 0xc0, - Invalid, // = 0xc1, - 5, // refanyval = 0xc2, - 1, // ckfinite = 0xc3, - Invalid, // = 0xc4, - Invalid, // = 0xc5, - 5, // mkrefany = 0xc6, - Invalid, // = 0xc7, - Invalid, // = 0xc8, - Invalid, // = 0xc9, - Invalid, // = 0xca, - Invalid, // = 0xcb, - Invalid, // = 0xcc, - Invalid, // = 0xcd, - Invalid, // = 0xce, - Invalid, // = 0xcf, - 5, // ldtoken = 0xd0, - 1, // conv_u2 = 0xd1, - 1, // conv_u1 = 0xd2, - 1, // conv_i = 0xd3, - 1, // conv_ovf_i = 0xd4, - 1, // conv_ovf_u = 0xd5, - 1, // add_ovf = 0xd6, - 1, // add_ovf_un = 0xd7, - 1, // mul_ovf = 0xd8, - 1, // mul_ovf_un = 0xd9, - 1, // sub_ovf = 0xda, - 1, // sub_ovf_un = 0xdb, - 1, // endfinally = 0xdc, - 5, // leave = 0xdd, - 2, // leave_s = 0xde, - 1, // stind_i = 0xdf, - 1, // conv_u = 0xe0, - Invalid, // = 0xe1, - Invalid, // = 0xe2, - Invalid, // = 0xe3, - Invalid, // = 0xe4, - Invalid, // = 0xe5, - Invalid, // = 0xe6, - Invalid, // = 0xe7, - Invalid, // = 0xe8, - Invalid, // = 0xe9, - Invalid, // = 0xea, - Invalid, // = 0xeb, - Invalid, // = 0xec, - Invalid, // = 0xed, - Invalid, // = 0xee, - Invalid, // = 0xef, - Invalid, // = 0xf0, - Invalid, // = 0xf1, - Invalid, // = 0xf2, - Invalid, // = 0xf3, - Invalid, // = 0xf4, - Invalid, // = 0xf5, - Invalid, // = 0xf6, - Invalid, // = 0xf7, - Invalid, // = 0xf8, - Invalid, // = 0xf9, - Invalid, // = 0xfa, - Invalid, // = 0xfb, - Invalid, // = 0xfc, - Invalid, // = 0xfd, - 1, // prefix1 = 0xfe, - Invalid, // = 0xff, - 2, // arglist = 0x100, - 2, // ceq = 0x101, - 2, // cgt = 0x102, - 2, // cgt_un = 0x103, - 2, // clt = 0x104, - 2, // clt_un = 0x105, - 6, // ldftn = 0x106, - 6, // ldvirtftn = 0x107, - Invalid, // = 0x108, - 4, // ldarg = 0x109, - 4, // ldarga = 0x10a, - 4, // starg = 0x10b, - 4, // ldloc = 0x10c, - 4, // ldloca = 0x10d, - 4, // stloc = 0x10e, - 2, // localloc = 0x10f, - Invalid, // = 0x110, - 2, // endfilter = 0x111, - 3, // unaligned = 0x112, - 2, // volatile_ = 0x113, - 2, // tail = 0x114, - 6, // initobj = 0x115, - 6, // constrained = 0x116, - 2, // cpblk = 0x117, - 2, // initblk = 0x118, - 3, // no = 0x119, - 2, // rethrow = 0x11a, - Invalid, // = 0x11b, - 6, // sizeof_ = 0x11c, - 2, // refanytype = 0x11d, - 2, // readonly_ = 0x11e, - }; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILProvider.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILProvider.cs deleted file mode 100644 index f17bb497982..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILProvider.cs +++ /dev/null @@ -1,17 +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 Internal.TypeSystem; - -namespace Internal.IL -{ - /// - /// Provides IL for method bodies either by reading - /// the IL bytes from the source ECMA-335 assemblies, or through other means. - /// - public abstract class ILProvider - { - public abstract MethodIL GetMethodIL(MethodDesc method); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILStackHelper.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILStackHelper.cs deleted file mode 100644 index d30532e1373..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/ILStackHelper.cs +++ /dev/null @@ -1,474 +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 System.Diagnostics; - -using Internal.TypeSystem; - -namespace Internal.IL -{ - public static class ILStackHelper - { - /// - /// Validates that the CIL evaluation stack is properly balanced. - /// - [Conditional("DEBUG")] - public static void CheckStackBalance(this MethodIL methodIL) - { - methodIL.ComputeMaxStack(); - } - - /// - /// Computes the maximum number of items that can be pushed onto the CIL evaluation stack. - /// - public static int ComputeMaxStack(this MethodIL methodIL) - { - const int StackHeightNotSet = Int32.MinValue; - - byte[] ilbytes = methodIL.GetILBytes(); - int currentOffset = 0; - int stackHeight = 0; - int maxStack = 0; - - // TODO: Use Span for this and stackalloc the array if reasonably sized - int[] stackHeights = new int[ilbytes.Length]; - for (int i = 0; i < stackHeights.Length; i++) - stackHeights[i] = StackHeightNotSet; - - // Catch and filter clauses have a known non-zero stack height. - foreach (ILExceptionRegion region in methodIL.GetExceptionRegions()) - { - if (region.Kind == ILExceptionRegionKind.Catch) - { - stackHeights[region.HandlerOffset] = 1; - } - else if (region.Kind == ILExceptionRegionKind.Filter) - { - stackHeights[region.FilterOffset] = 1; - stackHeights[region.HandlerOffset] = 1; - } - } - - while (currentOffset < ilbytes.Length) - { - ILOpcode opcode = (ILOpcode)ilbytes[currentOffset]; - if (opcode == ILOpcode.prefix1) - opcode = 0x100 + (ILOpcode)ilbytes[currentOffset + 1]; - - // The stack height could be unknown if the previous instruction - // was an unconditional control transfer. - // In that case we check if we have a known stack height due to - // this instruction being a target of a previous branch or an EH block. - if (stackHeight == StackHeightNotSet) - stackHeight = stackHeights[currentOffset]; - - // If we still don't know the stack height, ECMA-335 III.1.7.5 - // "Backward branch constraint" demands the evaluation stack be empty. - if (stackHeight == StackHeightNotSet) - stackHeight = 0; - - // Remeber the stack height at this offset. - Debug.Assert(stackHeights[currentOffset] == StackHeightNotSet - || stackHeights[currentOffset] == stackHeight); - stackHeights[currentOffset] = stackHeight; - - bool isVariableSize = false; - switch (opcode) - { - case ILOpcode.arglist: - case ILOpcode.dup: - case ILOpcode.ldc_i4: - case ILOpcode.ldc_i4_0: - case ILOpcode.ldc_i4_1: - case ILOpcode.ldc_i4_2: - case ILOpcode.ldc_i4_3: - case ILOpcode.ldc_i4_4: - case ILOpcode.ldc_i4_5: - case ILOpcode.ldc_i4_6: - case ILOpcode.ldc_i4_7: - case ILOpcode.ldc_i4_8: - case ILOpcode.ldc_i4_m1: - case ILOpcode.ldc_i4_s: - case ILOpcode.ldc_i8: - case ILOpcode.ldc_r4: - case ILOpcode.ldc_r8: - case ILOpcode.ldftn: - case ILOpcode.ldnull: - case ILOpcode.ldsfld: - case ILOpcode.ldsflda: - case ILOpcode.ldstr: - case ILOpcode.ldtoken: - case ILOpcode.ldarg: - case ILOpcode.ldarg_0: - case ILOpcode.ldarg_1: - case ILOpcode.ldarg_2: - case ILOpcode.ldarg_3: - case ILOpcode.ldarg_s: - case ILOpcode.ldarga: - case ILOpcode.ldarga_s: - case ILOpcode.ldloc: - case ILOpcode.ldloc_0: - case ILOpcode.ldloc_1: - case ILOpcode.ldloc_2: - case ILOpcode.ldloc_3: - case ILOpcode.ldloc_s: - case ILOpcode.ldloca: - case ILOpcode.ldloca_s: - case ILOpcode.sizeof_: - stackHeight += 1; - break; - - case ILOpcode.add: - case ILOpcode.add_ovf: - case ILOpcode.add_ovf_un: - case ILOpcode.and: - case ILOpcode.ceq: - case ILOpcode.cgt: - case ILOpcode.cgt_un: - case ILOpcode.clt: - case ILOpcode.clt_un: - case ILOpcode.div: - case ILOpcode.div_un: - case ILOpcode.initobj: - case ILOpcode.ldelem: - case ILOpcode.ldelem_i: - case ILOpcode.ldelem_i1: - case ILOpcode.ldelem_i2: - case ILOpcode.ldelem_i4: - case ILOpcode.ldelem_i8: - case ILOpcode.ldelem_r4: - case ILOpcode.ldelem_r8: - case ILOpcode.ldelem_ref: - case ILOpcode.ldelem_u1: - case ILOpcode.ldelem_u2: - case ILOpcode.ldelem_u4: - case ILOpcode.ldelema: - case ILOpcode.mkrefany: - case ILOpcode.mul: - case ILOpcode.mul_ovf: - case ILOpcode.mul_ovf_un: - case ILOpcode.or: - case ILOpcode.pop: - case ILOpcode.rem: - case ILOpcode.rem_un: - case ILOpcode.shl: - case ILOpcode.shr: - case ILOpcode.shr_un: - case ILOpcode.stsfld: - case ILOpcode.sub: - case ILOpcode.sub_ovf: - case ILOpcode.sub_ovf_un: - case ILOpcode.xor: - case ILOpcode.starg: - case ILOpcode.starg_s: - case ILOpcode.stloc: - case ILOpcode.stloc_0: - case ILOpcode.stloc_1: - case ILOpcode.stloc_2: - case ILOpcode.stloc_3: - case ILOpcode.stloc_s: - Debug.Assert(stackHeight > 0); - stackHeight -= 1; - break; - - case ILOpcode.throw_: - Debug.Assert(stackHeight > 0); - stackHeight = StackHeightNotSet; - break; - - case ILOpcode.br: - case ILOpcode.leave: - case ILOpcode.brfalse: - case ILOpcode.brtrue: - case ILOpcode.beq: - case ILOpcode.bge: - case ILOpcode.bge_un: - case ILOpcode.bgt: - case ILOpcode.bgt_un: - case ILOpcode.ble: - case ILOpcode.ble_un: - case ILOpcode.blt: - case ILOpcode.blt_un: - case ILOpcode.bne_un: - { - int target = currentOffset + ReadInt32(ilbytes, currentOffset + 1) + 5; - - int adjustment; - bool isConditional; - if (opcode == ILOpcode.br || opcode == ILOpcode.leave) - { - isConditional = false; - adjustment = 0; - } - else if (opcode == ILOpcode.brfalse || opcode == ILOpcode.brtrue) - { - isConditional = true; - adjustment = 1; - } - else - { - isConditional = true; - adjustment = 2; - } - - Debug.Assert(stackHeight >= adjustment); - stackHeight -= adjustment; - - Debug.Assert(stackHeights[target] == StackHeightNotSet - || stackHeights[target] == stackHeight); - - // Forward branch carries information about stack height at a future - // offset. We need to remember it. - if (target > currentOffset) - stackHeights[target] = stackHeight; - - if (!isConditional) - stackHeight = StackHeightNotSet; - } - break; - - case ILOpcode.br_s: - case ILOpcode.leave_s: - case ILOpcode.brfalse_s: - case ILOpcode.brtrue_s: - case ILOpcode.beq_s: - case ILOpcode.bge_s: - case ILOpcode.bge_un_s: - case ILOpcode.bgt_s: - case ILOpcode.bgt_un_s: - case ILOpcode.ble_s: - case ILOpcode.ble_un_s: - case ILOpcode.blt_s: - case ILOpcode.blt_un_s: - case ILOpcode.bne_un_s: - { - int target = currentOffset + (sbyte)ilbytes[currentOffset + 1] + 2; - - int adjustment; - bool isConditional; - if (opcode == ILOpcode.br_s || opcode == ILOpcode.leave_s) - { - isConditional = false; - adjustment = 0; - } - else if (opcode == ILOpcode.brfalse_s || opcode == ILOpcode.brtrue_s) - { - isConditional = true; - adjustment = 1; - } - else - { - isConditional = true; - adjustment = 2; - } - - Debug.Assert(stackHeight >= adjustment); - stackHeight -= adjustment; - - Debug.Assert(stackHeights[target] == StackHeightNotSet - || stackHeights[target] == stackHeight); - - // Forward branch carries information about stack height at a future - // offset. We need to remember it. - if (target > currentOffset) - stackHeights[target] = stackHeight; - - if (!isConditional) - stackHeight = StackHeightNotSet; - } - break; - - case ILOpcode.call: - case ILOpcode.calli: - case ILOpcode.callvirt: - case ILOpcode.newobj: - { - int token = ReadILToken(ilbytes, currentOffset + 1); - object obj = methodIL.GetObject(token); - MethodSignature sig = obj is MethodSignature ? - (MethodSignature)obj : - ((MethodDesc)obj).Signature; - int adjustment = sig.Length; - if (opcode == ILOpcode.newobj) - { - adjustment--; - } - else - { - if (opcode == ILOpcode.calli) - adjustment++; - if (!sig.IsStatic) - adjustment++; - if (!sig.ReturnType.IsVoid) - adjustment--; - } - - Debug.Assert(stackHeight >= adjustment); - stackHeight -= adjustment; - } - break; - - case ILOpcode.ret: - { - bool hasReturnValue = !methodIL.OwningMethod.Signature.ReturnType.IsVoid; - if (hasReturnValue) - stackHeight -= 1; - - Debug.Assert(stackHeight == 0); - - stackHeight = StackHeightNotSet; - } - break; - - case ILOpcode.cpobj: - case ILOpcode.stfld: - case ILOpcode.stind_i: - case ILOpcode.stind_i1: - case ILOpcode.stind_i2: - case ILOpcode.stind_i4: - case ILOpcode.stind_i8: - case ILOpcode.stind_r4: - case ILOpcode.stind_r8: - case ILOpcode.stind_ref: - case ILOpcode.stobj: - Debug.Assert(stackHeight > 1); - stackHeight -= 2; - break; - - case ILOpcode.cpblk: - case ILOpcode.initblk: - case ILOpcode.stelem: - case ILOpcode.stelem_i: - case ILOpcode.stelem_i1: - case ILOpcode.stelem_i2: - case ILOpcode.stelem_i4: - case ILOpcode.stelem_i8: - case ILOpcode.stelem_r4: - case ILOpcode.stelem_r8: - case ILOpcode.stelem_ref: - Debug.Assert(stackHeight > 2); - stackHeight -= 3; - break; - - case ILOpcode.break_: - case ILOpcode.constrained: - case ILOpcode.no: - case ILOpcode.nop: - case ILOpcode.readonly_: - case ILOpcode.tail: - case ILOpcode.unaligned: - case ILOpcode.volatile_: - break; - - case ILOpcode.endfilter: - Debug.Assert(stackHeight > 0); - stackHeight = StackHeightNotSet; - break; - - case ILOpcode.jmp: - case ILOpcode.rethrow: - case ILOpcode.endfinally: - stackHeight = StackHeightNotSet; - break; - - case ILOpcode.box: - case ILOpcode.castclass: - case ILOpcode.ckfinite: - case ILOpcode.conv_i: - case ILOpcode.conv_i1: - case ILOpcode.conv_i2: - case ILOpcode.conv_i4: - case ILOpcode.conv_i8: - case ILOpcode.conv_ovf_i: - case ILOpcode.conv_ovf_i_un: - case ILOpcode.conv_ovf_i1: - case ILOpcode.conv_ovf_i1_un: - case ILOpcode.conv_ovf_i2: - case ILOpcode.conv_ovf_i2_un: - case ILOpcode.conv_ovf_i4: - case ILOpcode.conv_ovf_i4_un: - case ILOpcode.conv_ovf_i8: - case ILOpcode.conv_ovf_i8_un: - case ILOpcode.conv_ovf_u: - case ILOpcode.conv_ovf_u_un: - case ILOpcode.conv_ovf_u1: - case ILOpcode.conv_ovf_u1_un: - case ILOpcode.conv_ovf_u2: - case ILOpcode.conv_ovf_u2_un: - case ILOpcode.conv_ovf_u4: - case ILOpcode.conv_ovf_u4_un: - case ILOpcode.conv_ovf_u8: - case ILOpcode.conv_ovf_u8_un: - case ILOpcode.conv_r_un: - case ILOpcode.conv_r4: - case ILOpcode.conv_r8: - case ILOpcode.conv_u: - case ILOpcode.conv_u1: - case ILOpcode.conv_u2: - case ILOpcode.conv_u4: - case ILOpcode.conv_u8: - case ILOpcode.isinst: - case ILOpcode.ldfld: - case ILOpcode.ldflda: - case ILOpcode.ldind_i: - case ILOpcode.ldind_i1: - case ILOpcode.ldind_i2: - case ILOpcode.ldind_i4: - case ILOpcode.ldind_i8: - case ILOpcode.ldind_r4: - case ILOpcode.ldind_r8: - case ILOpcode.ldind_ref: - case ILOpcode.ldind_u1: - case ILOpcode.ldind_u2: - case ILOpcode.ldind_u4: - case ILOpcode.ldlen: - case ILOpcode.ldobj: - case ILOpcode.ldvirtftn: - case ILOpcode.localloc: - case ILOpcode.neg: - case ILOpcode.newarr: - case ILOpcode.not: - case ILOpcode.refanytype: - case ILOpcode.refanyval: - case ILOpcode.unbox: - case ILOpcode.unbox_any: - Debug.Assert(stackHeight > 0); - break; - - case ILOpcode.switch_: - Debug.Assert(stackHeight > 0); - isVariableSize = true; - stackHeight -= 1; - currentOffset += 1 + (ReadInt32(ilbytes, currentOffset + 1) * 4) + 4; - break; - - default: - Debug.Fail("Unknown instruction"); - break; - } - - if (!isVariableSize) - currentOffset += opcode.GetSize(); - - maxStack = Math.Max(maxStack, stackHeight); - } - - return maxStack; - } - - private static int ReadInt32(byte[] ilBytes, int offset) - { - return ilBytes[offset] - + (ilBytes[offset + 1] << 8) - + (ilBytes[offset + 2] << 16) - + (ilBytes[offset + 3] << 24); - } - - private static int ReadILToken(byte[] ilBytes, int offset) - { - return ReadInt32(ilBytes, offset); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/InstantiatedMethodIL.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/InstantiatedMethodIL.cs deleted file mode 100644 index f444f5da770..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/InstantiatedMethodIL.cs +++ /dev/null @@ -1,130 +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.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL -{ - public sealed partial class InstantiatedMethodIL : MethodIL - { - private MethodDesc _method; - private MethodIL _methodIL; - private Instantiation _typeInstantiation; - private Instantiation _methodInstantiation; - - public InstantiatedMethodIL(MethodDesc owningMethod, MethodIL methodIL) - { - Debug.Assert(methodIL.GetMethodILDefinition() == methodIL); - Debug.Assert(owningMethod.HasInstantiation || owningMethod.OwningType.HasInstantiation); - Debug.Assert(owningMethod.GetTypicalMethodDefinition() == methodIL.OwningMethod); - - _methodIL = methodIL; - _method = owningMethod; - - _typeInstantiation = owningMethod.OwningType.Instantiation; - _methodInstantiation = owningMethod.Instantiation; - } - - public override MethodDesc OwningMethod - { - get - { - return _method; - } - } - - public override byte[] GetILBytes() - { - return _methodIL.GetILBytes(); - } - - public override int MaxStack - { - get - { - return _methodIL.MaxStack; - } - } - - public override ILExceptionRegion[] GetExceptionRegions() - { - return _methodIL.GetExceptionRegions(); - } - - public override bool IsInitLocals - { - get - { - return _methodIL.IsInitLocals; - } - } - - public override LocalVariableDefinition[] GetLocals() - { - LocalVariableDefinition[] locals = _methodIL.GetLocals(); - LocalVariableDefinition[] clone = null; - - for (int i = 0; i < locals.Length; i++) - { - TypeDesc uninst = locals[i].Type; - TypeDesc inst = uninst.InstantiateSignature(_typeInstantiation, _methodInstantiation); - if (uninst != inst) - { - if (clone == null) - { - clone = new LocalVariableDefinition[locals.Length]; - for (int j = 0; j < clone.Length; j++) - { - clone[j] = locals[j]; - } - } - clone[i] = new LocalVariableDefinition(inst, locals[i].IsPinned); - } - } - - return (clone == null) ? locals : clone; - } - - public override Object GetObject(int token) - { - Object o = _methodIL.GetObject(token); - - if (o is MethodDesc) - { - o = ((MethodDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); - } - else if (o is TypeDesc) - { - o = ((TypeDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); - } - else if (o is FieldDesc) - { - o = ((FieldDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); - } - else if (o is MethodSignature) - { - MethodSignature template = (MethodSignature)o; - MethodSignatureBuilder builder = new MethodSignatureBuilder(template); - - builder.ReturnType = template.ReturnType.InstantiateSignature(_typeInstantiation, _methodInstantiation); - for (int i = 0; i < template.Length; i++) - builder[i] = template[i].InstantiateSignature(_typeInstantiation, _methodInstantiation); - - o = builder.ToSignature(); - } - - - return o; - } - - public override MethodIL GetMethodILDefinition() - { - return _methodIL; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodIL.Symbols.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodIL.Symbols.cs deleted file mode 100644 index 9271af838e5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodIL.Symbols.cs +++ /dev/null @@ -1,87 +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 System.Collections.Generic; - -using Internal.TypeSystem; - -namespace Internal.IL -{ - partial class MethodIL - { - public virtual MethodDebugInformation GetDebugInfo() - { - return MethodDebugInformation.None; - } - } - - partial class InstantiatedMethodIL - { - public override MethodDebugInformation GetDebugInfo() - { - return _methodIL.GetDebugInfo(); - } - } - - /// - /// Represents debug information attached to a . - /// - public class MethodDebugInformation - { - public static MethodDebugInformation None = new MethodDebugInformation(); - - public virtual IEnumerable GetSequencePoints() - { - return null; - } - - public virtual IEnumerable GetLocalVariables() - { - return null; - } - - public virtual IEnumerable GetParameterNames() - { - return null; - } - } - - /// - /// Represents a sequence point within an IL method body. - /// Sequence point describes a point in the method body at which all side effects of - /// previous evaluations have been performed. - /// - public struct ILSequencePoint - { - public readonly int Offset; - public readonly string Document; - public readonly int LineNumber; - // TODO: The remaining info - - public ILSequencePoint(int offset, string document, int lineNumber) - { - Offset = offset; - Document = document; - LineNumber = lineNumber; - } - } - - /// - /// Represents information about a local variable within a method body. - /// - public struct ILLocalVariable - { - public readonly int Slot; - public readonly string Name; - public readonly bool CompilerGenerated; - - public ILLocalVariable(int slot, string name, bool compilerGenerated) - { - Slot = slot; - Name = name; - CompilerGenerated = compilerGenerated; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodIL.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodIL.cs deleted file mode 100644 index 70e925d718b..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodIL.cs +++ /dev/null @@ -1,110 +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.TypeSystem; - -namespace Internal.IL -{ - // - // This duplicates types from System.Reflection.Metadata to avoid layering issues, and - // because of the System.Reflection.Metadata constructors are not public anyway. - // - - public enum ILExceptionRegionKind - { - Catch = 0, - Filter = 1, - Finally = 2, - Fault = 4, - } - - public struct ILExceptionRegion - { - public readonly ILExceptionRegionKind Kind; - public readonly int TryOffset; - public readonly int TryLength; - public readonly int HandlerOffset; - public readonly int HandlerLength; - public readonly int ClassToken; - public readonly int FilterOffset; - - public ILExceptionRegion( - ILExceptionRegionKind kind, - int tryOffset, - int tryLength, - int handlerOffset, - int handlerLength, - int classToken, - int filterOffset) - { - Kind = kind; - TryOffset = tryOffset; - TryLength = tryLength; - HandlerOffset = handlerOffset; - HandlerLength = handlerLength; - ClassToken = classToken; - FilterOffset = filterOffset; - } - } - - /// - /// Represents a method body. - /// - [System.Diagnostics.DebuggerTypeProxy(typeof(MethodILDebugView))] - public abstract partial class MethodIL - { - /// - /// Gets the method whose body this represents. - /// - public abstract MethodDesc OwningMethod { get; } - - /// - /// Gets the maximum possible stack depth this method declares. - /// - public abstract int MaxStack { get; } - - /// - /// Gets a value indicating whether the locals should be initialized to zero - /// before first access. - /// - public abstract bool IsInitLocals { get; } - - /// - /// Retrieves IL opcode bytes of this method body. - /// - public abstract byte[] GetILBytes(); - - /// - /// Gets the list of locals this method body defines. - /// - public abstract LocalVariableDefinition[] GetLocals(); - - /// - /// Resolves a token from within the method body into a type system object - /// (typically a , , , - /// or ). - /// - public abstract Object GetObject(int token); - - /// - /// Gets a list of exception regions this method body defines. - /// - public abstract ILExceptionRegion[] GetExceptionRegions(); - - /// - /// Gets the open (uninstantiated) version of the . - /// - public virtual MethodIL GetMethodILDefinition() - { - return this; - } - - public override string ToString() - { - return OwningMethod.ToString(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodILDebugView.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodILDebugView.cs deleted file mode 100644 index e0d5675e602..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/MethodILDebugView.cs +++ /dev/null @@ -1,143 +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.Text; - -using Internal.TypeSystem; - -namespace Internal.IL -{ - internal sealed class MethodILDebugView - { - private readonly MethodIL _methodIL; - - public MethodILDebugView(MethodIL methodIL) - { - _methodIL = methodIL; - } - - public string Disassembly - { - get - { - ILDisassembler disasm = new ILDisassembler(_methodIL); - - StringBuilder sb = new StringBuilder(); - - MethodDesc owningMethod = _methodIL.OwningMethod; - - sb.Append("// "); - sb.AppendLine(owningMethod.ToString()); - sb.Append(".method "); - // TODO: accessibility, specialname, calling conventions etc. - if (!owningMethod.Signature.IsStatic) - sb.Append("instance "); - disasm.AppendType(sb, owningMethod.Signature.ReturnType); - sb.Append(" "); - sb.Append(owningMethod.Name); - if (owningMethod.HasInstantiation) - { - sb.Append("<"); - for (int i = 0; i < owningMethod.Instantiation.Length; i++) - { - if (i != 0) - sb.Append(", "); - disasm.AppendType(sb, owningMethod.Instantiation[i]); - } - sb.Append(">"); - } - sb.Append("("); - for (int i = 0; i < owningMethod.Signature.Length; i++) - { - if (i != 0) - sb.Append(", "); - disasm.AppendType(sb, owningMethod.Signature[i]); - } - sb.AppendLine(") cil managed"); - - sb.AppendLine("{"); - - sb.Append(" // Code size: "); - sb.Append(disasm.CodeSize); - sb.AppendLine(); - sb.Append(" .maxstack "); - sb.Append(_methodIL.MaxStack); - sb.AppendLine(); - - LocalVariableDefinition[] locals = _methodIL.GetLocals(); - if (locals != null && locals.Length > 0) - { - sb.Append(" .locals "); - if (_methodIL.IsInitLocals) - sb.Append("init "); - - sb.Append("("); - - for (int i = 0; i < locals.Length; i++) - { - if (i != 0) - { - sb.AppendLine(","); - sb.Append(' ', 6); - } - disasm.AppendType(sb, locals[i].Type); - sb.Append(" "); - if (locals[i].IsPinned) - sb.Append("pinned "); - sb.Append("V_"); - sb.Append(i); - } - sb.AppendLine(")"); - } - sb.AppendLine(); - - const string pad = " "; - - // TODO: pretty exception regions - foreach (ILExceptionRegion region in _methodIL.GetExceptionRegions()) - { - sb.Append(pad); - sb.Append(".try "); - ILDisassembler.AppendOffset(sb, region.TryOffset); - sb.Append(" to "); - ILDisassembler.AppendOffset(sb, region.TryOffset + region.TryLength); - - switch (region.Kind) - { - case ILExceptionRegionKind.Catch: - sb.Append(" catch "); - disasm.AppendType(sb, (TypeDesc)_methodIL.GetObject(region.ClassToken)); - break; - case ILExceptionRegionKind.Fault: - sb.Append(" fault"); - break; - case ILExceptionRegionKind.Filter: - sb.Append(" filter "); - ILDisassembler.AppendOffset(sb, region.FilterOffset); - break; - case ILExceptionRegionKind.Finally: - sb.Append(" finally"); - break; - } - - sb.Append(" handler "); - ILDisassembler.AppendOffset(sb, region.HandlerOffset); - sb.Append(" to "); - ILDisassembler.AppendOffset(sb, region.HandlerOffset + region.HandlerLength); - sb.AppendLine(); - } - - while (disasm.HasNextInstruction) - { - sb.Append(pad); - sb.AppendLine(disasm.GetNextInstruction()); - } - - sb.AppendLine("}"); - - return sb.ToString(); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs deleted file mode 100644 index 9919805e286..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs +++ /dev/null @@ -1,219 +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 System.Collections.Generic; - -using Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL.Stubs -{ - /// - /// Intrinsic support arround EqualityComparer<T> and Comparer<T>. - /// - public static class ComparerIntrinsics - { - /// - /// Generates a specialized method body for Comparer`1.Create or returns null if no specialized body can be generated. - /// - public static MethodIL EmitComparerCreate(MethodDesc target) - { - return EmitComparerAndEqualityComparerCreateCommon(target, "Comparer", "IComparable`1"); - } - - /// - /// Generates a specialized method body for EqualityComparer`1.Create or returns null if no specialized body can be generated. - /// - public static MethodIL EmitEqualityComparerCreate(MethodDesc target) - { - return EmitComparerAndEqualityComparerCreateCommon(target, "EqualityComparer", "IEquatable`1"); - } - - /// - /// Gets the concrete type EqualityComparer`1.Create returns or null if it's not known at compile time. - /// - public static TypeDesc GetEqualityComparerForType(TypeDesc comparand) - { - return GetComparerForType(comparand, "EqualityComparer", "IEquatable`1"); - } - - private static MethodIL EmitComparerAndEqualityComparerCreateCommon(MethodDesc methodBeingGenerated, string flavor, string interfaceName) - { - // We expect the method to be fully instantiated - Debug.Assert(!methodBeingGenerated.IsTypicalMethodDefinition); - - TypeDesc owningType = methodBeingGenerated.OwningType; - TypeDesc comparedType = owningType.Instantiation[0]; - - // If the type is canonical, we use the default implementation provided by the class library. - // This will rely on the type loader to load the proper type at runtime. - if (comparedType.IsCanonicalSubtype(CanonicalFormKind.Any)) - return null; - - TypeDesc comparerType = GetComparerForType(comparedType, flavor, interfaceName); - Debug.Assert(comparerType != null); - - ILEmitter emitter = new ILEmitter(); - var codeStream = emitter.NewCodeStream(); - - codeStream.Emit(ILOpcode.newobj, emitter.NewToken(comparerType.GetParameterlessConstructor())); - codeStream.Emit(ILOpcode.dup); - codeStream.Emit(ILOpcode.stsfld, emitter.NewToken(owningType.GetKnownField("_default"))); - codeStream.Emit(ILOpcode.ret); - - return emitter.Link(methodBeingGenerated); - } - - /// - /// Gets the comparer type that is suitable to compare instances of - /// or null if such comparer cannot be determined at compile time. - /// - private static TypeDesc GetComparerForType(TypeDesc type, string flavor, string interfaceName) - { - TypeSystemContext context = type.Context; - - if (context.IsCanonicalDefinitionType(type, CanonicalFormKind.Any) || - (type.IsRuntimeDeterminedSubtype && !type.HasInstantiation)) - { - // The comparer will be determined at runtime. We can't tell the exact type at compile time. - return null; - } - else if (type.IsNullable) - { - TypeDesc nullableType = type.Instantiation[0]; - - if (context.IsCanonicalDefinitionType(nullableType, CanonicalFormKind.Universal)) - { - // We can't tell at compile time either. - return null; - } - else if (ImplementsInterfaceOfSelf(nullableType, interfaceName)) - { - return context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1") - .MakeInstantiatedType(nullableType); - } - } - else if (flavor == "EqualityComparer" && type.IsEnum) - { - // Enums have a specialized comparer that avoids boxing - return context.SystemModule.GetKnownType("System.Collections.Generic", $"Enum{flavor}`1") - .MakeInstantiatedType(type); - } - else if (ImplementsInterfaceOfSelf(type, interfaceName)) - { - return context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1") - .MakeInstantiatedType(type); - } - - return context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1") - .MakeInstantiatedType(type); - } - - public static TypeDesc[] GetPotentialComparersForType(TypeDesc type) - { - return GetPotentialComparersForTypeCommon(type, "Comparer", "IComparable`1"); - } - - public static TypeDesc[] GetPotentialEqualityComparersForType(TypeDesc type) - { - return GetPotentialComparersForTypeCommon(type, "EqualityComparer", "IEquatable`1"); - } - - /// - /// Gets the set of template types needed to support loading comparers for the give canonical type at runtime. - /// - private static TypeDesc[] GetPotentialComparersForTypeCommon(TypeDesc type, string flavor, string interfaceName) - { - Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any)); - - TypeDesc exactComparer = GetComparerForType(type, flavor, interfaceName); - - if (exactComparer != null) - { - // If we have a comparer that is exactly known at runtime, we're done. - // This will typically be if type is a generic struct, generic enum, or a nullable. - return new TypeDesc[] { exactComparer }; - } - - TypeSystemContext context = type.Context; - - if (context.IsCanonicalDefinitionType(type, CanonicalFormKind.Universal)) - { - // This can be any of the comparers we have. - - ArrayBuilder universalComparers = new ArrayBuilder(); - - universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1") - .MakeInstantiatedType(type)); - - if (flavor == "EqualityComparer") - universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Enum{flavor}`1") - .MakeInstantiatedType(type)); - - universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1") - .MakeInstantiatedType(type)); - - universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1") - .MakeInstantiatedType(type)); - - return universalComparers.ToArray(); - } - - // This mirrors exactly what GetUnknownEquatableComparer and GetUnknownComparer (in the class library) - // will need at runtime. This is the general purpose code path that can be used to compare - // anything. - - if (type.IsNullable) - { - TypeDesc nullableType = type.Instantiation[0]; - - // This should only be reachabe for universal canon code. - // For specific canon, this should have been an exact match above. - Debug.Assert(context.IsCanonicalDefinitionType(nullableType, CanonicalFormKind.Universal)); - - return new TypeDesc[] - { - context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1") - .MakeInstantiatedType(nullableType), - context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1") - .MakeInstantiatedType(type), - }; - } - - return new TypeDesc[] - { - context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1") - .MakeInstantiatedType(type), - context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1") - .MakeInstantiatedType(type), - }; - } - - public static bool ImplementsIEquatable(TypeDesc type) - => ImplementsInterfaceOfSelf(type, "IEquatable`1"); - - private static bool ImplementsInterfaceOfSelf(TypeDesc type, string interfaceName) - { - MetadataType interfaceType = null; - - foreach (TypeDesc implementedInterface in type.RuntimeInterfaces) - { - Instantiation interfaceInstantiation = implementedInterface.Instantiation; - if (interfaceInstantiation.Length == 1 && - interfaceInstantiation[0] == type) - { - if (interfaceType == null) - interfaceType = type.Context.SystemModule.GetKnownType("System", interfaceName); - - if (implementedInterface.GetTypeDefinition() == interfaceType) - return true; - } - } - - return false; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/ILEmitter.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/ILEmitter.cs deleted file mode 100644 index 363ab351c89..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/ILEmitter.cs +++ /dev/null @@ -1,829 +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 System.Collections.Generic; - -using Internal.IL; -using Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL.Stubs -{ - public class ILCodeStream - { - private const int StartOffsetNotSet = -1; - - private struct LabelAndOffset - { - public readonly ILCodeLabel Label; - public readonly int Offset; - public LabelAndOffset(ILCodeLabel label, int offset) - { - Label = label; - Offset = offset; - } - } - - internal byte[] _instructions; - internal int _length; - internal int _startOffsetForLinking; - internal ArrayBuilder _sequencePoints; - - private ArrayBuilder _offsetsNeedingPatching; - - private ILEmitter _emitter; - - internal ILCodeStream(ILEmitter emitter) - { - _instructions = Array.Empty(); - _startOffsetForLinking = StartOffsetNotSet; - _emitter = emitter; - } - - internal int RelativeToAbsoluteOffset(int relativeOffset) - { - Debug.Assert(_startOffsetForLinking != StartOffsetNotSet); - return _startOffsetForLinking + relativeOffset; - } - - private void EmitByte(byte b) - { - if (_instructions.Length == _length) - Array.Resize(ref _instructions, 2 * _instructions.Length + 10); - _instructions[_length++] = b; - } - - private void EmitUInt16(ushort value) - { - EmitByte((byte)value); - EmitByte((byte)(value >> 8)); - } - - private void EmitUInt32(int value) - { - EmitByte((byte)value); - EmitByte((byte)(value >> 8)); - EmitByte((byte)(value >> 16)); - EmitByte((byte)(value >> 24)); - } - - public void Emit(ILOpcode opcode) - { - if ((int)opcode > 0x100) - EmitByte((byte)ILOpcode.prefix1); - EmitByte((byte)opcode); - } - - public void Emit(ILOpcode opcode, ILToken token) - { - Emit(opcode); - EmitUInt32((int)token); - } - - public void EmitLdc(int value) - { - if (-1 <= value && value <= 8) - { - Emit((ILOpcode)(ILOpcode.ldc_i4_0 + value)); - } - else if (value == (sbyte)value) - { - Emit(ILOpcode.ldc_i4_s); - EmitByte((byte)value); - } - else - { - Emit(ILOpcode.ldc_i4); - EmitUInt32(value); - } - } - - public void EmitLdArg(int index) - { - if (index < 4) - { - Emit((ILOpcode)(ILOpcode.ldarg_0 + index)); - } - else - { - Emit(ILOpcode.ldarg); - EmitUInt16((ushort)index); - } - } - - public void EmitLdArga(int index) - { - if (index < 0x100) - { - Emit(ILOpcode.ldarga_s); - EmitByte((byte)index); - } - else - { - Emit(ILOpcode.ldarga); - EmitUInt16((ushort)index); - } - } - - public void EmitLdLoc(ILLocalVariable variable) - { - int index = (int)variable; - - if (index < 4) - { - Emit((ILOpcode)(ILOpcode.ldloc_0 + index)); - } - else if (index < 0x100) - { - Emit(ILOpcode.ldloc_s); - EmitByte((byte)index); - } - else - { - Emit(ILOpcode.ldloc); - EmitUInt16((ushort)index); - } - } - - public void EmitLdLoca(ILLocalVariable variable) - { - int index = (int)variable; - - if (index < 0x100) - { - Emit(ILOpcode.ldloca_s); - EmitByte((byte)index); - } - else - { - Emit(ILOpcode.ldloca); - EmitUInt16((ushort)index); - } - } - - public void EmitStLoc(ILLocalVariable variable) - { - int index = (int)variable; - - if (index < 4) - { - Emit((ILOpcode)(ILOpcode.stloc_0 + index)); - } - else if (index < 0x100) - { - Emit(ILOpcode.stloc_s); - EmitByte((byte)index); - } - else - { - Emit(ILOpcode.stloc); - EmitUInt16((ushort)index); - } - } - - public void Emit(ILOpcode opcode, ILCodeLabel label) - { - Debug.Assert(opcode == ILOpcode.br || opcode == ILOpcode.brfalse || - opcode == ILOpcode.brtrue || opcode == ILOpcode.beq || - opcode == ILOpcode.bge || opcode == ILOpcode.bgt || - opcode == ILOpcode.ble || opcode == ILOpcode.blt || - opcode == ILOpcode.bne_un || opcode == ILOpcode.bge_un || - opcode == ILOpcode.bgt_un || opcode == ILOpcode.ble_un || - opcode == ILOpcode.blt_un || opcode == ILOpcode.leave); - - Emit(opcode); - _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length)); - EmitUInt32(4); - } - - public void EmitSwitch(ILCodeLabel[] labels) - { - Emit(ILOpcode.switch_); - EmitUInt32(labels.Length); - - int remainingBytes = labels.Length * 4; - foreach (var label in labels) - { - _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length)); - EmitUInt32(remainingBytes); - remainingBytes -= 4; - } - } - - public void EmitUnaligned() - { - Emit(ILOpcode.unaligned); - EmitByte(1); - } - - public void EmitLdInd(TypeDesc type) - { - switch (type.UnderlyingType.Category) - { - case TypeFlags.SByte: - Emit(ILOpcode.ldind_i1); - break; - case TypeFlags.Byte: - case TypeFlags.Boolean: - Emit(ILOpcode.ldind_u1); - break; - case TypeFlags.Int16: - Emit(ILOpcode.ldind_i2); - break; - case TypeFlags.Char: - case TypeFlags.UInt16: - Emit(ILOpcode.ldind_u2); - break; - case TypeFlags.UInt32: - Emit(ILOpcode.ldind_u4); - break; - case TypeFlags.Int32: - Emit(ILOpcode.ldind_i4); - break; - case TypeFlags.UInt64: - case TypeFlags.Int64: - Emit(ILOpcode.ldind_i8); - break; - case TypeFlags.Single: - Emit(ILOpcode.ldind_r4); - break; - case TypeFlags.Double: - Emit(ILOpcode.ldind_r8); - break; - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - case TypeFlags.Pointer: - case TypeFlags.FunctionPointer: - Emit(ILOpcode.ldind_i); - break; - case TypeFlags.Array: - case TypeFlags.SzArray: - case TypeFlags.Class: - case TypeFlags.Interface: - Emit(ILOpcode.ldind_ref); - break; - case TypeFlags.ValueType: - case TypeFlags.Nullable: - case TypeFlags.SignatureMethodVariable: - case TypeFlags.SignatureTypeVariable: - Emit(ILOpcode.ldobj, _emitter.NewToken(type)); - break; - default: - Debug.Fail("Unexpected TypeDesc category"); - break; - } - } - public void EmitStInd(TypeDesc type) - { - switch (type.UnderlyingType.Category) - { - case TypeFlags.Byte: - case TypeFlags.SByte: - case TypeFlags.Boolean: - Emit(ILOpcode.stind_i1); - break; - case TypeFlags.Char: - case TypeFlags.UInt16: - case TypeFlags.Int16: - Emit(ILOpcode.stind_i2); - break; - case TypeFlags.UInt32: - case TypeFlags.Int32: - Emit(ILOpcode.stind_i4); - break; - case TypeFlags.UInt64: - case TypeFlags.Int64: - Emit(ILOpcode.stind_i8); - break; - case TypeFlags.Single: - Emit(ILOpcode.stind_r4); - break; - case TypeFlags.Double: - Emit(ILOpcode.stind_r8); - break; - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - case TypeFlags.Pointer: - case TypeFlags.FunctionPointer: - Emit(ILOpcode.stind_i); - break; - case TypeFlags.Array: - case TypeFlags.SzArray: - case TypeFlags.Class: - case TypeFlags.Interface: - Emit(ILOpcode.stind_ref); - break; - case TypeFlags.ValueType: - case TypeFlags.Nullable: - Emit(ILOpcode.stobj, _emitter.NewToken(type)); - break; - default: - Debug.Fail("Unexpected TypeDesc category"); - break; - } - } - - public void EmitStElem(TypeDesc type) - { - switch (type.UnderlyingType.Category) - { - case TypeFlags.Byte: - case TypeFlags.SByte: - case TypeFlags.Boolean: - Emit(ILOpcode.stelem_i1); - break; - case TypeFlags.Char: - case TypeFlags.UInt16: - case TypeFlags.Int16: - Emit(ILOpcode.stelem_i2); - break; - case TypeFlags.UInt32: - case TypeFlags.Int32: - Emit(ILOpcode.stelem_i4); - break; - case TypeFlags.UInt64: - case TypeFlags.Int64: - Emit(ILOpcode.stelem_i8); - break; - case TypeFlags.Single: - Emit(ILOpcode.stelem_r4); - break; - case TypeFlags.Double: - Emit(ILOpcode.stelem_r8); - break; - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - case TypeFlags.Pointer: - case TypeFlags.FunctionPointer: - Emit(ILOpcode.stelem_i); - break; - case TypeFlags.Array: - case TypeFlags.SzArray: - case TypeFlags.Class: - case TypeFlags.Interface: - Emit(ILOpcode.stelem_ref); - break; - case TypeFlags.ValueType: - case TypeFlags.Nullable: - Emit(ILOpcode.stelem, _emitter.NewToken(type)); - break; - default: - Debug.Fail("Unexpected TypeDesc category"); - break; - } - } - - public void EmitLdElem(TypeDesc type) - { - switch (type.UnderlyingType.Category) - { - case TypeFlags.Byte: - case TypeFlags.SByte: - case TypeFlags.Boolean: - Emit(ILOpcode.ldelem_i1); - break; - case TypeFlags.Char: - case TypeFlags.UInt16: - case TypeFlags.Int16: - Emit(ILOpcode.ldelem_i2); - break; - case TypeFlags.UInt32: - case TypeFlags.Int32: - Emit(ILOpcode.ldelem_i4); - break; - case TypeFlags.UInt64: - case TypeFlags.Int64: - Emit(ILOpcode.ldelem_i8); - break; - case TypeFlags.Single: - Emit(ILOpcode.ldelem_r4); - break; - case TypeFlags.Double: - Emit(ILOpcode.ldelem_r8); - break; - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - case TypeFlags.Pointer: - case TypeFlags.FunctionPointer: - Emit(ILOpcode.ldelem_i); - break; - case TypeFlags.Array: - case TypeFlags.SzArray: - case TypeFlags.Class: - case TypeFlags.Interface: - Emit(ILOpcode.ldelem_ref); - break; - case TypeFlags.ValueType: - case TypeFlags.Nullable: - Emit(ILOpcode.ldelem, _emitter.NewToken(type)); - break; - default: - Debug.Fail("Unexpected TypeDesc category"); - break; - } - } - - public void EmitLabel(ILCodeLabel label) - { - label.Place(this, _length); - } - - public void BeginTry(ILExceptionRegionBuilder builder) - { - Debug.Assert(builder._beginTryStream == null); - builder._beginTryStream = this; - builder._beginTryOffset = _length; - } - - public void EndTry(ILExceptionRegionBuilder builder) - { - Debug.Assert(builder._endTryStream == null); - builder._endTryStream = this; - builder._endTryOffset = _length; - } - - public void BeginHandler(ILExceptionRegionBuilder builder) - { - Debug.Assert(builder._beginHandlerStream == null); - builder._beginHandlerStream = this; - builder._beginHandlerOffset = _length; - } - - public void EndHandler(ILExceptionRegionBuilder builder) - { - Debug.Assert(builder._endHandlerStream == null); - builder._endHandlerStream = this; - builder._endHandlerOffset = _length; - } - - internal void PatchLabels() - { - for (int i = 0; i < _offsetsNeedingPatching.Count; i++) - { - LabelAndOffset patch = _offsetsNeedingPatching[i]; - - Debug.Assert(patch.Label.IsPlaced); - Debug.Assert(_startOffsetForLinking != StartOffsetNotSet); - - int offset = patch.Offset; - - int delta = _instructions[offset + 3] << 24 | - _instructions[offset + 2] << 16 | - _instructions[offset + 1] << 8 | - _instructions[offset]; - - int value = patch.Label.AbsoluteOffset - _startOffsetForLinking - patch.Offset - delta; - - _instructions[offset] = (byte)value; - _instructions[offset + 1] = (byte)(value >> 8); - _instructions[offset + 2] = (byte)(value >> 16); - _instructions[offset + 3] = (byte)(value >> 24); - } - } - - public void DefineSequencePoint(string document, int lineNumber) - { - // Last sequence point defined for this offset wins. - if (_sequencePoints.Count > 0 && _sequencePoints[_sequencePoints.Count - 1].Offset == _length) - { - _sequencePoints[_sequencePoints.Count - 1] = new ILSequencePoint(_length, document, lineNumber); - } - else - { - _sequencePoints.Add(new ILSequencePoint(_length, document, lineNumber)); - } - } - } - - public class ILExceptionRegionBuilder - { - internal ILCodeStream _beginTryStream; - internal int _beginTryOffset; - - internal ILCodeStream _endTryStream; - internal int _endTryOffset; - - internal ILCodeStream _beginHandlerStream; - internal int _beginHandlerOffset; - - internal ILCodeStream _endHandlerStream; - internal int _endHandlerOffset; - - internal ILExceptionRegionBuilder() - { - } - - internal int TryOffset => _beginTryStream.RelativeToAbsoluteOffset(_beginTryOffset); - internal int TryLength => _endTryStream.RelativeToAbsoluteOffset(_endTryOffset) - TryOffset; - internal int HandlerOffset => _beginHandlerStream.RelativeToAbsoluteOffset(_beginHandlerOffset); - internal int HandlerLength => _endHandlerStream.RelativeToAbsoluteOffset(_endHandlerOffset) - HandlerOffset; - - internal bool IsDefined => - _beginTryStream != null && _endTryStream != null - && _beginHandlerStream != null && _endHandlerStream != null; - } - - /// - /// Represent a token. Use one of the overloads of - /// to create a new token. - /// - public enum ILToken { } - - /// - /// Represents a local variable. Use to create a new local variable. - /// - public enum ILLocalVariable { } - - public class ILStubMethodIL : MethodIL - { - private readonly byte[] _ilBytes; - private readonly LocalVariableDefinition[] _locals; - private readonly Object[] _tokens; - private readonly MethodDesc _method; - private readonly ILExceptionRegion[] _exceptionRegions; - private readonly MethodDebugInformation _debugInformation; - - private const int MaxStackNotSet = -1; - private int _maxStack; - - public ILStubMethodIL(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, ILExceptionRegion[] exceptionRegions = null, MethodDebugInformation debugInfo = null) - { - _ilBytes = ilBytes; - _locals = locals; - _tokens = tokens; - _method = owningMethod; - _maxStack = MaxStackNotSet; - - if (exceptionRegions == null) - exceptionRegions = Array.Empty(); - _exceptionRegions = exceptionRegions; - - if (debugInfo == null) - debugInfo = MethodDebugInformation.None; - _debugInformation = debugInfo; - } - - public ILStubMethodIL(ILStubMethodIL methodIL) - { - _ilBytes = methodIL._ilBytes; - _locals = methodIL._locals; - _tokens = methodIL._tokens; - _method = methodIL._method; - _debugInformation = methodIL._debugInformation; - _exceptionRegions = methodIL._exceptionRegions; - _maxStack = methodIL._maxStack; - } - - public override MethodDesc OwningMethod - { - get - { - return _method; - } - } - - public override byte[] GetILBytes() - { - return _ilBytes; - } - - public override MethodDebugInformation GetDebugInfo() - { - return _debugInformation; - } - - public override int MaxStack - { - get - { - if (_maxStack == MaxStackNotSet) - _maxStack = this.ComputeMaxStack(); - return _maxStack; - } - } - - public override ILExceptionRegion[] GetExceptionRegions() - { - return _exceptionRegions; - } - public override bool IsInitLocals - { - get - { - return true; - } - } - - public override LocalVariableDefinition[] GetLocals() - { - return _locals; - } - public override Object GetObject(int token) - { - return _tokens[(token & 0xFFFFFF) - 1]; - } - } - - public class ILCodeLabel - { - private ILCodeStream _codeStream; - private int _offsetWithinCodeStream; - - internal bool IsPlaced - { - get - { - return _codeStream != null; - } - } - - internal int AbsoluteOffset - { - get - { - Debug.Assert(IsPlaced); - return _codeStream.RelativeToAbsoluteOffset(_offsetWithinCodeStream); - } - } - - internal ILCodeLabel() - { - } - - internal void Place(ILCodeStream codeStream, int offsetWithinCodeStream) - { - Debug.Assert(!IsPlaced); - _codeStream = codeStream; - _offsetWithinCodeStream = offsetWithinCodeStream; - } - } - - public class ILEmitter - { - private ArrayBuilder _codeStreams; - private ArrayBuilder _locals; - private ArrayBuilder _tokens; - private ArrayBuilder _finallyRegions; - - public ILEmitter() - { - } - - public ILCodeStream NewCodeStream() - { - ILCodeStream stream = new ILCodeStream(this); - _codeStreams.Add(stream); - return stream; - } - - private ILToken NewToken(Object value, int tokenType) - { - Debug.Assert(value != null); - _tokens.Add(value); - return (ILToken)(_tokens.Count | tokenType); - } - - public ILToken NewToken(TypeDesc value) - { - return NewToken(value, 0x01000000); - } - - public ILToken NewToken(MethodDesc value) - { - return NewToken(value, 0x0a000000); - } - - public ILToken NewToken(FieldDesc value) - { - return NewToken(value, 0x0a000000); - } - - public ILToken NewToken(string value) - { - return NewToken(value, 0x70000000); - } - - public ILToken NewToken(MethodSignature value) - { - return NewToken(value, 0x11000000); - } - - public ILLocalVariable NewLocal(TypeDesc localType, bool isPinned = false) - { - int index = _locals.Count; - _locals.Add(new LocalVariableDefinition(localType, isPinned)); - return (ILLocalVariable)index; - } - - public ILCodeLabel NewCodeLabel() - { - var newLabel = new ILCodeLabel(); - return newLabel; - } - - public ILExceptionRegionBuilder NewFinallyRegion() - { - var region = new ILExceptionRegionBuilder(); - _finallyRegions.Add(region); - return region; - } - - public MethodIL Link(MethodDesc owningMethod) - { - int totalLength = 0; - int numSequencePoints = 0; - - for (int i = 0; i < _codeStreams.Count; i++) - { - ILCodeStream ilCodeStream = _codeStreams[i]; - ilCodeStream._startOffsetForLinking = totalLength; - totalLength += ilCodeStream._length; - numSequencePoints += ilCodeStream._sequencePoints.Count; - } - - byte[] ilInstructions = new byte[totalLength]; - int copiedLength = 0; - for (int i = 0; i < _codeStreams.Count; i++) - { - ILCodeStream ilCodeStream = _codeStreams[i]; - ilCodeStream.PatchLabels(); - Array.Copy(ilCodeStream._instructions, 0, ilInstructions, copiedLength, ilCodeStream._length); - copiedLength += ilCodeStream._length; - } - - MethodDebugInformation debugInfo = null; - if (numSequencePoints > 0) - { - ILSequencePoint[] sequencePoints = new ILSequencePoint[numSequencePoints]; - int copiedSequencePointLength = 0; - for (int codeStreamIndex = 0; codeStreamIndex < _codeStreams.Count; codeStreamIndex++) - { - ILCodeStream ilCodeStream = _codeStreams[codeStreamIndex]; - - for (int sequencePointIndex = 0; sequencePointIndex < ilCodeStream._sequencePoints.Count; sequencePointIndex++) - { - ILSequencePoint sequencePoint = ilCodeStream._sequencePoints[sequencePointIndex]; - sequencePoints[copiedSequencePointLength] = new ILSequencePoint( - ilCodeStream._startOffsetForLinking + sequencePoint.Offset, - sequencePoint.Document, - sequencePoint.LineNumber); - copiedSequencePointLength++; - } - } - - debugInfo = new EmittedMethodDebugInformation(sequencePoints); - } - - ILExceptionRegion[] exceptionRegions = null; - - int numberOfExceptionRegions = _finallyRegions.Count; - if (numberOfExceptionRegions > 0) - { - exceptionRegions = new ILExceptionRegion[numberOfExceptionRegions]; - - for (int i = 0; i < _finallyRegions.Count; i++) - { - ILExceptionRegionBuilder region = _finallyRegions[i]; - - Debug.Assert(region.IsDefined); - - exceptionRegions[i] = new ILExceptionRegion(ILExceptionRegionKind.Finally, - region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength, - classToken: 0, filterOffset: 0); - } - } - - var result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), exceptionRegions, debugInfo); - result.CheckStackBalance(); - return result; - } - - private class EmittedMethodDebugInformation : MethodDebugInformation - { - private readonly ILSequencePoint[] _sequencePoints; - - public EmittedMethodDebugInformation(ILSequencePoint[] sequencePoints) - { - _sequencePoints = sequencePoints; - } - - public override IEnumerable GetSequencePoints() - { - return _sequencePoints; - } - } - } - - public abstract partial class ILStubMethod : MethodDesc - { - public abstract MethodIL EmitIL(); - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return false; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/InterlockedIntrinsics.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/InterlockedIntrinsics.cs deleted file mode 100644 index bf75857a937..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/InterlockedIntrinsics.cs +++ /dev/null @@ -1,45 +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.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL.Stubs -{ - /// - /// Provides method bodies for System.Threading.Interlocked intrinsics. - /// - public static class InterlockedIntrinsics - { - public static MethodIL EmitIL(MethodDesc method) - { - Debug.Assert(((MetadataType)method.OwningType).Name == "Interlocked"); - - if (method.HasInstantiation && method.Name == "CompareExchange") - { - TypeDesc objectType = method.Context.GetWellKnownType(WellKnownType.Object); - MethodDesc compareExchangeObject = method.OwningType.GetKnownMethod("CompareExchange", - new MethodSignature( - MethodSignatureFlags.Static, - genericParameterCount: 0, - returnType: objectType, - parameters: new TypeDesc[] { objectType.MakeByRefType(), objectType, objectType })); - - ILEmitter emit = new ILEmitter(); - ILCodeStream codeStream = emit.NewCodeStream(); - codeStream.EmitLdArg(0); - codeStream.EmitLdArg(1); - codeStream.EmitLdArg(2); - codeStream.Emit(ILOpcode.call, emit.NewToken(compareExchangeObject)); - codeStream.Emit(ILOpcode.ret); - return emit.Link(method); - } - - return null; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeILCodeStreams.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeILCodeStreams.cs deleted file mode 100644 index c8a7d94d49d..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeILCodeStreams.cs +++ /dev/null @@ -1,45 +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. - -namespace Internal.IL.Stubs -{ - internal sealed class PInvokeILCodeStreams - { - public ILEmitter Emitter { get; } - public ILCodeStream FunctionPointerLoadStream { get; } - public ILCodeStream MarshallingCodeStream { get; } - public ILCodeStream CallsiteSetupCodeStream { get; } - public ILCodeStream ReturnValueMarshallingCodeStream { get; } - public ILCodeStream UnmarshallingCodestream { get; } - public ILCodeStream CleanupCodeStream { get; } - public PInvokeILCodeStreams() - { - Emitter = new ILEmitter(); - - // We have these code streams: - // - FunctionPointerLoadStream is used to load the function pointer to call - // - MarshallingCodeStream is used to convert each argument into a native type and - // store that into the local - // - CallsiteSetupCodeStream is used to used to load each previously generated local - // and call the actual target native method. - // - ReturnValueMarshallingCodeStream is used to convert the native return value - // to managed one. - // - UnmarshallingCodestream is used to propagate [out] native arguments values to - // managed ones. - // - CleanupCodestream is used to perform a guaranteed cleanup - FunctionPointerLoadStream = Emitter.NewCodeStream(); - MarshallingCodeStream = Emitter.NewCodeStream(); - CallsiteSetupCodeStream = Emitter.NewCodeStream(); - ReturnValueMarshallingCodeStream = Emitter.NewCodeStream(); - UnmarshallingCodestream = Emitter.NewCodeStream(); - CleanupCodeStream = Emitter.NewCodeStream(); - } - - public PInvokeILCodeStreams(ILEmitter emitter, ILCodeStream codeStream) - { - Emitter = emitter; - MarshallingCodeStream = codeStream; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Diagnostic.cs deleted file mode 100644 index 2cb4d1ea33c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Diagnostic.cs +++ /dev/null @@ -1,19 +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 Internal.TypeSystem; - -namespace Internal.IL.Stubs -{ - partial class PInvokeTargetNativeMethod - { - public override string DiagnosticName - { - get - { - return _declMethod.DiagnosticName; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Mangling.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Mangling.cs deleted file mode 100644 index 79ea39a9001..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Mangling.cs +++ /dev/null @@ -1,27 +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 Internal.TypeSystem; - -namespace Internal.IL.Stubs -{ - partial class PInvokeTargetNativeMethod : IPrefixMangledMethod - { - MethodDesc IPrefixMangledMethod.BaseMethod - { - get - { - return _declMethod; - } - } - - string IPrefixMangledMethod.Prefix - { - get - { - return "rawpinvoke"; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Sorting.cs deleted file mode 100644 index ea754346f7a..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.Sorting.cs +++ /dev/null @@ -1,20 +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 Internal.TypeSystem; - -namespace Internal.IL.Stubs -{ - // Functionality related to deterministic ordering of types - partial class PInvokeTargetNativeMethod - { - protected internal override int ClassCode => -1626939381; - - protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) - { - var otherMethod = (PInvokeTargetNativeMethod)other; - return comparer.Compare(_declMethod, otherMethod._declMethod); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.cs deleted file mode 100644 index 519dee4e9ab..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/PInvokeTargetNativeMethod.cs +++ /dev/null @@ -1,92 +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 Internal.TypeSystem; - -namespace Internal.IL.Stubs -{ - /// - /// Synthetic method that represents the actual PInvoke target method. - /// All parameters are simple types. There will be no code - /// generated for this method. Instead, a static reference to a symbol will be emitted. - /// - public sealed partial class PInvokeTargetNativeMethod : MethodDesc - { - private readonly MethodDesc _declMethod; - private readonly MethodSignature _signature; - - public MethodDesc Target - { - get - { - return _declMethod; - } - } - - public PInvokeTargetNativeMethod(MethodDesc declMethod, MethodSignature signature) - { - _declMethod = declMethod; - _signature = signature; - } - - public override TypeSystemContext Context - { - get - { - return _declMethod.Context; - } - } - - public override TypeDesc OwningType - { - get - { - return _declMethod.OwningType; - } - } - - public override MethodSignature Signature - { - get - { - return _signature; - } - } - - public override string Name - { - get - { - return _declMethod.Name; - } - } - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return false; - } - - public override bool IsPInvoke - { - get - { - return true; - } - } - - public override bool IsNoInlining - { - get - { - // This method does not have real IL body. NoInlining stops the JIT asking for it. - return true; - } - } - - public override PInvokeMetadata GetPInvokeMethodMetadata() - { - return _declMethod.GetPInvokeMethodMetadata(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/RuntimeHelpersIntrinsics.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/RuntimeHelpersIntrinsics.cs deleted file mode 100644 index d45a6c9ec08..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/RuntimeHelpersIntrinsics.cs +++ /dev/null @@ -1,97 +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.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL.Stubs -{ - /// - /// Provides method bodies for System.Runtime.CompilerServices.RuntimeHelpers intrinsics. - /// - public static class RuntimeHelpersIntrinsics - { - public static MethodIL EmitIL(MethodDesc method) - { - Debug.Assert(((MetadataType)method.OwningType).Name == "RuntimeHelpers"); - string methodName = method.Name; - - if (methodName == "GetRawSzArrayData") - { - ILEmitter emit = new ILEmitter(); - ILCodeStream codeStream = emit.NewCodeStream(); - codeStream.EmitLdArg(0); - codeStream.Emit(ILOpcode.ldflda, emit.NewToken(method.Context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "RawArrayData").GetField("Data"))); - codeStream.Emit(ILOpcode.ret); - return emit.Link(method); - } - - // All the methods handled below are per-instantiation generic methods - if (method.Instantiation.Length != 1 || method.IsTypicalMethodDefinition) - return null; - - TypeDesc elementType = method.Instantiation[0]; - - // Fallback to non-intrinsic implementation for universal generics - if (elementType.IsCanonicalSubtype(CanonicalFormKind.Universal)) - return null; - - bool result; - if (methodName == "IsReferenceOrContainsReferences") - { - result = elementType.IsGCPointer || (elementType is DefType defType && defType.ContainsGCPointers); - } - else if (methodName == "IsReference") - { - result = elementType.IsGCPointer; - } - else if (methodName == "IsBitwiseEquatable") - { - // Ideally we could detect automatically whether a type is trivially equatable - // (i.e., its operator == could be implemented via memcmp). But for now we'll - // do the simple thing and hardcode the list of types we know fulfill this contract. - // n.b. This doesn't imply that the type's CompareTo method can be memcmp-implemented, - // as a method like CompareTo may need to take a type's signedness into account. - switch (elementType.UnderlyingType.Category) - { - case TypeFlags.Boolean: - case TypeFlags.Byte: - case TypeFlags.SByte: - case TypeFlags.Char: - case TypeFlags.UInt16: - case TypeFlags.Int16: - case TypeFlags.UInt32: - case TypeFlags.Int32: - case TypeFlags.UInt64: - case TypeFlags.Int64: - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - result = true; - break; - default: - var mdType = elementType as MetadataType; - if (mdType != null && mdType.Name == "Rune" && mdType.Namespace == "System.Text") - result = true; - else if (mdType != null && mdType.Name == "Char8" && mdType.Namespace == "System") - result = true; - else - result = false; - break; - } - } - else - { - return null; - } - - ILOpcode opcode = result ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0; - - return new ILStubMethodIL(method, new byte[] { (byte)opcode, (byte)ILOpcode.ret }, Array.Empty(), Array.Empty()); - } - } -} - diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs deleted file mode 100644 index c0e0ea1feab..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs +++ /dev/null @@ -1,141 +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.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL.Stubs -{ - /// - /// Provides method bodies for generic System.Runtime.CompilerServices.Unsafe intrinsics. - /// - public static class UnsafeIntrinsics - { - public static MethodIL EmitIL(MethodDesc method) - { - Debug.Assert(((MetadataType)method.OwningType).Name == "Unsafe"); - - switch (method.Name) - { - case "AsPointer": - return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.conv_u, (byte)ILOpcode.ret }, Array.Empty(), null); - case "SizeOf": - return EmitSizeOf(method); - case "As": - case "AsRef": - return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ret }, Array.Empty(), null); - case "Add": - return EmitAdd(method); - case "AddByteOffset": - return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.add, (byte)ILOpcode.ret }, Array.Empty(), null); - case "InitBlockUnaligned": - return new ILStubMethodIL(method, new byte[] { - (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.ldarg_2, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.unaligned), 0x01, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.initblk), - (byte)ILOpcode.ret }, Array.Empty(), null); - case "Read": - return EmitReadWrite(method, write: false); - case "Write": - return EmitReadWrite(method, write: true); - case "ReadUnaligned": - return EmitReadWrite(method, write: false, unaligned: true); - case "WriteUnaligned": - return EmitReadWrite(method, write: true, unaligned: true); - case "AreSame": - return new ILStubMethodIL(method, new byte[] - { - (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), - (byte)ILOpcode.ret }, Array.Empty(), null); - case "IsAddressGreaterThan": - return new ILStubMethodIL(method, new byte[] - { - (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.cgt_un), - (byte)ILOpcode.ret }, Array.Empty(), null); - case "IsAddressLessThan": - return new ILStubMethodIL(method, new byte[] - { - (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.clt_un), - (byte)ILOpcode.ret }, Array.Empty(), null); - case "ByteOffset": - return new ILStubMethodIL(method, new byte[] - { - (byte)ILOpcode.ldarg_1, (byte)ILOpcode.ldarg_0, - (byte)ILOpcode.sub, - (byte)ILOpcode.ret }, Array.Empty(), null); - case "NullRef": - return new ILStubMethodIL(method, new byte[] - { - (byte)ILOpcode.ldc_i4_0, (byte)ILOpcode.conv_u, - (byte)ILOpcode.ret }, Array.Empty(), null); - case "IsNullRef": - return new ILStubMethodIL(method, new byte[] - { - (byte)ILOpcode.ldarg_0, - (byte)ILOpcode.ldc_i4_0, (byte)ILOpcode.conv_u, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), - (byte)ILOpcode.ret }, Array.Empty(), null); - case "SkipInit": - return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ret }, Array.Empty(), null); - } - - return null; - } - - private static MethodIL EmitSizeOf(MethodDesc method) - { - Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 0); - - TypeSystemContext context = method.Context; - - ILEmitter emit = new ILEmitter(); - ILCodeStream codeStream = emit.NewCodeStream(); - codeStream.Emit(ILOpcode.sizeof_, emit.NewToken(context.GetSignatureVariable(0, method: true))); - codeStream.Emit(ILOpcode.ret); - return emit.Link(method); - } - - private static MethodIL EmitAdd(MethodDesc method) - { - Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 2); - - TypeSystemContext context = method.Context; - - ILEmitter emit = new ILEmitter(); - ILCodeStream codeStream = emit.NewCodeStream(); - codeStream.Emit(ILOpcode.ldarg_1); - codeStream.Emit(ILOpcode.sizeof_, emit.NewToken(context.GetSignatureVariable(0, method: true))); - codeStream.Emit(ILOpcode.conv_i); - codeStream.Emit(ILOpcode.mul); - codeStream.Emit(ILOpcode.ldarg_0); - codeStream.Emit(ILOpcode.add); - codeStream.Emit(ILOpcode.ret); - return emit.Link(method); - } - - private static MethodIL EmitReadWrite(MethodDesc method, bool write, bool unaligned = false) - { - Debug.Assert(method.Signature.IsStatic && method.Signature.Length == (write ? 2 : 1)); - - TypeSystemContext context = method.Context; - - ILEmitter emit = new ILEmitter(); - ILCodeStream codeStream = emit.NewCodeStream(); - - codeStream.EmitLdArg(0); - if (write) codeStream.EmitLdArg(1); - if (unaligned) codeStream.EmitUnaligned(); - codeStream.Emit(write ? ILOpcode.stobj : ILOpcode.ldobj, - emit.NewToken(context.GetSignatureVariable(0, method: true))); - codeStream.Emit(ILOpcode.ret); - return emit.Link(method); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs deleted file mode 100644 index 4a9ca72eb9f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs +++ /dev/null @@ -1,107 +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.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL.Stubs -{ - /// - /// Provides method bodies for System.Threading.Volatile intrinsics. - /// - public static class VolatileIntrinsics - { - public static MethodIL EmitIL(MethodDesc method) - { - Debug.Assert(((MetadataType)method.OwningType).Name == "Volatile"); - - bool isRead = method.Name == "Read"; - if (!isRead && method.Name != "Write") - return null; - - // All interesting methods have a signature that starts with `ref location` - if (method.Signature.Length == 0 || !method.Signature[0].IsByRef) - return null; - - ILOpcode opcode; - switch (((ByRefType)method.Signature[0]).ParameterType.Category) - { - case TypeFlags.SignatureMethodVariable: - opcode = isRead ? ILOpcode.ldind_ref : ILOpcode.stind_ref; - break; - - case TypeFlags.Boolean: - case TypeFlags.SByte: - opcode = isRead ? ILOpcode.ldind_i1 : ILOpcode.stind_i1; - break; - case TypeFlags.Byte: - opcode = isRead ? ILOpcode.ldind_u1 : ILOpcode.stind_i1; - break; - case TypeFlags.Int16: - opcode = isRead ? ILOpcode.ldind_i2 : ILOpcode.stind_i2; - break; - case TypeFlags.UInt16: - opcode = isRead ? ILOpcode.ldind_u2 : ILOpcode.stind_i2; - break; - case TypeFlags.Int32: - opcode = isRead ? ILOpcode.ldind_i4 : ILOpcode.stind_i4; - break; - case TypeFlags.UInt32: - opcode = isRead ? ILOpcode.ldind_u4 : ILOpcode.stind_i4; - break; - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - opcode = isRead ? ILOpcode.ldind_i : ILOpcode.stind_i; - break; - case TypeFlags.Single: - opcode = isRead ? ILOpcode.ldind_r4 : ILOpcode.stind_r4; - break; - - // - // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data. - // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types. - // The implementation in mscorlib already does this, so we will only substitute a new - // IL body if we're running on a 64-bit platform. - // - case TypeFlags.Int64 when method.Context.Target.PointerSize == 8: - case TypeFlags.UInt64 when method.Context.Target.PointerSize == 8: - opcode = isRead ? ILOpcode.ldind_i8 : ILOpcode.stind_i8; - break; - case TypeFlags.Double when method.Context.Target.PointerSize == 8: - opcode = isRead ? ILOpcode.ldind_r8 : ILOpcode.stind_r8; - break; - default: - return null; - } - - byte[] ilBytes; - if (isRead) - { - ilBytes = new byte[] - { - (byte)ILOpcode.ldarg_0, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.volatile_), - (byte)opcode, - (byte)ILOpcode.ret - }; - } - else - { - ilBytes = new byte[] - { - (byte)ILOpcode.ldarg_0, - (byte)ILOpcode.ldarg_1, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.volatile_), - (byte)opcode, - (byte)ILOpcode.ret - }; - } - - return new ILStubMethodIL(method, ilBytes, Array.Empty(), null); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/FieldDesc.Interop.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/FieldDesc.Interop.cs deleted file mode 100644 index 1e7a3e3ba76..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/FieldDesc.Interop.cs +++ /dev/null @@ -1,25 +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. - -namespace Internal.TypeSystem -{ - partial class FieldDesc - { - /// - /// Returns description of how the field should be marshalled to native code. - /// - public virtual MarshalAsDescriptor GetMarshalAsDescriptor() - { - return null; - } - } - - partial class FieldForInstantiatedType - { - public override MarshalAsDescriptor GetMarshalAsDescriptor() - { - return _fieldDef.GetMarshalAsDescriptor(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalHelpers.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalHelpers.cs deleted file mode 100644 index fc857c30381..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalHelpers.cs +++ /dev/null @@ -1,758 +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.IL; -using Debug = System.Diagnostics.Debug; -using Internal.IL.Stubs; - -namespace Internal.TypeSystem.Interop -{ - public static partial class MarshalHelpers - { - internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type, - MarshallerKind kind, - MarshallerKind elementMarshallerKind, -#if !READYTORUN - InteropStateManager interopStateManager, -#endif - MarshalAsDescriptor marshalAs, - bool isArrayElement = false) - { - TypeSystemContext context = type.Context; - NativeTypeKind nativeType = NativeTypeKind.Default; - if (marshalAs != null) - { - nativeType = isArrayElement ? marshalAs.ArraySubType : marshalAs.Type; - } - - switch (kind) - { - case MarshallerKind.BlittableValue: - { - switch (nativeType) - { - case NativeTypeKind.I1: - return context.GetWellKnownType(WellKnownType.SByte); - case NativeTypeKind.U1: - return context.GetWellKnownType(WellKnownType.Byte); - case NativeTypeKind.I2: - return context.GetWellKnownType(WellKnownType.Int16); - case NativeTypeKind.U2: - return context.GetWellKnownType(WellKnownType.UInt16); - case NativeTypeKind.I4: - return context.GetWellKnownType(WellKnownType.Int32); - case NativeTypeKind.U4: - return context.GetWellKnownType(WellKnownType.UInt32); - case NativeTypeKind.I8: - return context.GetWellKnownType(WellKnownType.Int64); - case NativeTypeKind.U8: - return context.GetWellKnownType(WellKnownType.UInt64); - case NativeTypeKind.R4: - return context.GetWellKnownType(WellKnownType.Single); - case NativeTypeKind.R8: - return context.GetWellKnownType(WellKnownType.Double); - default: - return type.UnderlyingType; - } - } - - case MarshallerKind.Bool: - return context.GetWellKnownType(WellKnownType.Int32); - - case MarshallerKind.CBool: - return context.GetWellKnownType(WellKnownType.Byte); - - case MarshallerKind.Enum: - case MarshallerKind.BlittableStruct: - case MarshallerKind.Decimal: - case MarshallerKind.VoidReturn: - return type; - -#if !READYTORUN - case MarshallerKind.Struct: - case MarshallerKind.LayoutClass: - return interopStateManager.GetStructMarshallingNativeType((MetadataType)type); -#endif - - case MarshallerKind.BlittableStructPtr: - return type.MakePointerType(); - - case MarshallerKind.HandleRef: - return context.GetWellKnownType(WellKnownType.IntPtr); - - case MarshallerKind.UnicodeChar: - if (nativeType == NativeTypeKind.U2) - return context.GetWellKnownType(WellKnownType.UInt16); - else - return context.GetWellKnownType(WellKnownType.Int16); - - case MarshallerKind.OleDateTime: - return context.GetWellKnownType(WellKnownType.Double); - - case MarshallerKind.SafeHandle: - case MarshallerKind.CriticalHandle: - return context.GetWellKnownType(WellKnownType.IntPtr); - - case MarshallerKind.UnicodeString: - case MarshallerKind.UnicodeStringBuilder: - return context.GetWellKnownType(WellKnownType.Char).MakePointerType(); - - case MarshallerKind.AnsiString: - case MarshallerKind.AnsiStringBuilder: - case MarshallerKind.UTF8String: - return context.GetWellKnownType(WellKnownType.Byte).MakePointerType(); - - case MarshallerKind.BlittableArray: - case MarshallerKind.Array: - case MarshallerKind.AnsiCharArray: - { - ArrayType arrayType = type as ArrayType; - Debug.Assert(arrayType != null, "Expecting array"); - - // - // We need to construct the unsafe array from the right unsafe array element type - // - TypeDesc elementNativeType = GetNativeTypeFromMarshallerKind( - arrayType.ElementType, - elementMarshallerKind, - MarshallerKind.Unknown, -#if !READYTORUN - interopStateManager, -#endif - marshalAs, - isArrayElement: true); - - return elementNativeType.MakePointerType(); - } - - case MarshallerKind.AnsiChar: - return context.GetWellKnownType(WellKnownType.Byte); - - case MarshallerKind.FunctionPointer: - return context.GetWellKnownType(WellKnownType.IntPtr); - -#if !READYTORUN - case MarshallerKind.ByValUnicodeString: - case MarshallerKind.ByValAnsiString: - { - var inlineArrayCandidate = GetInlineArrayCandidate(context.GetWellKnownType(WellKnownType.Char), elementMarshallerKind, interopStateManager, marshalAs); - return interopStateManager.GetInlineArrayType(inlineArrayCandidate); - } - - case MarshallerKind.ByValAnsiCharArray: - case MarshallerKind.ByValArray: - { - ArrayType arrayType = type as ArrayType; - Debug.Assert(arrayType != null, "Expecting array"); - - var inlineArrayCandidate = GetInlineArrayCandidate(arrayType.ElementType, elementMarshallerKind, interopStateManager, marshalAs); - - return interopStateManager.GetInlineArrayType(inlineArrayCandidate); - } -#endif - - case MarshallerKind.LayoutClassPtr: - case MarshallerKind.AsAnyA: - case MarshallerKind.AsAnyW: - return context.GetWellKnownType(WellKnownType.IntPtr); - - case MarshallerKind.Unknown: - default: - throw new NotSupportedException(); - } - } - - internal static MarshallerKind GetMarshallerKind( - TypeDesc type, - MarshalAsDescriptor marshalAs, - bool isReturn, - bool isAnsi, - MarshallerType marshallerType, - out MarshallerKind elementMarshallerKind) - { - elementMarshallerKind = MarshallerKind.Invalid; - - bool isByRef = false; - if (type.IsByRef) - { - isByRef = true; - - type = type.GetParameterType(); - - // Compat note: CLR allows ref returning blittable structs for IJW - if (isReturn) - return MarshallerKind.Invalid; - } - TypeSystemContext context = type.Context; - NativeTypeKind nativeType = NativeTypeKind.Default; - bool isField = marshallerType == MarshallerType.Field; - - if (marshalAs != null) - nativeType = marshalAs.Type; - - // - // Determine MarshalerKind - // - // This mostly resembles desktop CLR and .NET Native code as we need to match their behavior - // - if (type.IsPrimitive) - { - switch (type.Category) - { - case TypeFlags.Void: - return MarshallerKind.VoidReturn; - - case TypeFlags.Boolean: - switch (nativeType) - { - case NativeTypeKind.Default: - case NativeTypeKind.Boolean: - return MarshallerKind.Bool; - - case NativeTypeKind.U1: - case NativeTypeKind.I1: - return MarshallerKind.CBool; - - default: - return MarshallerKind.Invalid; - } - - case TypeFlags.Char: - switch (nativeType) - { - case NativeTypeKind.I1: - case NativeTypeKind.U1: - return MarshallerKind.AnsiChar; - - case NativeTypeKind.I2: - case NativeTypeKind.U2: - return MarshallerKind.UnicodeChar; - - case NativeTypeKind.Default: - if (isAnsi) - return MarshallerKind.AnsiChar; - else - return MarshallerKind.UnicodeChar; - default: - return MarshallerKind.Invalid; - } - - case TypeFlags.SByte: - case TypeFlags.Byte: - if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - - case TypeFlags.Int16: - case TypeFlags.UInt16: - if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - - case TypeFlags.Int32: - case TypeFlags.UInt32: - if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - - case TypeFlags.Int64: - case TypeFlags.UInt64: - if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - if (nativeType == NativeTypeKind.SysInt || nativeType == NativeTypeKind.SysUInt || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - - case TypeFlags.Single: - if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - - case TypeFlags.Double: - if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - - default: - return MarshallerKind.Invalid; - } - } - else if (type.IsValueType) - { - if (type.IsEnum) - return MarshallerKind.Enum; - - if (InteropTypes.IsSystemDateTime(context, type)) - { - if (nativeType == NativeTypeKind.Default || - nativeType == NativeTypeKind.Struct) - return MarshallerKind.OleDateTime; - else - return MarshallerKind.Invalid; - } - else if (InteropTypes.IsHandleRef(context, type)) - { - if (nativeType == NativeTypeKind.Default) - return MarshallerKind.HandleRef; - else - return MarshallerKind.Invalid; - } - else if (InteropTypes.IsSystemDecimal(context, type)) - { - if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default) - return MarshallerKind.Decimal; - else if (nativeType == NativeTypeKind.LPStruct && !isField && !isReturn) - return MarshallerKind.BlittableStructPtr; - else - return MarshallerKind.Invalid; - } - else if (InteropTypes.IsSystemGuid(context, type)) - { - if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableStruct; - else if (nativeType == NativeTypeKind.LPStruct && !isField && !isReturn) - return MarshallerKind.BlittableStructPtr; - else - return MarshallerKind.Invalid; - } - else if (InteropTypes.IsSystemArgIterator(context, type)) - { - // Don't want to fall through to the blittable/haslayout case - return MarshallerKind.Invalid; - } - - bool isBlittable = MarshalUtils.IsBlittableType(type); - - // Blittable generics are allowed to be marshalled with the following exceptions: - // * ByReference: This represents an interior pointer and is not actually blittable - // * Nullable: We don't want to be locked into the default behavior as we may want special handling later - // * Vector64: Represents the __m64 ABI primitive which requires currently unimplemented handling - // * Vector128: Represents the __m128 ABI primitive which requires currently unimplemented handling - // * Vector256: Represents the __m256 ABI primitive which requires currently unimplemented handling - // * Vector: Has a variable size (either __m128 or __m256) and isn't readily usable for inteorp scenarios - - if (type.HasInstantiation && (!isBlittable - || InteropTypes.IsSystemByReference(context, type) - || InteropTypes.IsSystemNullable(context, type) - || InteropTypes.IsSystemRuntimeIntrinsicsVector64T(context, type) - || InteropTypes.IsSystemRuntimeIntrinsicsVector128T(context, type) - || InteropTypes.IsSystemRuntimeIntrinsicsVector256T(context, type) - || InteropTypes.IsSystemNumericsVectorT(context, type))) - { - // Generic types cannot be marshaled. - return MarshallerKind.Invalid; - } - - if (isBlittable) - { - if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct) - return MarshallerKind.Invalid; - - return MarshallerKind.BlittableStruct; - } - else if (((MetadataType)type).HasLayout()) - { - if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct) - return MarshallerKind.Invalid; - - return MarshallerKind.Struct; - } - else - { - return MarshallerKind.Invalid; - } - } - else if (type.IsSzArray) - { -#if READYTORUN - // We don't want the additional test/maintenance cost of this in R2R. - if (isByRef) - return MarshallerKind.Invalid; -#else - _ = isByRef; -#endif - - if (nativeType == NativeTypeKind.Default) - nativeType = NativeTypeKind.Array; - - switch (nativeType) - { - case NativeTypeKind.Array: - { - if (isField || isReturn) - return MarshallerKind.Invalid; - - var arrayType = (ArrayType)type; - - elementMarshallerKind = GetArrayElementMarshallerKind( - arrayType, - marshalAs, - isAnsi); - - // If element is invalid type, the array itself is invalid - if (elementMarshallerKind == MarshallerKind.Invalid) - return MarshallerKind.Invalid; - - if (elementMarshallerKind == MarshallerKind.AnsiChar) - return MarshallerKind.AnsiCharArray; - else if (elementMarshallerKind == MarshallerKind.UnicodeChar // Arrays of unicode char should be marshalled as blittable arrays - || elementMarshallerKind == MarshallerKind.Enum - || elementMarshallerKind == MarshallerKind.BlittableValue) - return MarshallerKind.BlittableArray; - else - return MarshallerKind.Array; - } - - case NativeTypeKind.ByValArray: // fix sized array - { - var arrayType = (ArrayType)type; - elementMarshallerKind = GetArrayElementMarshallerKind( - arrayType, - marshalAs, - isAnsi); - - // If element is invalid type, the array itself is invalid - if (elementMarshallerKind == MarshallerKind.Invalid) - return MarshallerKind.Invalid; - - if (elementMarshallerKind == MarshallerKind.AnsiChar) - return MarshallerKind.ByValAnsiCharArray; - else - return MarshallerKind.ByValArray; - } - - default: - return MarshallerKind.Invalid; - } - } - else if (type.IsPointer) - { - TypeDesc parameterType = ((PointerType)type).ParameterType; - - if ((!parameterType.IsEnum - && !parameterType.IsPrimitive - && !MarshalUtils.IsBlittableType(parameterType)) - || parameterType.IsGCPointer) - { - // Pointers cannot reference marshaled structures. Use ByRef instead. - return MarshallerKind.Invalid; - } - - if (nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - } - else if (type.IsFunctionPointer) - { - if (nativeType == NativeTypeKind.Func || nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - } - else if (type.IsDelegate) - { - if (type.HasInstantiation) - { - // Generic types cannot be marshaled. - return MarshallerKind.Invalid; - } - - if (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Func) - return MarshallerKind.FunctionPointer; - else - return MarshallerKind.Invalid; - } - else if (type.IsString) - { - switch (nativeType) - { - case NativeTypeKind.LPWStr: - return MarshallerKind.UnicodeString; - - case NativeTypeKind.LPStr: - return MarshallerKind.AnsiString; - - case NativeTypeKind.LPUTF8Str: - return MarshallerKind.UTF8String; - - case NativeTypeKind.LPTStr: - return MarshallerKind.UnicodeString; - - case NativeTypeKind.ByValTStr: - if (isAnsi) - { - elementMarshallerKind = MarshallerKind.AnsiChar; - return MarshallerKind.ByValAnsiString; - } - else - { - elementMarshallerKind = MarshallerKind.UnicodeChar; - return MarshallerKind.ByValUnicodeString; - } - - case NativeTypeKind.Default: - if (isAnsi) - return MarshallerKind.AnsiString; - else - return MarshallerKind.UnicodeString; - - default: - return MarshallerKind.Invalid; - } - } - else if (type.IsObject) - { - if (nativeType == NativeTypeKind.AsAny) - return isAnsi ? MarshallerKind.AsAnyA : MarshallerKind.AsAnyW; - else - return MarshallerKind.Invalid; - } - else if (InteropTypes.IsStringBuilder(context, type)) - { - switch (nativeType) - { - case NativeTypeKind.Default: - if (isAnsi) - { - return MarshallerKind.AnsiStringBuilder; - } - else - { - return MarshallerKind.UnicodeStringBuilder; - } - - case NativeTypeKind.LPStr: - return MarshallerKind.AnsiStringBuilder; - - case NativeTypeKind.LPWStr: - return MarshallerKind.UnicodeStringBuilder; - default: - return MarshallerKind.Invalid; - } - } - else if (InteropTypes.IsSafeHandle(context, type)) - { - if (nativeType == NativeTypeKind.Default) - return MarshallerKind.SafeHandle; - else - return MarshallerKind.Invalid; - } - else if (InteropTypes.IsCriticalHandle(context, type)) - { - if (nativeType == NativeTypeKind.Default) - return MarshallerKind.CriticalHandle; - else - return MarshallerKind.Invalid; - } - else if (type is MetadataType mdType && mdType.HasLayout()) - { - if (type.HasInstantiation) - { - // Generic types cannot be marshaled. - return MarshallerKind.Invalid; - } - - if (!isField && nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.LPStruct) - return MarshallerKind.LayoutClassPtr; - else if (isField && (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Struct)) - return MarshallerKind.LayoutClass; - else - return MarshallerKind.Invalid; - } - else - return MarshallerKind.Invalid; - } - - private static MarshallerKind GetArrayElementMarshallerKind( - ArrayType arrayType, - MarshalAsDescriptor marshalAs, - bool isAnsi) - { - TypeDesc elementType = arrayType.ElementType; - NativeTypeKind nativeType = NativeTypeKind.Default; - TypeSystemContext context = arrayType.Context; - - if (marshalAs != null) - nativeType = (NativeTypeKind)marshalAs.ArraySubType; - - if (elementType.IsPrimitive) - { - switch (elementType.Category) - { - case TypeFlags.Char: - switch (nativeType) - { - case NativeTypeKind.I1: - case NativeTypeKind.U1: - return MarshallerKind.AnsiChar; - case NativeTypeKind.I2: - case NativeTypeKind.U2: - return MarshallerKind.UnicodeChar; - default: - if (isAnsi) - return MarshallerKind.AnsiChar; - else - return MarshallerKind.UnicodeChar; - } - - case TypeFlags.Boolean: - switch (nativeType) - { - case NativeTypeKind.Boolean: - return MarshallerKind.Bool; - case NativeTypeKind.I1: - case NativeTypeKind.U1: - return MarshallerKind.CBool; - case NativeTypeKind.Default: - default: - return MarshallerKind.Bool; - } - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - return MarshallerKind.BlittableValue; - - case TypeFlags.Void: - return MarshallerKind.Invalid; - - case TypeFlags.SByte: - case TypeFlags.Int16: - case TypeFlags.Int32: - case TypeFlags.Int64: - case TypeFlags.Byte: - case TypeFlags.UInt16: - case TypeFlags.UInt32: - case TypeFlags.UInt64: - case TypeFlags.Single: - case TypeFlags.Double: - return MarshallerKind.BlittableValue; - default: - return MarshallerKind.Invalid; - } - } - else if (elementType.IsValueType) - { - if (elementType.IsEnum) - return MarshallerKind.Enum; - - if (InteropTypes.IsSystemDecimal(context, elementType)) - { - switch (nativeType) - { - case NativeTypeKind.Default: - case NativeTypeKind.Struct: - return MarshallerKind.Decimal; - - case NativeTypeKind.LPStruct: - return MarshallerKind.BlittableStructPtr; - - default: - return MarshallerKind.Invalid; - } - } - else if (InteropTypes.IsSystemGuid(context, elementType)) - { - switch (nativeType) - { - case NativeTypeKind.Default: - case NativeTypeKind.Struct: - return MarshallerKind.BlittableValue; - - case NativeTypeKind.LPStruct: - return MarshallerKind.BlittableStructPtr; - - default: - return MarshallerKind.Invalid; - } - } - else if (InteropTypes.IsSystemDateTime(context, elementType)) - { - if (nativeType == NativeTypeKind.Default || - nativeType == NativeTypeKind.Struct) - { - return MarshallerKind.OleDateTime; - } - else - { - return MarshallerKind.Invalid; - } - } - else if (InteropTypes.IsHandleRef(context, elementType)) - { - if (nativeType == NativeTypeKind.Default) - return MarshallerKind.HandleRef; - else - return MarshallerKind.Invalid; - } - else - { - if (MarshalUtils.IsBlittableType(elementType)) - { - switch (nativeType) - { - case NativeTypeKind.Default: - case NativeTypeKind.Struct: - return MarshallerKind.BlittableStruct; - - default: - return MarshallerKind.Invalid; - } - } - else - { - // TODO: Differentiate between struct and Union, we only need to support struct not union here - return MarshallerKind.Struct; - } - } - } - else if (elementType.IsPointer || elementType.IsFunctionPointer) - { - if (nativeType == NativeTypeKind.Default) - return MarshallerKind.BlittableValue; - else - return MarshallerKind.Invalid; - } - else if (elementType.IsString) - { - switch (nativeType) - { - case NativeTypeKind.Default: - if (isAnsi) - return MarshallerKind.AnsiString; - else - return MarshallerKind.UnicodeString; - case NativeTypeKind.LPStr: - return MarshallerKind.AnsiString; - case NativeTypeKind.LPWStr: - return MarshallerKind.UnicodeString; - default: - return MarshallerKind.Invalid; - } - } - // else if (elementType.IsObject) - // { - // if (nativeType == NativeTypeKind.Invalid) - // return MarshallerKind.Variant; - // else - // return MarshallerKind.Invalid; - // } - else - { - return MarshallerKind.Invalid; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalUtils.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalUtils.cs deleted file mode 100644 index ce0897a1177..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalUtils.cs +++ /dev/null @@ -1,74 +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; - -namespace Internal.TypeSystem.Interop -{ - public static class MarshalUtils - { - /// - /// Returns true if this type has a common representation in both managed and unmanaged memory - /// and does not require special handling by the interop marshaler. - /// - public static bool IsBlittableType(TypeDesc type) - { - if (!type.IsDefType) - { - return false; - } - - TypeDesc baseType = type.BaseType; - bool hasNonTrivialParent = baseType != null - && !baseType.IsWellKnownType(WellKnownType.Object) - && !baseType.IsWellKnownType(WellKnownType.ValueType); - - if (hasNonTrivialParent && !IsBlittableType(baseType)) - { - return false; - } - - var mdType = (MetadataType)type; - - if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout) - { - return false; - } - - foreach (FieldDesc field in type.GetFields()) - { - if (field.IsStatic) - { - continue; - } - - if (!field.FieldType.IsValueType) - { - // Types with fields of non-value types cannot be blittable - // This check prevents possible infinite recursion where GetMarshallerKind would call back to IsBlittable e.g. for - // the case of classes with pointer members to the class itself. - return false; - } - - MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind( - field.FieldType, - field.GetMarshalAsDescriptor(), - isReturn: false, - isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass, - MarshallerType.Field, - elementMarshallerKind: out var _); - - if (marshallerKind != MarshallerKind.Enum - && marshallerKind != MarshallerKind.BlittableValue - && marshallerKind != MarshallerKind.BlittableStruct - && marshallerKind != MarshallerKind.UnicodeChar) - { - return false; - } - } - - return true; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/Marshaller.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/Marshaller.cs deleted file mode 100644 index f037e12b780..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/Marshaller.cs +++ /dev/null @@ -1,1956 +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 System.Runtime.InteropServices; -using Internal.IL.Stubs; -using Internal.IL; - -using Debug = System.Diagnostics.Debug; -using ILLocalVariable = Internal.IL.Stubs.ILLocalVariable; - -namespace Internal.TypeSystem.Interop -{ - enum MarshallerKind - { - Unknown, - BlittableValue, - Array, - BlittableArray, - Bool, // 4 byte bool - CBool, // 1 byte bool - Enum, - AnsiChar, // Marshal char (Unicode 16bits) for byte (Ansi 8bits) - UnicodeChar, - AnsiCharArray, - ByValArray, - ByValAnsiCharArray, // Particular case of ByValArray because the conversion between wide Char and Byte need special treatment. - AnsiString, - UnicodeString, - UTF8String, - ByValAnsiString, - ByValUnicodeString, - AnsiStringBuilder, - UnicodeStringBuilder, - FunctionPointer, - SafeHandle, - CriticalHandle, - HandleRef, - VoidReturn, - Variant, - Object, - OleDateTime, - Decimal, - Guid, - Struct, - BlittableStruct, - BlittableStructPtr, // Additional indirection on top of blittable struct. Used by MarshalAs(LpStruct) - LayoutClass, - LayoutClassPtr, - AsAnyA, - AsAnyW, - Invalid - } - public enum MarshalDirection - { - Forward, // safe-to-unsafe / managed-to-native - Reverse, // unsafe-to-safe / native-to-managed - } - - public enum MarshallerType - { - Argument, - Element, - Field - } - - // Each type of marshaller knows how to generate the marshalling code for the argument it marshals. - // Marshallers contain method related marshalling information (which is common to all the Marshallers) - // and also argument specific marshalling informaiton - abstract partial class Marshaller - { - #region Instance state information - public TypeSystemContext Context; -#if !READYTORUN - public InteropStateManager InteropStateManager; -#endif - public MarshallerKind MarshallerKind; - public MarshallerType MarshallerType; - public MarshalAsDescriptor MarshalAsDescriptor; - public MarshallerKind ElementMarshallerKind; - public int Index; - public TypeDesc ManagedType; - public TypeDesc ManagedParameterType; - public PInvokeFlags PInvokeFlags; - protected Marshaller[] Marshallers; - private TypeDesc _nativeType; - private TypeDesc _nativeParamType; - - /// - /// Native Type of the value being marshalled - /// For by-ref scenarios (ref T), Native Type is T - /// - public TypeDesc NativeType - { - get - { - if (_nativeType == null) - { - _nativeType = MarshalHelpers.GetNativeTypeFromMarshallerKind( - ManagedType, - MarshallerKind, - ElementMarshallerKind, -#if !READYTORUN - InteropStateManager, -#endif - MarshalAsDescriptor); - Debug.Assert(_nativeType != null); - } - - return _nativeType; - } - } - - /// - /// NativeType appears in function parameters - /// For by-ref scenarios (ref T), NativeParameterType is T* - /// - public TypeDesc NativeParameterType - { - get - { - if (_nativeParamType == null) - { - TypeDesc nativeParamType = NativeType; - if (IsNativeByRef) - nativeParamType = nativeParamType.MakePointerType(); - _nativeParamType = nativeParamType; - } - - return _nativeParamType; - } - } - - /// - /// Indicates whether cleanup is necessay if this marshaller is used - /// as an element of an array marshaller - /// - internal virtual bool CleanupRequired - { - get - { - return false; - } - } - - public bool In; - public bool Out; - public bool Return; - public bool IsManagedByRef; // Whether managed argument is passed by ref - public bool IsNativeByRef; // Whether native argument is passed by byref - // There are special cases (such as LpStruct, and class) that - // isNativeByRef != IsManagedByRef - public MarshalDirection MarshalDirection; - protected PInvokeILCodeStreams _ilCodeStreams; - protected Home _managedHome; - protected Home _nativeHome; - #endregion - - enum HomeType - { - Arg, - Local, - ByRefArg, - ByRefLocal - } - - /// - /// Abstraction for handling by-ref and non-by-ref locals/arguments - /// - internal class Home - { - public Home(ILLocalVariable var, TypeDesc type, bool isByRef) - { - _homeType = isByRef ? HomeType.ByRefLocal : HomeType.Local; - _type = type; - _var = var; - } - - public Home(int argIndex, TypeDesc type, bool isByRef) - { - _homeType = isByRef ? HomeType.ByRefArg : HomeType.Arg; - _type = type; - _argIndex = argIndex; - } - - public void LoadValue(ILCodeStream stream) - { - switch (_homeType) - { - case HomeType.Arg: - stream.EmitLdArg(_argIndex); - break; - case HomeType.ByRefArg: - stream.EmitLdArg(_argIndex); - stream.EmitLdInd(_type); - break; - case HomeType.Local: - stream.EmitLdLoc(_var); - break; - case HomeType.ByRefLocal: - stream.EmitLdLoc(_var); - stream.EmitLdInd(_type); - break; - default: - Debug.Assert(false); - break; - } - } - - public void LoadAddr(ILCodeStream stream) - { - switch (_homeType) - { - case HomeType.Arg: - stream.EmitLdArga(_argIndex); - break; - case HomeType.ByRefArg: - stream.EmitLdArg(_argIndex); - break; - case HomeType.Local: - stream.EmitLdLoca(_var); - break; - case HomeType.ByRefLocal: - stream.EmitLdLoc(_var); - break; - default: - Debug.Assert(false); - break; - } - } - - public void StoreValue(ILCodeStream stream) - { - switch (_homeType) - { - case HomeType.Arg: - Debug.Fail("Unexpectting setting value on non-byref arg"); - break; - case HomeType.Local: - stream.EmitStLoc(_var); - break; - default: - // Storing by-ref arg/local is not supported because StInd require - // address to be pushed first. Instead we need to introduce a non-byref - // local and propagate value as needed for by-ref arguments - Debug.Assert(false); - break; - } - } - - HomeType _homeType; - TypeDesc _type; - ILLocalVariable _var; - int _argIndex; - } - - #region Creation of marshallers - - /// - /// Protected ctor - /// Only Marshaller.CreateMarshaller can create a marshaller - /// - protected Marshaller() - { - } - - /// - /// Create a marshaller - /// - /// type of the parameter to marshal - /// The created Marshaller - public static Marshaller CreateMarshaller(TypeDesc parameterType, - MarshallerType marshallerType, - MarshalAsDescriptor marshalAs, - MarshalDirection direction, - Marshaller[] marshallers, -#if !READYTORUN - InteropStateManager interopStateManager, -#endif - int index, - PInvokeFlags flags, - bool isIn, - bool isOut, - bool isReturn) - { - MarshallerKind elementMarshallerKind; - MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(parameterType, - marshalAs, - isReturn, - flags.CharSet == CharSet.Ansi, - marshallerType, - out elementMarshallerKind); - - TypeSystemContext context = parameterType.Context; - // Create the marshaller based on MarshallerKind - Marshaller marshaller = CreateMarshaller(marshallerKind); - marshaller.Context = context; -#if !READYTORUN - marshaller.InteropStateManager = interopStateManager; -#endif - marshaller.MarshallerKind = marshallerKind; - marshaller.MarshallerType = marshallerType; - marshaller.ElementMarshallerKind = elementMarshallerKind; - marshaller.ManagedParameterType = parameterType; - marshaller.ManagedType = parameterType.IsByRef ? parameterType.GetParameterType() : parameterType; - marshaller.Return = isReturn; - marshaller.IsManagedByRef = parameterType.IsByRef; - marshaller.IsNativeByRef = marshaller.IsManagedByRef /* || isRetVal || LpStruct /etc */; - marshaller.In = isIn; - marshaller.MarshalDirection = direction; - marshaller.MarshalAsDescriptor = marshalAs; - marshaller.Marshallers = marshallers; - marshaller.Index = index; - marshaller.PInvokeFlags = flags; - - // - // Desktop ignores [Out] on marshaling scenarios where they don't make sense - // - if (isOut) - { - // Passing as [Out] by ref is always valid. - if (!marshaller.IsManagedByRef) - { - // Ignore [Out] for ValueType, string and pointers - if (parameterType.IsValueType || parameterType.IsString || parameterType.IsPointer || parameterType.IsFunctionPointer) - { - isOut = false; - } - } - } - marshaller.Out = isOut; - - if (!marshaller.In && !marshaller.Out) - { - // - // Rules for in/out - // 1. ByRef args: [in]/[out] implied by default - // 2. StringBuilder: [in, out] by default - // 3. non-ByRef args: [In] is implied if no [In]/[Out] is specified - // - if (marshaller.IsManagedByRef) - { - marshaller.In = true; - marshaller.Out = true; - } - else if (InteropTypes.IsStringBuilder(context, parameterType)) - { - marshaller.In = true; - marshaller.Out = true; - } - else - { - marshaller.In = true; - } - } - - // For unicodestring/ansistring, ignore out when it's in - if (!marshaller.IsManagedByRef && marshaller.In) - { - if (marshaller.MarshallerKind == MarshallerKind.AnsiString || marshaller.MarshallerKind == MarshallerKind.UnicodeString) - marshaller.Out = false; - } - - return marshaller; - } - - public static Marshaller[] GetMarshallersForMethod(MethodDesc targetMethod) - { - Debug.Assert(targetMethod.IsPInvoke); - - MarshalDirection direction = MarshalDirection.Forward; - MethodSignature methodSig = targetMethod.Signature; - PInvokeFlags flags = targetMethod.GetPInvokeMethodMetadata().Flags; - - ParameterMetadata[] parameterMetadataArray = targetMethod.GetParameterMetadata(); - Marshaller[] marshallers = new Marshaller[methodSig.Length + 1]; - ParameterMetadata parameterMetadata; - - for (int i = 0, parameterIndex = 0; i < marshallers.Length; i++) - { - Debug.Assert(parameterIndex == parameterMetadataArray.Length || i <= parameterMetadataArray[parameterIndex].Index); - if (parameterIndex == parameterMetadataArray.Length || i < parameterMetadataArray[parameterIndex].Index) - { - // if we don't have metadata for the parameter, create a dummy one - parameterMetadata = new ParameterMetadata(i, ParameterMetadataAttributes.None, null); - } - else - { - Debug.Assert(i == parameterMetadataArray[parameterIndex].Index); - parameterMetadata = parameterMetadataArray[parameterIndex++]; - } - - TypeDesc parameterType = (i == 0) ? methodSig.ReturnType : methodSig[i - 1]; //first item is the return type - marshallers[i] = CreateMarshaller(parameterType, - MarshallerType.Argument, - parameterMetadata.MarshalAsDescriptor, - direction, - marshallers, - parameterMetadata.Index, - flags, - parameterMetadata.In, - parameterMetadata.Out, - parameterMetadata.Return); - } - - return marshallers; - } - #endregion - - - #region Marshalling Requirement Checking - private static bool IsMarshallingRequired(MarshallerKind kind) - { - switch (kind) - { - case MarshallerKind.Enum: - case MarshallerKind.BlittableValue: - case MarshallerKind.BlittableStruct: - case MarshallerKind.UnicodeChar: - case MarshallerKind.VoidReturn: - return false; - } - return true; - } - - private bool IsMarshallingRequired() - { - return Out || IsMarshallingRequired(MarshallerKind); - } - - public static bool IsMarshallingRequired(MethodDesc targetMethod) - { - Debug.Assert(targetMethod.IsPInvoke); - - PInvokeFlags flags = targetMethod.GetPInvokeMethodMetadata().Flags; - - if (flags.SetLastError) - return true; - - if (!flags.PreserveSig) - return true; - - var marshallers = GetMarshallersForMethod(targetMethod); - for (int i = 0; i < marshallers.Length; i++) - { - if (marshallers[i].IsMarshallingRequired()) - return true; - } - - return false; - } - - public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMetadata[] paramMetadata) - { - for (int i = 0, paramIndex = 0; i < methodSig.Length + 1; i++) - { - ParameterMetadata parameterMetadata = (paramIndex == paramMetadata.Length || i < paramMetadata[paramIndex].Index) ? - new ParameterMetadata(i, ParameterMetadataAttributes.None, null) : - paramMetadata[paramIndex++]; - - TypeDesc parameterType = (i == 0) ? methodSig.ReturnType : methodSig[i - 1]; //first item is the return type - - MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind( - parameterType, - parameterMetadata.MarshalAsDescriptor, - parameterMetadata.Return, - isAnsi: true, - MarshallerType.Argument, - out MarshallerKind elementMarshallerKind); - - if (IsMarshallingRequired(marshallerKind)) - return true; - } - - return false; - } - #endregion - - public virtual void EmitMarshallingIL(PInvokeILCodeStreams pInvokeILCodeStreams) - { - _ilCodeStreams = pInvokeILCodeStreams; - - switch (MarshallerType) - { - case MarshallerType.Argument: EmitArgumentMarshallingIL(); return; - case MarshallerType.Element: EmitElementMarshallingIL(); return; - case MarshallerType.Field: EmitFieldMarshallingIL(); return; - } - } - - private void EmitArgumentMarshallingIL() - { - switch (MarshalDirection) - { - case MarshalDirection.Forward: EmitForwardArgumentMarshallingIL(); return; - case MarshalDirection.Reverse: EmitReverseArgumentMarshallingIL(); return; - } - } - - private void EmitElementMarshallingIL() - { - switch (MarshalDirection) - { - case MarshalDirection.Forward: EmitForwardElementMarshallingIL(); return; - case MarshalDirection.Reverse: EmitReverseElementMarshallingIL(); return; - } - } - - private void EmitFieldMarshallingIL() - { - switch (MarshalDirection) - { - case MarshalDirection.Forward: EmitForwardFieldMarshallingIL(); return; - case MarshalDirection.Reverse: EmitReverseFieldMarshallingIL(); return; - } - } - - protected virtual void EmitForwardArgumentMarshallingIL() - { - if (Return) - { - EmitMarshalReturnValueManagedToNative(); - } - else - { - EmitMarshalArgumentManagedToNative(); - } - } - - protected virtual void EmitReverseArgumentMarshallingIL() - { - if (Return) - { - EmitMarshalReturnValueNativeToManaged(); - } - else - { - EmitMarshalArgumentNativeToManaged(); - } - } - - protected virtual void EmitForwardElementMarshallingIL() - { - if (In) - EmitMarshalElementManagedToNative(); - else - EmitMarshalElementNativeToManaged(); - } - - protected virtual void EmitReverseElementMarshallingIL() - { - if (In) - EmitMarshalElementNativeToManaged(); - else - EmitMarshalElementManagedToNative(); - } - - protected virtual void EmitForwardFieldMarshallingIL() - { - if (In) - EmitMarshalFieldManagedToNative(); - else - EmitMarshalFieldNativeToManaged(); - } - - protected virtual void EmitReverseFieldMarshallingIL() - { - if (In) - EmitMarshalFieldNativeToManaged(); - else - EmitMarshalFieldManagedToNative(); - } - - - protected virtual void EmitMarshalReturnValueManagedToNative() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - SetupArgumentsForReturnValueMarshalling(); - - StoreNativeValue(_ilCodeStreams.ReturnValueMarshallingCodeStream); - - AllocAndTransformNativeToManaged(_ilCodeStreams.ReturnValueMarshallingCodeStream); - } - - public virtual void LoadReturnValue(ILCodeStream codeStream) - { - Debug.Assert(Return); - - switch (MarshalDirection) - { - case MarshalDirection.Forward: LoadManagedValue(codeStream); return; - case MarshalDirection.Reverse: LoadNativeValue(codeStream); return; - } - } - - protected virtual void SetupArguments() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - if (MarshalDirection == MarshalDirection.Forward) - { - // Due to StInd order (address, value), we can't do the following: - // LoadValue - // StoreManagedValue (LdArg + StInd) - // The way to work around this is to put it in a local - if (IsManagedByRef) - _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, false); - else - _managedHome = new Home(Index - 1, ManagedType, false); - _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); - } - else - { - _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); - if (IsNativeByRef) - _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); - else - _nativeHome = new Home(Index - 1, NativeType, isByRef: false); - } - } - - protected virtual void SetupArgumentsForElementMarshalling() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); - _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); - } - - protected virtual void SetupArgumentsForFieldMarshalling() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - // - // these are temporary locals for propagating value - // - _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); - _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); - } - - protected virtual void SetupArgumentsForReturnValueMarshalling() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); - _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); - } - - protected void LoadManagedValue(ILCodeStream stream) - { - _managedHome.LoadValue(stream); - } - - protected void LoadManagedAddr(ILCodeStream stream) - { - _managedHome.LoadAddr(stream); - } - - /// - /// Loads the argument to be passed to managed functions - /// In by-ref scenarios (ref T), it is &T - /// - protected void LoadManagedArg(ILCodeStream stream) - { - if (IsManagedByRef) - _managedHome.LoadAddr(stream); - else - _managedHome.LoadValue(stream); - } - - protected void StoreManagedValue(ILCodeStream stream) - { - _managedHome.StoreValue(stream); - } - - protected void LoadNativeValue(ILCodeStream stream) - { - _nativeHome.LoadValue(stream); - } - - /// - /// Loads the argument to be passed to native functions - /// In by-ref scenarios (ref T), it is T* - /// - protected void LoadNativeArg(ILCodeStream stream) - { - if (IsNativeByRef) - _nativeHome.LoadAddr(stream); - else - _nativeHome.LoadValue(stream); - } - - protected void LoadNativeAddr(ILCodeStream stream) - { - _nativeHome.LoadAddr(stream); - } - - protected void StoreNativeValue(ILCodeStream stream) - { - _nativeHome.StoreValue(stream); - } - - - /// - /// Propagate by-ref arg to corresponding local - /// We can't load value + ldarg + ldind in the expected order, so - /// we had to use a non-by-ref local and manually propagate the value - /// - protected void PropagateFromByRefArg(ILCodeStream stream, Home home) - { - stream.EmitLdArg(Index - 1); - stream.EmitLdInd(ManagedType); - home.StoreValue(stream); - } - - /// - /// Propagate local to corresponding by-ref arg - /// We can't load value + ldarg + ldind in the expected order, so - /// we had to use a non-by-ref local and manually propagate the value - /// - protected void PropagateToByRefArg(ILCodeStream stream, Home home) - { - stream.EmitLdArg(Index - 1); - home.LoadValue(stream); - stream.EmitStInd(ManagedType); - } - - protected virtual void EmitMarshalArgumentManagedToNative() - { - SetupArguments(); - - if (IsManagedByRef && In) - { - // Propagate byref arg to local - PropagateFromByRefArg(_ilCodeStreams.MarshallingCodeStream, _managedHome); - } - - // - // marshal - // - if (IsManagedByRef && !In) - { - ReInitNativeTransform(_ilCodeStreams.MarshallingCodeStream); - } - else - { - AllocAndTransformManagedToNative(_ilCodeStreams.MarshallingCodeStream); - } - - LoadNativeArg(_ilCodeStreams.CallsiteSetupCodeStream); - - // - // unmarshal - // - if (Out) - { - if (In) - { - ClearManagedTransform(_ilCodeStreams.UnmarshallingCodestream); - } - - if (IsManagedByRef && !In) - { - AllocNativeToManaged(_ilCodeStreams.UnmarshallingCodestream); - } - - TransformNativeToManaged(_ilCodeStreams.UnmarshallingCodestream); - - if (IsManagedByRef) - { - // Propagate back to byref arguments - PropagateToByRefArg(_ilCodeStreams.UnmarshallingCodestream, _managedHome); - } - } - - EmitCleanupManaged(_ilCodeStreams.CleanupCodeStream); - } - - /// - /// Reads managed parameter from _vManaged and writes the marshalled parameter in _vNative - /// - protected virtual void AllocAndTransformManagedToNative(ILCodeStream codeStream) - { - AllocManagedToNative(codeStream); - if (In) - { - TransformManagedToNative(codeStream); - } - } - - protected virtual void AllocAndTransformNativeToManaged(ILCodeStream codeStream) - { - AllocNativeToManaged(codeStream); - TransformNativeToManaged(codeStream); - } - - protected virtual void AllocManagedToNative(ILCodeStream codeStream) - { - } - protected virtual void TransformManagedToNative(ILCodeStream codeStream) - { - LoadManagedValue(codeStream); - StoreNativeValue(codeStream); - } - - protected virtual void ClearManagedTransform(ILCodeStream codeStream) - { - } - protected virtual void AllocNativeToManaged(ILCodeStream codeStream) - { - } - - protected virtual void TransformNativeToManaged(ILCodeStream codeStream) - { - LoadNativeValue(codeStream); - StoreManagedValue(codeStream); - } - - protected virtual void EmitCleanupManaged(ILCodeStream codeStream) - { - } - - protected virtual void EmitMarshalReturnValueNativeToManaged() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - SetupArgumentsForReturnValueMarshalling(); - - StoreManagedValue(_ilCodeStreams.ReturnValueMarshallingCodeStream); - - AllocAndTransformManagedToNative(_ilCodeStreams.ReturnValueMarshallingCodeStream); - } - - protected virtual void EmitMarshalArgumentNativeToManaged() - { - SetupArguments(); - - if (IsNativeByRef && In) - { - // Propagate byref arg to local - PropagateFromByRefArg(_ilCodeStreams.MarshallingCodeStream, _nativeHome); - } - - if (IsNativeByRef && !In) - { - ReInitManagedTransform(_ilCodeStreams.MarshallingCodeStream); - } - else - { - AllocAndTransformNativeToManaged(_ilCodeStreams.MarshallingCodeStream); - } - - LoadManagedArg(_ilCodeStreams.CallsiteSetupCodeStream); - - if (Out) - { - if (IsNativeByRef) - { - AllocManagedToNative(_ilCodeStreams.UnmarshallingCodestream); - } - - TransformManagedToNative(_ilCodeStreams.UnmarshallingCodestream); - - if (IsNativeByRef) - { - // Propagate back to byref arguments - PropagateToByRefArg(_ilCodeStreams.UnmarshallingCodestream, _nativeHome); - } - } - } - - protected virtual void EmitMarshalElementManagedToNative() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream codeStream = _ilCodeStreams.MarshallingCodeStream; - Debug.Assert(codeStream != null); - - SetupArgumentsForElementMarshalling(); - - StoreManagedValue(codeStream); - - // marshal - AllocAndTransformManagedToNative(codeStream); - - LoadNativeValue(codeStream); - } - - protected virtual void EmitMarshalElementNativeToManaged() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream codeStream = _ilCodeStreams.MarshallingCodeStream; - Debug.Assert(codeStream != null); - - SetupArgumentsForElementMarshalling(); - - StoreNativeValue(codeStream); - - // unmarshal - AllocAndTransformNativeToManaged(codeStream); - LoadManagedValue(codeStream); - } - - protected virtual void EmitMarshalFieldManagedToNative() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; - - SetupArgumentsForFieldMarshalling(); - // - // For field marshalling we expect the value of the field is already loaded - // in the stack. - // - StoreManagedValue(marshallingCodeStream); - - // marshal - AllocAndTransformManagedToNative(marshallingCodeStream); - - LoadNativeValue(marshallingCodeStream); - } - - protected virtual void EmitMarshalFieldNativeToManaged() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream codeStream = _ilCodeStreams.MarshallingCodeStream; - - SetupArgumentsForFieldMarshalling(); - - StoreNativeValue(codeStream); - - // unmarshal - AllocAndTransformNativeToManaged(codeStream); - LoadManagedValue(codeStream); - } - - protected virtual void ReInitManagedTransform(ILCodeStream codeStream) - { - } - - protected virtual void ReInitNativeTransform(ILCodeStream codeStream) - { - } - - internal virtual void EmitElementCleanup(ILCodeStream codestream, ILEmitter emitter) - { - } - } - - class NotSupportedMarshaller : Marshaller - { - public override void EmitMarshallingIL(PInvokeILCodeStreams pInvokeILCodeStreams) - { - throw new NotSupportedException(); - } - } - - class VoidReturnMarshaller : Marshaller - { - protected override void EmitMarshalReturnValueManagedToNative() - { - } - protected override void EmitMarshalReturnValueNativeToManaged() - { - } - public override void LoadReturnValue(ILCodeStream codeStream) - { - Debug.Assert(Return); - } - } - - class BlittableValueMarshaller : Marshaller - { - protected override void EmitMarshalArgumentManagedToNative() - { - if (IsNativeByRef && MarshalDirection == MarshalDirection.Forward) - { - ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; - ILEmitter emitter = _ilCodeStreams.Emitter; - ILLocalVariable native = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); - - ILLocalVariable vPinnedByRef = emitter.NewLocal(ManagedParameterType, true); - marshallingCodeStream.EmitLdArg(Index - 1); - marshallingCodeStream.EmitStLoc(vPinnedByRef); - marshallingCodeStream.EmitLdLoc(vPinnedByRef); - marshallingCodeStream.Emit(ILOpcode.conv_i); - marshallingCodeStream.EmitStLoc(native); - _ilCodeStreams.CallsiteSetupCodeStream.EmitLdLoc(native); - } - else - { - _ilCodeStreams.CallsiteSetupCodeStream.EmitLdArg(Index - 1); - } - } - - protected override void EmitMarshalArgumentNativeToManaged() - { - if (Out) - { - base.EmitMarshalArgumentNativeToManaged(); - } - else - { - _ilCodeStreams.CallsiteSetupCodeStream.EmitLdArg(Index - 1); - } - } - } - - class BlittableStructPtrMarshaller : Marshaller - { - protected override void TransformManagedToNative(ILCodeStream codeStream) - { - if (Out) - { - // TODO: https://github.com/dotnet/corert/issues/4466 - throw new NotSupportedException("Marshalling an LPStruct argument not yet implemented"); - } - else - { - LoadManagedAddr(codeStream); - StoreNativeValue(codeStream); - } - } - - protected override void TransformNativeToManaged(ILCodeStream codeStream) - { - // TODO: https://github.com/dotnet/corert/issues/4466 - throw new NotSupportedException("Marshalling an LPStruct argument not yet implemented"); - } - } - - class ArrayMarshaller : Marshaller - { - private Marshaller _elementMarshaller; - - protected TypeDesc ManagedElementType - { - get - { - Debug.Assert(ManagedType is ArrayType); - var arrayType = (ArrayType)ManagedType; - return arrayType.ElementType; - } - } - - protected TypeDesc NativeElementType - { - get - { - Debug.Assert(NativeType is PointerType); - return ((PointerType)NativeType).ParameterType; - } - } - - protected Marshaller GetElementMarshaller(MarshalDirection direction) - { - if (_elementMarshaller == null) - { - _elementMarshaller = CreateMarshaller(ElementMarshallerKind); - _elementMarshaller.MarshallerKind = ElementMarshallerKind; - _elementMarshaller.MarshallerType = MarshallerType.Element; -#if !READYTORUN - _elementMarshaller.InteropStateManager = InteropStateManager; -#endif - _elementMarshaller.Return = Return; - _elementMarshaller.Context = Context; - _elementMarshaller.ManagedType = ManagedElementType; - _elementMarshaller.MarshalAsDescriptor = MarshalAsDescriptor; - _elementMarshaller.PInvokeFlags = PInvokeFlags; - } - _elementMarshaller.In = (direction == MarshalDirection); - _elementMarshaller.Out = !In; - _elementMarshaller.MarshalDirection = MarshalDirection; - - return _elementMarshaller; - } - - protected virtual void EmitElementCount(ILCodeStream codeStream, MarshalDirection direction) - { - if (direction == MarshalDirection.Forward) - { - // In forward direction we skip whatever is passed through SizeParamIndex, because the - // size of the managed array is already known - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.ldlen); - codeStream.Emit(ILOpcode.conv_i4); - - } - else if (MarshalDirection == MarshalDirection.Forward - && MarshallerType == MarshallerType.Argument - && !Return - && !IsManagedByRef) - { - EmitElementCount(codeStream, MarshalDirection.Forward); - } - else - { - - uint? sizeParamIndex = MarshalAsDescriptor != null ? MarshalAsDescriptor.SizeParamIndex : null; - uint? sizeConst = MarshalAsDescriptor != null ? MarshalAsDescriptor.SizeConst : null; - - if (sizeConst.HasValue) - { - codeStream.EmitLdc((int)sizeConst.Value); - } - - if (sizeParamIndex.HasValue) - { - uint index = sizeParamIndex.Value; - - if (index < 0 || index >= Marshallers.Length - 1) - { - throw new InvalidProgramException("Invalid SizeParamIndex, must be between 0 and parameter count"); - } - - //zero-th index is for return type - index++; - var indexType = Marshallers[index].ManagedType; - switch (indexType.Category) - { - case TypeFlags.Byte: - case TypeFlags.SByte: - case TypeFlags.Int16: - case TypeFlags.UInt16: - case TypeFlags.Int32: - case TypeFlags.UInt32: - case TypeFlags.Int64: - case TypeFlags.UInt64: - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - break; - default: - throw new InvalidProgramException("Invalid SizeParamIndex, parameter must be of type int/uint"); - } - - // @TODO - We can use LoadManagedValue, but that requires byref arg propagation happen in a special setup stream - // otherwise there is an ordering issue - codeStream.EmitLdArg(Marshallers[index].Index - 1); - if (Marshallers[index].IsManagedByRef) - codeStream.EmitLdInd(indexType); - - if (sizeConst.HasValue) - codeStream.Emit(ILOpcode.add); - } - - if (!sizeConst.HasValue && !sizeParamIndex.HasValue) - { - // if neither sizeConst or sizeParamIndex are specified, default to 1 - codeStream.EmitLdc(1); - } - } - } - - protected override void AllocManagedToNative(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeLabel lNullArray = emitter.NewCodeLabel(); - - codeStream.EmitLdc(0); - codeStream.Emit(ILOpcode.conv_u); - StoreNativeValue(codeStream); - - // Check for null array - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNullArray); - - // allocate memory - // nativeParameter = (byte**)CoTaskMemAllocAndZeroMemory((IntPtr)(checked(managedParameter.Length * sizeof(byte*)))); - - // loads the number of elements - EmitElementCount(codeStream, MarshalDirection.Forward); - - TypeDesc nativeElementType = NativeElementType; - codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); - - codeStream.Emit(ILOpcode.mul_ovf); - - codeStream.Emit(ILOpcode.call, emitter.NewToken( - InteropTypes.GetMarshal(Context).GetKnownMethod("AllocCoTaskMem", null))); - StoreNativeValue(codeStream); - - codeStream.EmitLabel(lNullArray); - } - - protected override void TransformManagedToNative(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - var elementType = ManagedElementType; - - var lRangeCheck = emitter.NewCodeLabel(); - var lLoopHeader = emitter.NewCodeLabel(); - var lNullArray = emitter.NewCodeLabel(); - - var vNativeTemp = emitter.NewLocal(NativeType); - var vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); - var vSizeOf = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); - var vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); - - // Check for null array - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNullArray); - - // loads the number of elements - EmitElementCount(codeStream, MarshalDirection.Forward); - codeStream.EmitStLoc(vLength); - - TypeDesc nativeElementType = NativeElementType; - codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); - - codeStream.EmitStLoc(vSizeOf); - - LoadNativeValue(codeStream); - codeStream.EmitStLoc(vNativeTemp); - - codeStream.EmitLdc(0); - codeStream.EmitStLoc(vIndex); - codeStream.Emit(ILOpcode.br, lRangeCheck); - - codeStream.EmitLabel(lLoopHeader); - codeStream.EmitLdLoc(vNativeTemp); - - LoadManagedValue(codeStream); - codeStream.EmitLdLoc(vIndex); - codeStream.EmitLdElem(elementType); - // generate marshalling IL for the element - GetElementMarshaller(MarshalDirection.Forward) - .EmitMarshallingIL(new PInvokeILCodeStreams(_ilCodeStreams.Emitter, codeStream)); - - codeStream.EmitStInd(nativeElementType); - codeStream.EmitLdLoc(vIndex); - codeStream.EmitLdc(1); - codeStream.Emit(ILOpcode.add); - codeStream.EmitStLoc(vIndex); - codeStream.EmitLdLoc(vNativeTemp); - codeStream.EmitLdLoc(vSizeOf); - codeStream.Emit(ILOpcode.add); - codeStream.EmitStLoc(vNativeTemp); - - codeStream.EmitLabel(lRangeCheck); - - codeStream.EmitLdLoc(vIndex); - codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.blt, lLoopHeader); - codeStream.EmitLabel(lNullArray); - } - - protected override void TransformNativeToManaged(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - var elementType = ManagedElementType; - var nativeElementType = NativeElementType; - - ILLocalVariable vSizeOf = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); - ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); - - ILCodeLabel lRangeCheck = emitter.NewCodeLabel(); - ILCodeLabel lLoopHeader = emitter.NewCodeLabel(); - var lNullArray = emitter.NewCodeLabel(); - - // Check for null array - if (!IsManagedByRef) - { - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNullArray); - } - - EmitElementCount(codeStream, MarshalDirection.Reverse); - - codeStream.EmitStLoc(vLength); - - if (IsManagedByRef) - { - codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.newarr, emitter.NewToken(ManagedElementType)); - StoreManagedValue(codeStream); - } - - codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); - - codeStream.EmitStLoc(vSizeOf); - - var vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); - ILLocalVariable vNativeTemp = emitter.NewLocal(NativeType); - - LoadNativeValue(codeStream); - codeStream.EmitStLoc(vNativeTemp); - codeStream.EmitLdc(0); - codeStream.EmitStLoc(vIndex); - codeStream.Emit(ILOpcode.br, lRangeCheck); - - - codeStream.EmitLabel(lLoopHeader); - - LoadManagedValue(codeStream); - - codeStream.EmitLdLoc(vIndex); - codeStream.EmitLdLoc(vNativeTemp); - - codeStream.EmitLdInd(nativeElementType); - - // generate marshalling IL for the element - GetElementMarshaller(MarshalDirection.Reverse) - .EmitMarshallingIL(new PInvokeILCodeStreams(_ilCodeStreams.Emitter, codeStream)); - - codeStream.EmitStElem(elementType); - - codeStream.EmitLdLoc(vIndex); - codeStream.EmitLdc(1); - codeStream.Emit(ILOpcode.add); - codeStream.EmitStLoc(vIndex); - codeStream.EmitLdLoc(vNativeTemp); - codeStream.EmitLdLoc(vSizeOf); - codeStream.Emit(ILOpcode.add); - codeStream.EmitStLoc(vNativeTemp); - - - codeStream.EmitLabel(lRangeCheck); - codeStream.EmitLdLoc(vIndex); - codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.blt, lLoopHeader); - codeStream.EmitLabel(lNullArray); - } - - protected override void AllocNativeToManaged(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - var elementType = ManagedElementType; - EmitElementCount(codeStream, MarshalDirection.Reverse); - codeStream.Emit(ILOpcode.newarr, emitter.NewToken(elementType)); - StoreManagedValue(codeStream); - } - - protected override void EmitCleanupManaged(ILCodeStream codeStream) - { - Marshaller elementMarshaller = GetElementMarshaller(MarshalDirection.Forward); - ILEmitter emitter = _ilCodeStreams.Emitter; - - var lNullArray = emitter.NewCodeLabel(); - - // Check for null array - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNullArray); - - // generate cleanup code only if it is necessary - if (elementMarshaller.CleanupRequired) - { - // - // for (index=0; index< array.length; index++) - // Cleanup(array[i]); - // - var vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); - ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); - - ILCodeLabel lRangeCheck = emitter.NewCodeLabel(); - ILCodeLabel lLoopHeader = emitter.NewCodeLabel(); - ILLocalVariable vSizeOf = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); - - var nativeElementType = NativeElementType; - // calculate sizeof(array[i]) - codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); - - codeStream.EmitStLoc(vSizeOf); - - - // calculate array.length - EmitElementCount(codeStream, MarshalDirection.Forward); - codeStream.EmitStLoc(vLength); - - // load native value - ILLocalVariable vNativeTemp = emitter.NewLocal(NativeType); - LoadNativeValue(codeStream); - codeStream.EmitStLoc(vNativeTemp); - - // index = 0 - codeStream.EmitLdc(0); - codeStream.EmitStLoc(vIndex); - codeStream.Emit(ILOpcode.br, lRangeCheck); - - codeStream.EmitLabel(lLoopHeader); - codeStream.EmitLdLoc(vNativeTemp); - codeStream.EmitLdInd(nativeElementType); - // generate cleanup code for this element - elementMarshaller.EmitElementCleanup(codeStream, emitter); - - codeStream.EmitLdLoc(vIndex); - codeStream.EmitLdc(1); - codeStream.Emit(ILOpcode.add); - codeStream.EmitStLoc(vIndex); - codeStream.EmitLdLoc(vNativeTemp); - codeStream.EmitLdLoc(vSizeOf); - codeStream.Emit(ILOpcode.add); - codeStream.EmitStLoc(vNativeTemp); - - codeStream.EmitLabel(lRangeCheck); - - codeStream.EmitLdLoc(vIndex); - codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.blt, lLoopHeader); - } - - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(InteropTypes.GetMarshal(Context).GetKnownMethod("FreeCoTaskMem", null))); - codeStream.EmitLabel(lNullArray); - } - } - - class BlittableArrayMarshaller : ArrayMarshaller - { - protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeLabel lNullArray = emitter.NewCodeLabel(); - - MethodDesc getRawSzArrayDataMethod = InteropTypes.GetRuntimeHelpers(Context).GetKnownMethod("GetRawSzArrayData", null); - - // Check for null array - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNullArray); - - if (IsManagedByRef) - { - base.AllocManagedToNative(codeStream); - - LoadNativeValue(codeStream); - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(getRawSzArrayDataMethod)); - EmitElementCount(codeStream, MarshalDirection.Forward); - codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(ManagedElementType)); - codeStream.Emit(ILOpcode.mul_ovf); - codeStream.Emit(ILOpcode.cpblk); - - codeStream.EmitLabel(lNullArray); - } - else - { - ILLocalVariable vPinnedFirstElement = emitter.NewLocal(ManagedElementType.MakeByRefType(), true); - - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.ldlen); - codeStream.Emit(ILOpcode.conv_i4); - codeStream.Emit(ILOpcode.brfalse, lNullArray); - - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(getRawSzArrayDataMethod)); - codeStream.EmitStLoc(vPinnedFirstElement); - - // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit. - codeStream.EmitLabel(lNullArray); - codeStream.EmitLdLoc(vPinnedFirstElement); - codeStream.Emit(ILOpcode.conv_i); - StoreNativeValue(codeStream); - } - } - - protected override void ReInitNativeTransform(ILCodeStream codeStream) - { - codeStream.EmitLdc(0); - codeStream.Emit(ILOpcode.conv_u); - StoreNativeValue(codeStream); - } - - protected override void TransformNativeToManaged(ILCodeStream codeStream) - { - if (IsManagedByRef || (MarshalDirection == MarshalDirection.Reverse && MarshallerType == MarshallerType.Argument)) - base.TransformNativeToManaged(codeStream); - } - - protected override void EmitCleanupManaged(ILCodeStream codeStream) - { - if (IsManagedByRef) - base.EmitCleanupManaged(codeStream); - } - } - - class BooleanMarshaller : Marshaller - { - protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) - { - LoadManagedValue(codeStream); - codeStream.EmitLdc(0); - codeStream.Emit(ILOpcode.ceq); - codeStream.EmitLdc(0); - codeStream.Emit(ILOpcode.ceq); - StoreNativeValue(codeStream); - } - - protected override void AllocAndTransformNativeToManaged(ILCodeStream codeStream) - { - LoadNativeValue(codeStream); - codeStream.EmitLdc(0); - codeStream.Emit(ILOpcode.ceq); - codeStream.EmitLdc(0); - codeStream.Emit(ILOpcode.ceq); - StoreManagedValue(codeStream); - } - } - - class UnicodeStringMarshaller : Marshaller - { - private bool ShouldBePinned - { - get - { - return MarshalDirection == MarshalDirection.Forward - && MarshallerType != MarshallerType.Field - && !IsManagedByRef - && In - && !Out; - } - } - - internal override bool CleanupRequired - { - get - { - return !ShouldBePinned; //cleanup is only required when it is not pinned - } - } - - internal override void EmitElementCleanup(ILCodeStream codeStream, ILEmitter emitter) - { - codeStream.Emit(ILOpcode.call, emitter.NewToken( - Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); - } - - protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - if (ShouldBePinned) - { - // - // Pin the string and push a pointer to the first character on the stack. - // - TypeDesc stringType = Context.GetWellKnownType(WellKnownType.String); - - ILLocalVariable vPinnedString = emitter.NewLocal(stringType, true); - ILCodeLabel lNullString = emitter.NewCodeLabel(); - - LoadManagedValue(codeStream); - codeStream.EmitStLoc(vPinnedString); - codeStream.EmitLdLoc(vPinnedString); - - codeStream.Emit(ILOpcode.conv_i); - codeStream.Emit(ILOpcode.dup); - - // Marshalling a null string? - codeStream.Emit(ILOpcode.brfalse, lNullString); - - codeStream.Emit(ILOpcode.call, emitter.NewToken( - Context.SystemModule. - GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers"). - GetKnownMethod("get_OffsetToStringData", null))); - - codeStream.Emit(ILOpcode.add); - - codeStream.EmitLabel(lNullString); - StoreNativeValue(codeStream); - } - else - { - var helper = Context.GetHelperEntryPoint("InteropHelpers", "StringToUnicodeBuffer"); - LoadManagedValue(codeStream); - - codeStream.Emit(ILOpcode.call, emitter.NewToken(helper)); - - StoreNativeValue(codeStream); - } - } - - protected override void TransformNativeToManaged(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - var charPtrConstructor = Context.GetWellKnownType(WellKnownType.String).GetMethod(".ctor", - new MethodSignature( - MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.Void), - new TypeDesc[] { - Context.GetWellKnownType(WellKnownType.Char).MakePointerType() } - )); - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.newobj, emitter.NewToken(charPtrConstructor)); - StoreManagedValue(codeStream); - } - - protected override void EmitCleanupManaged(ILCodeStream codeStream) - { - if (CleanupRequired) - { - var emitter = _ilCodeStreams.Emitter; - var lNullCheck = emitter.NewCodeLabel(); - - // Check for null array - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNullCheck); - - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken( - InteropTypes.GetMarshal(Context).GetKnownMethod("FreeCoTaskMem", null))); - - codeStream.EmitLabel(lNullCheck); - } - } - } - - class AnsiStringMarshaller : Marshaller - { - internal override bool CleanupRequired - { - get - { - return true; - } - } - - internal override void EmitElementCleanup(ILCodeStream codeStream, ILEmitter emitter) - { - codeStream.Emit(ILOpcode.call, emitter.NewToken( - Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); - } - - protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - // - // ANSI marshalling. Allocate a byte array, copy characters - // - -#if READYTORUN - var stringToAnsi = - Context.SystemModule.GetKnownType("System.StubHelpers", "AnsiBSTRMarshaler") - .GetKnownMethod("ConvertToNative", null); - int flags = (PInvokeFlags.BestFitMapping ? 0x1 : 0) - | (PInvokeFlags.ThrowOnUnmappableChar ? 0x100 : 0); - codeStream.EmitLdc(flags); - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi)); -#else - LoadManagedValue(codeStream); - var stringToAnsi = Context.GetHelperEntryPoint("InteropHelpers", "StringToAnsiString"); - - codeStream.Emit(PInvokeFlags.BestFitMapping ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0); - codeStream.Emit(PInvokeFlags.ThrowOnUnmappableChar ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0); - - codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi)); -#endif - - StoreNativeValue(codeStream); - } - - protected override void TransformNativeToManaged(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - -#if READYTORUN - var ansiToString = - Context.SystemModule.GetKnownType("System.StubHelpers", "AnsiBSTRMarshaler") - .GetKnownMethod("ConvertToManaged", null); -#else - var ansiToString = Context.GetHelperEntryPoint("InteropHelpers", "AnsiStringToString"); -#endif - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(ansiToString)); - StoreManagedValue(codeStream); - } - - protected override void EmitCleanupManaged(ILCodeStream codeStream) - { - var emitter = _ilCodeStreams.Emitter; -#if READYTORUN - MethodDesc clearNative = - Context.SystemModule.GetKnownType("System.StubHelpers", "AnsiBSTRMarshaler") - .GetKnownMethod("ClearNative", null); - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(clearNative)); -#else - var lNullCheck = emitter.NewCodeLabel(); - - // Check for null array - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNullCheck); - - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken( - Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); - - codeStream.EmitLabel(lNullCheck); -#endif - } - } - - class UTF8StringMarshaller : Marshaller - { - internal override bool CleanupRequired - { - get - { - return true; - } - } - - internal override void EmitElementCleanup(ILCodeStream codeStream, ILEmitter emitter) - { - codeStream.Emit(ILOpcode.call, emitter.NewToken( - Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); - } - - protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - - // - // UTF8 marshalling. Allocate a byte array, copy characters - // - var stringToAnsi = Context.GetHelperEntryPoint("InteropHelpers", "StringToUTF8String"); - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi)); - StoreNativeValue(codeStream); - } - - protected override void TransformNativeToManaged(ILCodeStream codeStream) - { - ILEmitter emitter = _ilCodeStreams.Emitter; - var ansiToString = Context.GetHelperEntryPoint("InteropHelpers", "UTF8StringToString"); - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(ansiToString)); - StoreManagedValue(codeStream); - } - - protected override void EmitCleanupManaged(ILCodeStream codeStream) - { - var emitter = _ilCodeStreams.Emitter; - var lNullCheck = emitter.NewCodeLabel(); - - // Check for null array - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNullCheck); - - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken( - Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); - - codeStream.EmitLabel(lNullCheck); - } - } - - class SafeHandleMarshaller : Marshaller - { - private void AllocSafeHandle(ILCodeStream codeStream) - { - var ctor = ManagedType.GetParameterlessConstructor(); - if (ctor == null || ((MetadataType)ManagedType).IsAbstract) - { -#if READYTORUN - // Let the runtime generate the proper MissingMemberException for this. - throw new NotSupportedException(); -#else - var emitter = _ilCodeStreams.Emitter; - - MethodSignature ctorSignature = new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), - new TypeDesc[] { - Context.GetWellKnownType(WellKnownType.String) - }); - MethodDesc exceptionCtor = InteropTypes.GetMissingMemberException(Context).GetKnownMethod(".ctor", ctorSignature); - - string name = ((MetadataType)ManagedType).Name; - codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(String.Format("'{0}' does not have a default constructor. Subclasses of SafeHandle must have a default constructor to support marshaling a Windows HANDLE into managed code.", name))); - codeStream.Emit(ILOpcode.newobj, emitter.NewToken(exceptionCtor)); - codeStream.Emit(ILOpcode.throw_); - - return; -#endif - } - - codeStream.Emit(ILOpcode.newobj, _ilCodeStreams.Emitter.NewToken(ctor)); - } - - protected override void EmitMarshalReturnValueManagedToNative() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; - ILCodeStream returnValueMarshallingCodeStream = _ilCodeStreams.ReturnValueMarshallingCodeStream; - - SetupArgumentsForReturnValueMarshalling(); - - AllocSafeHandle(marshallingCodeStream); - StoreManagedValue(marshallingCodeStream); - - StoreNativeValue(returnValueMarshallingCodeStream); - - LoadManagedValue(returnValueMarshallingCodeStream); - LoadNativeValue(returnValueMarshallingCodeStream); - returnValueMarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( - InteropTypes.GetSafeHandle(Context).GetKnownMethod("SetHandle", null))); - } - - protected override void EmitMarshalArgumentManagedToNative() - { - ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; - ILCodeStream callsiteCodeStream = _ilCodeStreams.CallsiteSetupCodeStream; - ILCodeStream unmarshallingCodeStream = _ilCodeStreams.UnmarshallingCodestream; - ILCodeStream cleanupCodeStream = _ilCodeStreams.CleanupCodeStream; - - SetupArguments(); - - if (IsManagedByRef && In) - { - PropagateFromByRefArg(marshallingCodeStream, _managedHome); - } - - var safeHandleType = InteropTypes.GetSafeHandle(Context); - - if (In) - { - if (IsManagedByRef) - PropagateFromByRefArg(marshallingCodeStream, _managedHome); - - var vAddRefed = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Boolean)); - LoadManagedValue(marshallingCodeStream); - marshallingCodeStream.EmitLdLoca(vAddRefed); - marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( - safeHandleType.GetKnownMethod("DangerousAddRef", - new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), - new TypeDesc[] { Context.GetWellKnownType(WellKnownType.Boolean).MakeByRefType() })))); - - LoadManagedValue(marshallingCodeStream); - marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( - safeHandleType.GetKnownMethod("DangerousGetHandle", - new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.IntPtr), TypeDesc.EmptyTypes)))); - StoreNativeValue(marshallingCodeStream); - - ILCodeLabel lNotAddrefed = emitter.NewCodeLabel(); - cleanupCodeStream.EmitLdLoc(vAddRefed); - cleanupCodeStream.Emit(ILOpcode.brfalse, lNotAddrefed); - LoadManagedValue(cleanupCodeStream); - cleanupCodeStream.Emit(ILOpcode.call, emitter.NewToken( - safeHandleType.GetKnownMethod("DangerousRelease", - new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), TypeDesc.EmptyTypes)))); - cleanupCodeStream.EmitLabel(lNotAddrefed); - } - - if (Out && IsManagedByRef) - { - // 1) If this is an output parameter we need to preallocate a SafeHandle to wrap the new native handle value. We - // must allocate this before the native call to avoid a failure point when we already have a native resource - // allocated. We must allocate a new SafeHandle even if we have one on input since both input and output native - // handles need to be tracked and released by a SafeHandle. - // 2) Initialize a local IntPtr that will be passed to the native call. - // 3) After the native call, the new handle value is written into the output SafeHandle and that SafeHandle - // is propagated back to the caller. - var vSafeHandle = emitter.NewLocal(ManagedType); - AllocSafeHandle(marshallingCodeStream); - marshallingCodeStream.EmitStLoc(vSafeHandle); - - var lSkipPropagation = emitter.NewCodeLabel(); - if (In) - { - // Propagate the value only if it has changed - ILLocalVariable vOriginalValue = emitter.NewLocal(NativeType); - LoadNativeValue(marshallingCodeStream); - marshallingCodeStream.EmitStLoc(vOriginalValue); - - cleanupCodeStream.EmitLdLoc(vOriginalValue); - LoadNativeValue(cleanupCodeStream); - cleanupCodeStream.Emit(ILOpcode.beq, lSkipPropagation); - } - - cleanupCodeStream.EmitLdLoc(vSafeHandle); - LoadNativeValue(cleanupCodeStream); - cleanupCodeStream.Emit(ILOpcode.call, emitter.NewToken( - safeHandleType.GetKnownMethod("SetHandle", - new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), - new TypeDesc[] { Context.GetWellKnownType(WellKnownType.IntPtr) })))); - - cleanupCodeStream.EmitLdArg(Index - 1); - cleanupCodeStream.EmitLdLoc(vSafeHandle); - cleanupCodeStream.EmitStInd(ManagedType); - - cleanupCodeStream.EmitLabel(lSkipPropagation); - } - - LoadNativeArg(callsiteCodeStream); - } - - protected override void EmitMarshalArgumentNativeToManaged() - { - throw new NotSupportedException(); - } - - protected override void EmitMarshalElementNativeToManaged() - { - throw new NotSupportedException(); - } - - protected override void EmitMarshalElementManagedToNative() - { - throw new NotSupportedException(); - } - - protected override void EmitMarshalFieldManagedToNative() - { - throw new NotSupportedException(); - } - - protected override void EmitMarshalFieldNativeToManaged() - { - throw new NotSupportedException(); - } - } - - class DelegateMarshaller : Marshaller - { - protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream) - { - LoadManagedValue(codeStream); - - codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken( - InteropTypes.GetMarshal(Context).GetKnownMethod("GetFunctionPointerForDelegate", - new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.IntPtr), - new TypeDesc[] { Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType } - )))); - - StoreNativeValue(codeStream); - } - - protected override void TransformNativeToManaged(ILCodeStream codeStream) - { - LoadNativeValue(codeStream); - - TypeDesc systemType = Context.SystemModule.GetKnownType("System", "Type"); - - codeStream.Emit(ILOpcode.ldtoken, _ilCodeStreams.Emitter.NewToken(ManagedType)); - codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(systemType.GetKnownMethod("GetTypeFromHandle", null))); - - codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken( - InteropTypes.GetMarshal(Context).GetKnownMethod("GetDelegateForFunctionPointer", - new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType, - new TypeDesc[] { Context.GetWellKnownType(WellKnownType.IntPtr), systemType } - )))); - - StoreManagedValue(codeStream); - } - - protected override void EmitCleanupManaged(ILCodeStream codeStream) - { - if (In - && MarshalDirection == MarshalDirection.Forward - && MarshallerType == MarshallerType.Argument) - { - LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(InteropTypes.GetGC(Context).GetKnownMethod("KeepAlive", null))); - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/InstantiatedType.Interop.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/InstantiatedType.Interop.cs deleted file mode 100644 index 4f9cbad960e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/InstantiatedType.Interop.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem -{ - public partial class InstantiatedType - { - public override PInvokeStringFormat PInvokeStringFormat - { - get - { - return _typeDef.PInvokeStringFormat; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/InteropTypes.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/InteropTypes.cs deleted file mode 100644 index 3e7d8156e3d..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/InteropTypes.cs +++ /dev/null @@ -1,152 +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 Internal.IL; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem.Interop -{ - public static class InteropTypes - { - public static MetadataType GetGC(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System", "GC"); - } - - public static MetadataType GetSafeHandle(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "SafeHandle"); - } - - public static MetadataType GetCriticalHandle(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "CriticalHandle"); - } - - public static MetadataType GetHandleRef(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "HandleRef"); - } - - public static MetadataType GetMissingMemberException(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System", "MissingMemberException"); - } - - public static MetadataType GetPInvokeMarshal(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "PInvokeMarshal"); - } - - public static MetadataType GetMarshal(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "Marshal"); - } - - public static MetadataType GetRuntimeHelpers(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers"); - } - - public static MetadataType GetStubHelpers(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System.StubHelpers", "StubHelpers"); - } - - public static MetadataType GetNativeFunctionPointerWrapper(TypeSystemContext context) - { - return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "NativeFunctionPointerWrapper"); - } - - public static bool IsSafeHandle(TypeSystemContext context, TypeDesc type) - { - return IsOrDerivesFromType(type, GetSafeHandle(context)); - } - - public static bool IsCriticalHandle(TypeSystemContext context, TypeDesc type) - { - return IsOrDerivesFromType(type, GetCriticalHandle(context)); - } - - private static bool IsCoreNamedType(TypeSystemContext context, TypeDesc type, string @namespace, string name) - { - return type is MetadataType mdType && - mdType.Name == name && - mdType.Namespace == @namespace && - mdType.Module == context.SystemModule; - } - - public static bool IsHandleRef(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System.Runtime.InteropServices", "HandleRef"); - } - - public static bool IsSystemDateTime(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System", "DateTime"); - } - - public static bool IsStringBuilder(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System.Text", "StringBuilder"); - } - - public static bool IsSystemDecimal(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System", "Decimal"); - } - - public static bool IsSystemGuid(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System", "Guid"); - } - - public static bool IsSystemArgIterator(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System", "ArgIterator"); - } - - public static bool IsSystemByReference(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System", "ByReference`1"); - } - - public static bool IsSystemNullable(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System", "Nullable`1"); - } - - public static bool IsSystemRuntimeIntrinsicsVector64T(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector64`1"); - } - - public static bool IsSystemRuntimeIntrinsicsVector128T(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector128`1"); - } - - public static bool IsSystemRuntimeIntrinsicsVector256T(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector256`1"); - } - - public static bool IsSystemNumericsVectorT(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System.Numerics", "Vector`1"); - } - - private static bool IsOrDerivesFromType(TypeDesc type, MetadataType targetType) - { - while (type != null) - { - if (type == targetType) - return true; - type = type.BaseType; - } - return false; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MarshalAsDescriptor.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MarshalAsDescriptor.cs deleted file mode 100644 index 2131581d4fe..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MarshalAsDescriptor.cs +++ /dev/null @@ -1,59 +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.Runtime.CompilerServices; -using System; - -namespace Internal.TypeSystem -{ - public enum NativeTypeKind : byte - { - Boolean = 0x2, - I1 = 0x3, - U1 = 0x4, - I2 = 0x5, - U2 = 0x6, - I4 = 0x7, - U4 = 0x8, - I8 = 0x9, - U8 = 0xa, - R4 = 0xb, - R8 = 0xc, - LPStr = 0x14, - LPWStr = 0x15, - LPTStr = 0x16, // Ptr to OS preferred (SBCS/Unicode) string - ByValTStr = 0x17, // OS preferred (SBCS/Unicode) inline string (only valid in structs) - Struct = 0x1b, - SafeArray = 0x1d, - ByValArray = 0x1e, - SysInt = 0x1f, - SysUInt = 0x20, - Int = 0x1f, - UInt = 0x20, - Func = 0x26, - AsAny = 0x28, - Array = 0x2a, - LPStruct = 0x2b, // This is not defined in Ecma-335(II.23.4) - CustomMarshaler = 0x2c, - LPUTF8Str = 0x30, - Default = 0x50, // This is the default value - Variant = 0x51, - } - - public class MarshalAsDescriptor - { - public NativeTypeKind Type { get; } - public NativeTypeKind ArraySubType { get; } - public uint? SizeParamIndex { get; } - public uint? SizeConst { get; } - - public MarshalAsDescriptor(NativeTypeKind type, NativeTypeKind arraySubType, uint? sizeParamIndex, uint? sizeConst) - { - Type = type; - ArraySubType = arraySubType; - SizeParamIndex = sizeParamIndex; - SizeConst = sizeConst; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MetadataType.Interop.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MetadataType.Interop.cs deleted file mode 100644 index 3f586dcb3f5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MetadataType.Interop.cs +++ /dev/null @@ -1,37 +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; - -namespace Internal.TypeSystem -{ - public enum PInvokeStringFormat - { - /// - /// LPTSTR is interpreted as ANSI in this class. - /// - AnsiClass = 0x00000000, - - /// - /// LPTSTR is interpreted as UNICODE. - /// - UnicodeClass = 0x00010000, - - /// - /// LPTSTR is interpreted automatically. - /// - AutoClass = 0x00020000, - } - - public partial class MetadataType - { - /// - /// Gets a value indicating how strings should be handled for native interop. - /// - public abstract PInvokeStringFormat PInvokeStringFormat - { - get; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MethodDelegator.Interop.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MethodDelegator.Interop.cs deleted file mode 100644 index 73c11109d24..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MethodDelegator.Interop.cs +++ /dev/null @@ -1,21 +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. - -namespace Internal.TypeSystem -{ - partial class MethodDelegator - { - public override bool IsPInvoke => _wrappedMethod.IsPInvoke; - - public override PInvokeMetadata GetPInvokeMethodMetadata() - { - return _wrappedMethod.GetPInvokeMethodMetadata(); - } - - public override ParameterMetadata[] GetParameterMetadata() - { - return _wrappedMethod.GetParameterMetadata(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MethodDesc.Interop.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MethodDesc.Interop.cs deleted file mode 100644 index d496dcf0d1a..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MethodDesc.Interop.cs +++ /dev/null @@ -1,370 +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 System.Runtime.InteropServices; - -namespace Internal.TypeSystem -{ - // Additional extensions to MethodDesc related to interop - partial class MethodDesc - { - /// - /// Gets a value indicating whether this method is a (native unmanaged) platform invoke. - /// Use to retrieve the platform invoke detail information. - /// - public virtual bool IsPInvoke - { - get - { - return false; - } - } - - /// - /// If is true, retrieves the metadata related to the platform invoke. - /// - public virtual PInvokeMetadata GetPInvokeMethodMetadata() - { - return default(PInvokeMetadata); - } - - /// - /// Retrieves the metadata related to the parameters of the method. - /// - public virtual ParameterMetadata[] GetParameterMetadata() - { - return Array.Empty(); - } - } - - [Flags] - public enum ParameterMetadataAttributes - { - None = 0, - In = 1, - Out = 2, - Optional = 16, - HasDefault = 4096, - HasFieldMarshal = 8192 - } - - public struct ParameterMetadata - { - private readonly ParameterMetadataAttributes _attributes; - public readonly MarshalAsDescriptor MarshalAsDescriptor; - - /// - /// Gets a 1-based index of the parameter within the signature the metadata refers to. - /// Index 0 is the return value. - /// - public readonly int Index; - - public bool In { get { return (_attributes & ParameterMetadataAttributes.In) == ParameterMetadataAttributes.In; } } - public bool Out { get { return (_attributes & ParameterMetadataAttributes.Out) == ParameterMetadataAttributes.Out; } } - public bool Return { get { return Index == 0; } } - public bool Optional { get { return (_attributes & ParameterMetadataAttributes.Optional) == ParameterMetadataAttributes.Optional; } } - public bool HasDefault { get { return (_attributes & ParameterMetadataAttributes.HasDefault) == ParameterMetadataAttributes.HasDefault; } } - public bool HasFieldMarshal { get { return (_attributes & ParameterMetadataAttributes.HasFieldMarshal) == ParameterMetadataAttributes.HasFieldMarshal; } } - - - public ParameterMetadata(int index, ParameterMetadataAttributes attributes, MarshalAsDescriptor marshalAsDescriptor) - { - Index = index; - _attributes = attributes; - MarshalAsDescriptor = marshalAsDescriptor; - } - } - - [Flags] - public enum PInvokeAttributes - { - // These should match System.Reflection.MethodImportAttributes - None = 0, - ExactSpelling = 1, - CharSetAnsi = 2, - CharSetUnicode = 4, - CharSetAuto = 6, - CharSetMask = 6, - BestFitMappingEnable = 16, - BestFitMappingDisable = 32, - BestFitMappingMask = 48, - SetLastError = 64, - CallingConventionWinApi = 256, - CallingConventionCDecl = 512, - CallingConventionStdCall = 768, - CallingConventionThisCall = 1024, - CallingConventionFastCall = 1280, - CallingConventionMask = 1792, - ThrowOnUnmappableCharEnable = 4096, - ThrowOnUnmappableCharDisable = 8192, - ThrowOnUnmappableCharMask = 12288, - - // Not actually part of MethodImportAttributes. - // MethodImportAttributes is limited to `short`. This enum is based on int - // and we have 16 spare bytes. - PreserveSig = 0x10000, - } - - public struct PInvokeFlags : IEquatable, IComparable - { - private PInvokeAttributes _attributes; - public PInvokeAttributes Attributes - { - get - { - return _attributes; - } - } - - public PInvokeFlags(PInvokeAttributes attributes) - { - _attributes = attributes; - } - - public CharSet CharSet - { - get - { - PInvokeAttributes mask = _attributes & PInvokeAttributes.CharSetMask; - - // ECMA-335 II.10.1.5 - Default value is Ansi. - CharSet charset = CharSet.Ansi; - - if (mask == PInvokeAttributes.CharSetUnicode || mask == PInvokeAttributes.CharSetAuto) - { - charset = CharSet.Unicode; - } - return charset; - } - - set - { - // clear the charset bits; - _attributes &= ~(PInvokeAttributes.CharSetMask); - if (value == CharSet.Unicode || (short)value == 4) // CharSet.Auto has value 4, but not in the enum - { - _attributes |= PInvokeAttributes.CharSetUnicode; - } - else - { - _attributes |= PInvokeAttributes.CharSetAnsi; - } - } - } - - public MethodSignatureFlags UnmanagedCallingConvention - { - get - { - switch (_attributes & PInvokeAttributes.CallingConventionMask) - { - case PInvokeAttributes.CallingConventionWinApi: - return MethodSignatureFlags.UnmanagedCallingConventionStdCall; // TODO: CDecl for varargs - case PInvokeAttributes.CallingConventionCDecl: - return MethodSignatureFlags.UnmanagedCallingConventionCdecl; - case PInvokeAttributes.CallingConventionStdCall: - return MethodSignatureFlags.UnmanagedCallingConventionStdCall; - case PInvokeAttributes.CallingConventionThisCall: - return MethodSignatureFlags.UnmanagedCallingConventionThisCall; - case PInvokeAttributes.None: - return MethodSignatureFlags.None; - default: - throw new BadImageFormatException(); - } - } - set - { - _attributes &= ~(PInvokeAttributes.CallingConventionMask); - switch (value) - { - - case MethodSignatureFlags.UnmanagedCallingConventionStdCall: - _attributes |= PInvokeAttributes.CallingConventionStdCall; - break; - case MethodSignatureFlags.UnmanagedCallingConventionCdecl: - _attributes |= PInvokeAttributes.CallingConventionCDecl; - break; - case MethodSignatureFlags.UnmanagedCallingConventionThisCall: - _attributes |= PInvokeAttributes.CallingConventionThisCall; - break; - default: - System.Diagnostics.Debug.Fail("Unexpected Unmanaged Calling Convention."); - break; - } - } - } - - public bool SetLastError - { - get - { - return (_attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError; - } - set - { - if (value) - { - _attributes |= PInvokeAttributes.SetLastError; - } - else - { - _attributes &= ~(PInvokeAttributes.SetLastError); - } - } - } - - public bool ExactSpelling - { - get - { - return (_attributes & PInvokeAttributes.ExactSpelling) == PInvokeAttributes.ExactSpelling; - } - set - { - if (value) - { - _attributes |= PInvokeAttributes.ExactSpelling; - } - else - { - _attributes &= ~(PInvokeAttributes.ExactSpelling); - } - } - } - - public bool BestFitMapping - { - get - { - PInvokeAttributes mask = _attributes & PInvokeAttributes.BestFitMappingMask; - if (mask == PInvokeAttributes.BestFitMappingDisable) - { - return false; - } - // default value is true - return true; - } - set - { - _attributes &= ~(PInvokeAttributes.BestFitMappingMask); - if (value) - { - _attributes |= PInvokeAttributes.BestFitMappingEnable; - } - else - { - _attributes |= PInvokeAttributes.BestFitMappingDisable; - } - } - } - - public bool ThrowOnUnmappableChar - { - get - { - PInvokeAttributes mask = _attributes & PInvokeAttributes.ThrowOnUnmappableCharMask; - if (mask == PInvokeAttributes.ThrowOnUnmappableCharEnable) - { - return true; - } - // default value is false - return false; - } - set - { - _attributes &= ~(PInvokeAttributes.ThrowOnUnmappableCharMask); - if (value) - { - _attributes |= PInvokeAttributes.ThrowOnUnmappableCharEnable; - } - else - { - _attributes |= PInvokeAttributes.ThrowOnUnmappableCharDisable; - } - } - } - - public bool PreserveSig - { - get - { - return (_attributes & PInvokeAttributes.PreserveSig) != 0; - } - set - { - if (value) - { - _attributes |= PInvokeAttributes.PreserveSig; - } - else - { - _attributes &= ~PInvokeAttributes.PreserveSig; - } - } - } - - public int CompareTo(PInvokeFlags other) - { - return Attributes.CompareTo(other.Attributes); - } - - public bool Equals(PInvokeFlags other) - { - return Attributes == other.Attributes; - } - - public override bool Equals(object obj) - { - return obj is PInvokeFlags other && Equals(other); - } - - public override int GetHashCode() - { - return Attributes.GetHashCode(); - } - } - - /// - /// Represents details about a pinvokeimpl method import. - /// - public struct PInvokeMetadata - { - public readonly string Name; - - public readonly string Module; - - public readonly PInvokeFlags Flags; - - public PInvokeMetadata(string module, string entrypoint, PInvokeAttributes attributes) - { - Name = entrypoint; - Module = module; - Flags = new PInvokeFlags(attributes); - } - - public PInvokeMetadata(string module, string entrypoint, PInvokeFlags flags) - { - Name = entrypoint; - Module = module; - Flags = flags; - } - } - - partial class InstantiatedMethod - { - public override ParameterMetadata[] GetParameterMetadata() - { - return _methodDef.GetParameterMetadata(); - } - } - - partial class MethodForInstantiatedType - { - public override ParameterMetadata[] GetParameterMetadata() - { - return _typicalMethodDef.GetParameterMetadata(); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledMethod.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledMethod.cs deleted file mode 100644 index 7e06aa83d26..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledMethod.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - /// - /// When implemented by a or , instructs a name mangler to use the same mangled name - /// as another entity while prepending a specific prefix to that mangled name. - /// - public interface IPrefixMangledMethod - { - /// - /// Method whose mangled name to use. - /// - MethodDesc BaseMethod { get; } - - /// - /// Prefix to apply when mangling. - /// - string Prefix { get; } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledSignature.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledSignature.cs deleted file mode 100644 index 3dabbc53a67..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledSignature.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - /// - /// When implemented by a , instructs a name mangler to use the same mangled name - /// as another entity while prepending a specific prefix to that mangled name. - /// - public interface IPrefixMangledSignature - { - /// - /// Signature whose mangled name to use. - /// - MethodSignature BaseSignature { get; } - - /// - /// Prefix to apply when mangling. - /// - string Prefix { get; } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledType.cs deleted file mode 100644 index 8ea628abdc1..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Mangling/IPrefixMangledType.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - /// - /// When implemented by a or , instructs a name mangler to use the same mangled name - /// as another entity while prepending a specific prefix to that mangled name. - /// - public interface IPrefixMangledType - { - /// - /// Type whose mangled name to use. - /// - TypeDesc BaseType { get; } - - /// - /// Prefix to apply when mangling. - /// - string Prefix { get; } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ArrayType.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ArrayType.RuntimeDetermined.cs deleted file mode 100644 index 08983940ffa..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ArrayType.RuntimeDetermined.cs +++ /dev/null @@ -1,34 +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. - -namespace Internal.TypeSystem -{ - partial class ArrayType - { - public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc parameterTypeConverted = ParameterType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); - if (ParameterType != parameterTypeConverted) - { - return Context.GetArrayType(parameterTypeConverted, _rank); - } - - return this; - } - } - - partial class ArrayMethod - { - public override MethodDesc GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc owningType = this.OwningType; - TypeDesc instantiatedOwningType = owningType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); - - if (owningType != instantiatedOwningType) - return ((ArrayType)instantiatedOwningType).GetArrayMethod(_kind); - else - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ByRefType.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ByRefType.RuntimeDetermined.cs deleted file mode 100644 index a10a9c8e5e7..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ByRefType.RuntimeDetermined.cs +++ /dev/null @@ -1,20 +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. - -namespace Internal.TypeSystem -{ - partial class ByRefType - { - public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc parameterTypeConverted = ParameterType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); - if (ParameterType != parameterTypeConverted) - { - return Context.GetByRefType(parameterTypeConverted); - } - - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs deleted file mode 100644 index 02d1b252339..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs +++ /dev/null @@ -1,87 +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. - -namespace Internal.TypeSystem -{ - partial class DefType - { - public override bool IsRuntimeDeterminedSubtype - { - get - { - // Handles situation when shared code refers to uninstantiated generic - // type definitions (think: LDTOKEN). - // Walking the instantiation would make us assert. This is simply - // not a runtime determined type. - if (IsGenericDefinition) - return false; - - foreach (TypeDesc type in Instantiation) - { - if (type.IsRuntimeDeterminedSubtype) - return true; - } - return false; - } - } - - /// - /// Converts the type to the shared runtime determined form where the types this type is instantiatied - /// over become bound to the generic parameters of this type. - /// - public DefType ConvertToSharedRuntimeDeterminedForm() - { - Instantiation instantiation = Instantiation; - if (instantiation.Length > 0) - { - MetadataType typeDefinition = (MetadataType)GetTypeDefinition(); - - bool changed; - Instantiation sharedInstantiation = RuntimeDeterminedTypeUtilities.ConvertInstantiationToSharedRuntimeForm( - instantiation, typeDefinition.Instantiation, out changed); - if (changed) - { - return Context.GetInstantiatedType(typeDefinition, sharedInstantiation); - } - } - - return this; - } - - public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc typeDefinition = GetTypeDefinition(); - if (this == typeDefinition) - return this; - - Instantiation instantiation = Instantiation; - TypeDesc[] clone = null; - - for (int i = 0; i < instantiation.Length; i++) - { - TypeDesc uninst = instantiation[i]; - TypeDesc inst = uninst.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); - if (inst != uninst) - { - if (clone == null) - { - clone = new TypeDesc[instantiation.Length]; - for (int j = 0; j < clone.Length; j++) - { - clone[j] = instantiation[j]; - } - } - clone[i] = inst; - } - } - - if (clone != null) - { - return Context.GetInstantiatedType((MetadataType)typeDefinition, new Instantiation(clone)); - } - - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/FieldDesc.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/FieldDesc.RuntimeDetermined.cs deleted file mode 100644 index c3bd99565e8..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/FieldDesc.RuntimeDetermined.cs +++ /dev/null @@ -1,21 +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. - -namespace Internal.TypeSystem -{ - partial class FieldDesc - { - public FieldDesc GetNonRuntimeDeterminedFieldFromRuntimeDeterminedFieldViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - DefType owningType = OwningType; - TypeDesc owningTypeInstantiated = owningType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); - if (owningTypeInstantiated != owningType) - { - return Context.GetFieldForInstantiatedType(GetTypicalFieldDefinition(), (InstantiatedType)owningTypeInstantiated); - } - - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/FunctionPointerType.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/FunctionPointerType.RuntimeDetermined.cs deleted file mode 100644 index 3ad0e6e701f..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/FunctionPointerType.RuntimeDetermined.cs +++ /dev/null @@ -1,32 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - partial class FunctionPointerType - { - public override bool IsRuntimeDeterminedSubtype - { - get - { - if (_signature.ReturnType.IsRuntimeDeterminedSubtype) - return true; - - for (int i = 0; i < _signature.Length; i++) - if (_signature[i].IsRuntimeDeterminedSubtype) - return true; - - return false; - } - } - - public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - Debug.Assert(false); - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/GenericParameterDesc.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/GenericParameterDesc.RuntimeDetermined.cs deleted file mode 100644 index 79b2b7b429e..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/GenericParameterDesc.RuntimeDetermined.cs +++ /dev/null @@ -1,26 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - partial class GenericParameterDesc - { - public sealed override bool IsRuntimeDeterminedSubtype - { - get - { - Debug.Fail("IsRuntimeDeterminedSubtype of an indefinite type"); - return false; - } - } - - public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - Debug.Assert(false); - return this; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs deleted file mode 100644 index 8fd47116dd9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs +++ /dev/null @@ -1,141 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - partial class MethodDesc - { - /// - /// Gets the shared runtime determined form of the method. This is a canonical form of the method - /// where generic arguments of the method and the owning type have been converted to runtime determined types. - /// - public MethodDesc GetSharedRuntimeFormMethodTarget() - { - MethodDesc result = this; - - DefType owningType = OwningType as DefType; - if (owningType != null) - { - // First find the method on the shared runtime form of the owning type - DefType sharedRuntimeOwningType = owningType.ConvertToSharedRuntimeDeterminedForm(); - if (sharedRuntimeOwningType != owningType) - { - result = Context.GetMethodForInstantiatedType( - GetTypicalMethodDefinition(), (InstantiatedType)sharedRuntimeOwningType); - } - - // Now convert the method instantiation to the shared runtime form - if (result.HasInstantiation) - { - MethodDesc uninstantiatedMethod = result.GetMethodDefinition(); - - bool changed; - Instantiation sharedInstantiation = RuntimeDeterminedTypeUtilities.ConvertInstantiationToSharedRuntimeForm( - Instantiation, uninstantiatedMethod.Instantiation, out changed); - - // If either the instantiation changed, or we switched the owning type, we need to find the matching - // instantiated method. - if (changed || result != this) - { - result = Context.GetInstantiatedMethod(uninstantiatedMethod, sharedInstantiation); - } - } - } - - return result; - } - - /// - /// Gets the type which holds the implementation of this method. This is typically the owning method, - /// unless this method models a target of a constrained method call. - /// - public TypeDesc ImplementationType - { - get - { - // TODO: IsConstrainedMethod - return OwningType; - } - } - - /// - /// Gets a value indicating whether this is a shared method body. - /// - public bool IsSharedByGenericInstantiations - { - get - { - return IsCanonicalMethod(CanonicalFormKind.Any); - } - } - - /// - /// Gets a value indicating whether this is a canonical method that will only become concrete - /// at runtime (after supplying the generic context). - /// - public bool IsRuntimeDeterminedExactMethod - { - get - { - TypeDesc containingType = ImplementationType; - if (containingType.IsRuntimeDeterminedSubtype) - return true; - - // Handles situation when shared code refers to uninstantiated generic - // method definitions (think: LDTOKEN). - // Walking the instantiation would make us assert. This is simply - // not a runtime determined method. - if (IsGenericMethodDefinition) - return false; - - foreach (TypeDesc typeArg in Instantiation) - { - if (typeArg.IsRuntimeDeterminedSubtype) - return true; - } - - return false; - } - } - - public virtual MethodDesc GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - Instantiation instantiation = Instantiation; - TypeDesc[] clone = null; - - for (int i = 0; i < instantiation.Length; i++) - { - TypeDesc uninst = instantiation[i]; - TypeDesc inst = uninst.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); - if (inst != uninst) - { - if (clone == null) - { - clone = new TypeDesc[instantiation.Length]; - for (int j = 0; j < clone.Length; j++) - { - clone[j] = instantiation[j]; - } - } - clone[i] = inst; - } - } - - MethodDesc method = this; - - TypeDesc owningType = method.OwningType; - TypeDesc instantiatedOwningType = owningType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); - if (owningType != instantiatedOwningType) - { - method = Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType); - if (clone == null && instantiation.Length != 0) - return Context.GetInstantiatedMethod(method, instantiation); - } - - return (clone == null) ? method : Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone)); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.cs deleted file mode 100644 index 3aa3b441fd6..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.cs +++ /dev/null @@ -1,11 +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. - -namespace Internal.TypeSystem -{ - partial class MethodForRuntimeDeterminedType - { - public override string DiagnosticName => _typicalMethodDef.DiagnosticName; - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Sorting.cs deleted file mode 100644 index dd318b30ce9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Sorting.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to deterministic ordering of types - partial class MethodForRuntimeDeterminedType - { - protected internal override int ClassCode => 719937490; - - protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) - { - var otherMethod = (MethodForRuntimeDeterminedType)other; - - int result = comparer.CompareWithinClass(_rdType, otherMethod._rdType); - if (result != 0) - return result; - - return comparer.Compare(_typicalMethodDef, otherMethod._typicalMethodDef); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs deleted file mode 100644 index 2ae3380ad12..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs +++ /dev/null @@ -1,62 +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 System.Diagnostics; - -namespace Internal.TypeSystem -{ - public sealed partial class MethodForRuntimeDeterminedType : MethodDesc - { - private MethodDesc _typicalMethodDef; - private RuntimeDeterminedType _rdType; - - internal MethodForRuntimeDeterminedType(MethodDesc typicalMethodDef, RuntimeDeterminedType rdType) - { - Debug.Assert(typicalMethodDef.IsTypicalMethodDefinition); - - _typicalMethodDef = typicalMethodDef; - _rdType = rdType; - } - - // This constructor is a performance optimization - it allows supplying the hash code if it has already - // been computed prior to the allocation of this type. The supplied hash code still has to match the - // hash code this type would compute on it's own (and we assert to enforce that). - internal MethodForRuntimeDeterminedType(MethodDesc typicalMethodDef, RuntimeDeterminedType rdType, int hashcode) - : this(typicalMethodDef, rdType) - { - SetHashCode(hashcode); - } - - public override TypeSystemContext Context => _typicalMethodDef.Context; - public override TypeDesc OwningType => _rdType; - public override MethodSignature Signature => _typicalMethodDef.Signature; - public override bool IsVirtual => _typicalMethodDef.IsVirtual; - public override bool IsNewSlot => _typicalMethodDef.IsNewSlot; - public override bool IsAbstract => _typicalMethodDef.IsAbstract; - public override bool IsFinal => _typicalMethodDef.IsFinal; - public override bool IsDefaultConstructor => _typicalMethodDef.IsDefaultConstructor; - public override string Name => _typicalMethodDef.Name; - public override MethodDesc GetTypicalMethodDefinition() => _typicalMethodDef; - public override Instantiation Instantiation => _typicalMethodDef.Instantiation; - - public override bool HasCustomAttribute(string attributeNamespace, string attributeName) - { - return _typicalMethodDef.HasCustomAttribute(attributeNamespace, attributeName); - } - - public override bool IsCanonicalMethod(CanonicalFormKind policy) - { - // Owning type is a RuntimeDeterminedType, so it can never be canonical. - // Instantiation for the method can also never be canonical since it's a typical method definition. - return false; - } - - public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) - { - TypeDesc canonicalizedTypeOfTargetMethod = _rdType.CanonicalType.ConvertToCanonForm(kind); - return Context.GetMethodForInstantiatedType(_typicalMethodDef, (InstantiatedType)canonicalizedTypeOfTargetMethod); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ParameterizedType.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ParameterizedType.RuntimeDetermined.cs deleted file mode 100644 index f48325c7ebd..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/ParameterizedType.RuntimeDetermined.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem -{ - partial class ParameterizedType - { - public sealed override bool IsRuntimeDeterminedSubtype - { - get - { - return _parameterType.IsRuntimeDeterminedSubtype; - } - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/PointerType.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/PointerType.RuntimeDetermined.cs deleted file mode 100644 index f3ef66f3712..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/PointerType.RuntimeDetermined.cs +++ /dev/null @@ -1,20 +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. - -namespace Internal.TypeSystem -{ - partial class PointerType - { - public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - TypeDesc parameterTypeConverted = ParameterType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation); - if (ParameterType != parameterTypeConverted) - { - return Context.GetPointerType(parameterTypeConverted); - } - - return this; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedCanonicalizationAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedCanonicalizationAlgorithm.cs deleted file mode 100644 index f1ea5fc96b0..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedCanonicalizationAlgorithm.cs +++ /dev/null @@ -1,151 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// Contains utility functionality for canonicalization used by multiple types. - /// This implementation can handle runtime determined types and the various fallouts from using them - /// (e.g. the ability to upgrade to - /// if somewhere within the construction of the type we encounter a universal form). - /// - public static class RuntimeDeterminedCanonicalizationAlgorithm - { - public static Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) - { - TypeDesc[] canonInstantiation = null; - - CanonicalFormKind currentKind = kind; - CanonicalFormKind startLoopKind; - - // This logic is wrapped in a loop because we might potentially need to restart canonicalization if the policy - // changes due to one of the instantiation arguments already being universally canonical. - do - { - startLoopKind = currentKind; - - for (int instantiationIndex = 0; instantiationIndex < instantiation.Length; instantiationIndex++) - { - TypeDesc typeToConvert = instantiation[instantiationIndex]; - TypeDesc canonForm = ConvertToCanon(typeToConvert, ref currentKind); - if (typeToConvert != canonForm || canonInstantiation != null) - { - if (canonInstantiation == null) - { - canonInstantiation = new TypeDesc[instantiation.Length]; - for (int i = 0; i < instantiationIndex; i++) - canonInstantiation[i] = instantiation[i]; - } - - canonInstantiation[instantiationIndex] = canonForm; - } - } - - // Optimization: even if canonical policy changed, we don't actually need to re-run the loop - // for instantiations that only have a single element. - if (instantiation.Length == 1) - { - break; - } - - } while (currentKind != startLoopKind); - - - changed = canonInstantiation != null; - if (changed) - { - return new Instantiation(canonInstantiation); - } - - return instantiation; - } - - public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) - { - // Wrap the call to the version that potentially modifies the parameter. External - // callers are not interested in that. - return ConvertToCanon(typeToConvert, ref kind); - } - - public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) - { - TypeSystemContext context = typeToConvert.Context; - if (kind == CanonicalFormKind.Universal) - { - return context.UniversalCanonType; - } - else if (kind == CanonicalFormKind.Specific) - { - if (typeToConvert == context.UniversalCanonType) - { - kind = CanonicalFormKind.Universal; - return context.UniversalCanonType; - } - else if (typeToConvert.IsSignatureVariable) - { - return typeToConvert; - } - else if (typeToConvert.IsDefType) - { - if (!typeToConvert.IsValueType) - { - return context.CanonType; - } - else if (typeToConvert.HasInstantiation) - { - TypeDesc canonicalType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); - - // This is a generic struct type. If the generic struct is instantiated over universal canon, - // the entire struct becomes universally canonical. - if (canonicalType.IsCanonicalSubtype(CanonicalFormKind.Universal)) - { - kind = CanonicalFormKind.Universal; - return context.UniversalCanonType; - } - - return canonicalType; - } - else if (typeToConvert.IsRuntimeDeterminedType) - { - // For non-universal canon cases, RuntimeDeterminedType's passed into this function are either - // reference types (which are turned into normal Canon), or instantiated types (which are handled - // by the above case.). But for UniversalCanon, we can have non-instantiated universal canon - // which will reach this case. - - // We should only ever reach this for T__UniversalCanon. - Debug.Assert(((RuntimeDeterminedType)typeToConvert).CanonicalType == context.UniversalCanonType); - - kind = CanonicalFormKind.Universal; - return context.UniversalCanonType; - } - else - { - return typeToConvert; - } - } - else if (typeToConvert.IsArray) - { - return context.CanonType; - } - else - { - if (typeToConvert.IsCanonicalSubtype(CanonicalFormKind.Universal)) - { - kind = CanonicalFormKind.Universal; - return context.UniversalCanonType; - } - - return typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); - } - } - else - { - Debug.Assert(false); - return null; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs deleted file mode 100644 index 75039d735b2..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs +++ /dev/null @@ -1,70 +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 System.Collections.Generic; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// RuntimeDeterminedFieldLayoutAlgorithm algorithm which can be used to compute field layout - /// for any RuntimeDeterminedType - /// Only useable for accessing the instance field size - /// - public class RuntimeDeterminedFieldLayoutAlgorithm : FieldLayoutAlgorithm - { - public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind) - { - // Individual field offset layout for a RuntimeDeterminedType is not a supported operation - if (layoutKind != InstanceLayoutKind.TypeOnly) - throw new NotSupportedException(); - - RuntimeDeterminedType type = (RuntimeDeterminedType)defType; - DefType canonicalType = type.CanonicalType; - - ComputedInstanceFieldLayout result = new ComputedInstanceFieldLayout - { - ByteCountUnaligned = canonicalType.InstanceByteCountUnaligned, - ByteCountAlignment = canonicalType.InstanceByteAlignment, - FieldAlignment = canonicalType.InstanceFieldAlignment, - FieldSize = canonicalType.InstanceFieldSize, - Offsets = Array.Empty() - }; - - return result; - } - - public unsafe override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind) - { - // Static field layout for a RuntimeDeterminedType is not a supported operation - throw new NotSupportedException(); - } - - public override bool ComputeContainsGCPointers(DefType type) - { - RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type; - DefType canonicalType = runtimeDeterminedType.CanonicalType; - - return canonicalType.ContainsGCPointers; - } - - public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) - { - RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type; - DefType canonicalType = runtimeDeterminedType.CanonicalType; - - return canonicalType.ValueTypeShapeCharacteristics; - } - - public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) - { - RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type; - DefType canonicalType = runtimeDeterminedType.CanonicalType; - - return canonicalType.HfaElementType; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs deleted file mode 100644 index 8b9a7cca1d5..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs +++ /dev/null @@ -1,25 +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. - -namespace Internal.TypeSystem -{ - partial class RuntimeDeterminedType - { - public override string DiagnosticName - { - get - { - return _rawCanonType.DiagnosticName; - } - } - - public override string DiagnosticNamespace - { - get - { - return _rawCanonType.DiagnosticNamespace; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Sorting.cs deleted file mode 100644 index 685bf46ad08..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Sorting.cs +++ /dev/null @@ -1,22 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class RuntimeDeterminedType - { - protected internal override int ClassCode => 351938209; - - protected internal sealed override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - var otherType = (RuntimeDeterminedType)other; - int result = comparer.Compare(_rawCanonType, otherType._rawCanonType); - if (result != 0) - return result; - - return comparer.Compare(_runtimeDeterminedDetailsType, otherType._runtimeDeterminedDetailsType); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.cs deleted file mode 100644 index 48abf82860a..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.cs +++ /dev/null @@ -1,189 +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 System.Collections.Generic; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - /// - /// Represents a runtime determined type. Runtime determined types are used to represent types - /// within shared generic method bodies and generic dictionaries. The concrete type will only - /// be known at runtime (when executing a shared generic method body under a specific generic context). - /// - /// - /// The use of runtime determined types is limited to the dependency analysis and to communicating - /// with the codegen backend during shared generic code generation. They should not show up within - /// the system otherwise. - /// - /// Runtime determined types behave mostly like the canonical type they are wrapping. Most of the overrides - /// this type implements will forward the implementation to the 's - /// implementation. - /// - /// Runtime determined types also behave like signature variables in the sense that they allow being - /// substituted during signature instantiation. - /// - public sealed partial class RuntimeDeterminedType : DefType - { - private DefType _rawCanonType; - private GenericParameterDesc _runtimeDeterminedDetailsType; - - public RuntimeDeterminedType(DefType rawCanonType, GenericParameterDesc runtimeDeterminedDetailsType) - { - _rawCanonType = rawCanonType; - _runtimeDeterminedDetailsType = runtimeDeterminedDetailsType; - } - - /// - /// Gets the generic parameter this runtime determined type represents. - /// - public GenericParameterDesc RuntimeDeterminedDetailsType - { - get - { - return _runtimeDeterminedDetailsType; - } - } - - /// - /// Gets the canonical type wrapped by this runtime determined type. - /// - public DefType CanonicalType - { - get - { - return _rawCanonType; - } - } - - public override TypeSystemContext Context - { - get - { - return _rawCanonType.Context; - } - } - - public override bool IsRuntimeDeterminedSubtype - { - get - { - return true; - } - } - - public override DefType BaseType - { - get - { - return _rawCanonType.BaseType; - } - } - - public override Instantiation Instantiation - { - get - { - return _rawCanonType.Instantiation; - } - } - - public override string Name - { - get - { - return _rawCanonType.Name; - } - } - - public override string Namespace - { - get - { - return String.Concat(_runtimeDeterminedDetailsType.Name, "_", _rawCanonType.Namespace); - } - } - - public override IEnumerable GetMethods() - { - foreach (var method in _rawCanonType.GetMethods()) - { - yield return Context.GetMethodForRuntimeDeterminedType(method.GetTypicalMethodDefinition(), this); - } - } - - public override MethodDesc GetMethod(string name, MethodSignature signature) - { - MethodDesc method = _rawCanonType.GetMethod(name, signature); - if (method == null) - return null; - return Context.GetMethodForRuntimeDeterminedType(method.GetTypicalMethodDefinition(), this); - } - - protected override TypeFlags ComputeTypeFlags(TypeFlags mask) - { - TypeFlags flags = 0; - - if ((mask & TypeFlags.CategoryMask) != 0) - { - flags |= _rawCanonType.GetTypeFlags(mask); - } - - if ((mask & TypeFlags.HasGenericVarianceComputed) != 0) - { - flags |= _rawCanonType.GetTypeFlags(mask); - } - - if ((mask & TypeFlags.AttributeCacheComputed) != 0) - { - flags |= _rawCanonType.GetTypeFlags(mask); - } - - // Might need to define the behavior if we ever hit this. - Debug.Assert((flags & mask) != 0); - return flags; - } - - public override TypeDesc GetTypeDefinition() - { - // TODO: this is needed because NameMangler calls it to see if we're dealing with genericness. Revise? - if (_rawCanonType.HasInstantiation) - { - return Context.GetRuntimeDeterminedType((DefType)_rawCanonType.GetTypeDefinition(), _runtimeDeterminedDetailsType); - } - - return this; - } - - public override int GetHashCode() - { - return _rawCanonType.GetHashCode(); - } - - protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind) - { - return _rawCanonType.ConvertToCanonForm(kind); - } - - public override bool IsCanonicalSubtype(CanonicalFormKind policy) - { - return false; - } - - public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - if (_runtimeDeterminedDetailsType.Kind == GenericParameterKind.Type) - { - return typeInstantiation[_runtimeDeterminedDetailsType.Index]; - } - else - { - Debug.Assert(_runtimeDeterminedDetailsType.Kind == GenericParameterKind.Method); - return methodInstantiation[_runtimeDeterminedDetailsType.Index]; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedTypeUtilities.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedTypeUtilities.cs deleted file mode 100644 index d8411a65b12..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedTypeUtilities.cs +++ /dev/null @@ -1,71 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - internal static class RuntimeDeterminedTypeUtilities - { - public static Instantiation ConvertInstantiationToSharedRuntimeForm(Instantiation instantiation, Instantiation openInstantiation, out bool changed) - { - Debug.Assert(instantiation.Length == openInstantiation.Length); - - TypeDesc[] sharedInstantiation = null; - - CanonicalFormKind currentPolicy = CanonicalFormKind.Specific; - CanonicalFormKind startLoopPolicy; - - do - { - startLoopPolicy = currentPolicy; - - for (int instantiationIndex = 0; instantiationIndex < instantiation.Length; instantiationIndex++) - { - TypeDesc typeToConvert = instantiation[instantiationIndex]; - TypeSystemContext context = typeToConvert.Context; - TypeDesc canonForm = context.ConvertToCanon(typeToConvert, ref currentPolicy); - TypeDesc runtimeDeterminedForm = typeToConvert; - - Debug.Assert(openInstantiation[instantiationIndex] is GenericParameterDesc); - - if ((typeToConvert != canonForm) || typeToConvert.IsCanonicalType) - { - Debug.Assert(canonForm is DefType); - if (sharedInstantiation == null) - { - sharedInstantiation = new TypeDesc[instantiation.Length]; - for (int i = 0; i < instantiationIndex; i++) - sharedInstantiation[i] = instantiation[i]; - } - - runtimeDeterminedForm = context.GetRuntimeDeterminedType( - (DefType)canonForm, (GenericParameterDesc)openInstantiation[instantiationIndex]); - } - - if (sharedInstantiation != null) - { - sharedInstantiation[instantiationIndex] = runtimeDeterminedForm; - } - } - - // Optimization: even if canonical policy changed, we don't actually need to re-run the loop - // for instantiations that only have a single element. - if (instantiation.Length == 1) - { - break; - } - - } while (currentPolicy != startLoopPolicy); - - changed = sharedInstantiation != null; - if (changed) - { - return new Instantiation(sharedInstantiation); - } - - return instantiation; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/SignatureVariable.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/SignatureVariable.RuntimeDetermined.cs deleted file mode 100644 index 416cc19d1c9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/SignatureVariable.RuntimeDetermined.cs +++ /dev/null @@ -1,26 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - partial class SignatureVariable - { - public sealed override bool IsRuntimeDeterminedSubtype - { - get - { - Debug.Fail("IsRuntimeDeterminedSubtype of an indefinite type"); - return false; - } - } - - public override TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation) - { - Debug.Assert(false); - return this; - } - } -} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/TypeDesc.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/TypeDesc.RuntimeDetermined.cs deleted file mode 100644 index c21ee835aaf..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/TypeDesc.RuntimeDetermined.cs +++ /dev/null @@ -1,35 +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. - -namespace Internal.TypeSystem -{ - partial class TypeDesc - { - /// - /// Gets a value indicating whether the concrete type this object represents is unknown - /// at compile time. For a constructed type, returns true if any of the constituents are - /// unknown at compile time. Use to check if - /// this is a runtime determined type without checking constituents. - /// - public abstract bool IsRuntimeDeterminedSubtype - { - get; - } - - /// - /// Gets a value indicating whether this is a runtime determined type. This will not - /// check the composition of constructed types for runtime determined types. Use - /// to do that. - /// - public bool IsRuntimeDeterminedType - { - get - { - return this.GetType() == typeof(RuntimeDeterminedType); - } - } - - public abstract TypeDesc GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/TypeSystemContext.RuntimeDetermined.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/TypeSystemContext.RuntimeDetermined.cs deleted file mode 100644 index e84d8752421..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/TypeSystemContext.RuntimeDetermined.cs +++ /dev/null @@ -1,142 +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 System.Diagnostics; - -using Internal.NativeFormat; - -namespace Internal.TypeSystem -{ - partial class TypeSystemContext - { - private struct RuntimeDeterminedTypeKey - { - private DefType _plainCanonType; - private GenericParameterDesc _detailsType; - - public RuntimeDeterminedTypeKey(DefType plainCanonType, GenericParameterDesc detailsType) - { - _plainCanonType = plainCanonType; - _detailsType = detailsType; - } - - public class RuntimeDeterminedTypeKeyHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(RuntimeDeterminedTypeKey key) - { - return key._detailsType.GetHashCode() ^ key._plainCanonType.GetHashCode(); - } - - protected override int GetValueHashCode(RuntimeDeterminedType value) - { - return value.RuntimeDeterminedDetailsType.GetHashCode() ^ value.CanonicalType.GetHashCode(); - } - - protected override bool CompareKeyToValue(RuntimeDeterminedTypeKey key, RuntimeDeterminedType value) - { - return key._detailsType == value.RuntimeDeterminedDetailsType && key._plainCanonType == value.CanonicalType; - } - - protected override bool CompareValueToValue(RuntimeDeterminedType value1, RuntimeDeterminedType value2) - { - return value1.RuntimeDeterminedDetailsType == value2.RuntimeDeterminedDetailsType - && value1.CanonicalType == value2.CanonicalType; - } - - protected override RuntimeDeterminedType CreateValueFromKey(RuntimeDeterminedTypeKey key) - { - return new RuntimeDeterminedType(key._plainCanonType, key._detailsType); - } - } - } - - private RuntimeDeterminedTypeKey.RuntimeDeterminedTypeKeyHashtable _runtimeDeterminedTypes = new RuntimeDeterminedTypeKey.RuntimeDeterminedTypeKeyHashtable(); - - public RuntimeDeterminedType GetRuntimeDeterminedType(DefType plainCanonType, GenericParameterDesc detailsType) - { - return _runtimeDeterminedTypes.GetOrCreateValue(new RuntimeDeterminedTypeKey(plainCanonType, detailsType)); - } - - protected internal virtual TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) - { - throw new NotSupportedException(); - } - - // - // Methods for runtime determined type - // - - private struct MethodForRuntimeDeterminedTypeKey - { - private MethodDesc _typicalMethodDef; - private RuntimeDeterminedType _rdType; - private int _hashcode; - - public MethodForRuntimeDeterminedTypeKey(MethodDesc typicalMethodDef, RuntimeDeterminedType rdType) - { - _typicalMethodDef = typicalMethodDef; - _rdType = rdType; - _hashcode = TypeHashingAlgorithms.ComputeMethodHashCode(rdType.CanonicalType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(typicalMethodDef.Name)); - } - - public MethodDesc TypicalMethodDef - { - get - { - return _typicalMethodDef; - } - } - - public RuntimeDeterminedType RDType - { - get - { - return _rdType; - } - } - - public class MethodForRuntimeDeterminedTypeKeyHashtable : LockFreeReaderHashtable - { - protected override int GetKeyHashCode(MethodForRuntimeDeterminedTypeKey key) - { - return key._hashcode; - } - - protected override int GetValueHashCode(MethodForRuntimeDeterminedType value) - { - return value.GetHashCode(); - } - - protected override bool CompareKeyToValue(MethodForRuntimeDeterminedTypeKey key, MethodForRuntimeDeterminedType value) - { - if (key._typicalMethodDef != value.GetTypicalMethodDefinition()) - return false; - - return key._rdType == value.OwningType; - } - - protected override bool CompareValueToValue(MethodForRuntimeDeterminedType value1, MethodForRuntimeDeterminedType value2) - { - return (value1.GetTypicalMethodDefinition() == value2.GetTypicalMethodDefinition()) && (value1.OwningType == value2.OwningType); - } - - protected override MethodForRuntimeDeterminedType CreateValueFromKey(MethodForRuntimeDeterminedTypeKey key) - { - return new MethodForRuntimeDeterminedType(key.TypicalMethodDef, key.RDType, key._hashcode); - } - } - } - - private MethodForRuntimeDeterminedTypeKey.MethodForRuntimeDeterminedTypeKeyHashtable _methodForRDTypes = new MethodForRuntimeDeterminedTypeKey.MethodForRuntimeDeterminedTypeKeyHashtable(); - - public MethodDesc GetMethodForRuntimeDeterminedType(MethodDesc typicalMethodDef, RuntimeDeterminedType rdType) - { - Debug.Assert(!(typicalMethodDef is MethodForRuntimeDeterminedType)); - Debug.Assert(typicalMethodDef.IsTypicalMethodDefinition); - - return _methodForRDTypes.GetOrCreateValue(new MethodForRuntimeDeterminedTypeKey(typicalMethodDef, rdType)); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Serialization/FieldDesc.Serialization.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Serialization/FieldDesc.Serialization.cs deleted file mode 100644 index 9f5afef28a2..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Serialization/FieldDesc.Serialization.cs +++ /dev/null @@ -1,33 +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. - -namespace Internal.TypeSystem -{ - // Additional members of FieldDesc related to serialization. - partial class FieldDesc - { - /// - /// Gets a value indicating whether this field is not serialized. - /// specially. - /// - public virtual bool IsNotSerialized - { - get - { - return false; - } - } - } - - partial class FieldForInstantiatedType - { - public override bool IsNotSerialized - { - get - { - return _fieldDef.IsNotSerialized; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Serialization/TypeDesc.Serialization.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Serialization/TypeDesc.Serialization.cs deleted file mode 100644 index f8ba33aedd9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Serialization/TypeDesc.Serialization.cs +++ /dev/null @@ -1,31 +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. - -namespace Internal.TypeSystem -{ - partial class TypeDesc - { - /// - /// Gets a value indicating whether this type is serializable. - /// - public virtual bool IsSerializable - { - get - { - return false; - } - } - } - - partial class InstantiatedType - { - public override bool IsSerializable - { - get - { - return _typeDef.IsSerializable; - } - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/ArrayType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/ArrayType.Sorting.cs deleted file mode 100644 index ba20c3609db..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/ArrayType.Sorting.cs +++ /dev/null @@ -1,37 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class ArrayType - { - protected internal override int ClassCode => -1274559616; - - protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - var otherType = (ArrayType)other; - int result = _rank - otherType._rank; - if (result != 0) - return result; - - return comparer.Compare(ElementType, otherType.ElementType); - } - } - - partial class ArrayMethod - { - protected internal override int ClassCode => 487354154; - - protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) - { - var otherMethod = (ArrayMethod)other; - int result = _kind - otherMethod._kind; - if (result != 0) - return result; - - return comparer.CompareWithinClass(OwningArray, otherMethod.OwningArray); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/ByRefType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/ByRefType.Sorting.cs deleted file mode 100644 index 7d5a2392741..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/ByRefType.Sorting.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class ByRefType - { - protected internal override int ClassCode => -959602231; - - protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - return comparer.Compare(ParameterType, ((ByRefType)other).ParameterType); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FieldDesc.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FieldDesc.Sorting.cs deleted file mode 100644 index 9888013b159..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FieldDesc.Sorting.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to deterministic ordering of types and members - partial class FieldDesc - { - /// - /// Gets an identifier that is the same for all instances of this - /// descendant, but different from the of any other descendant. - /// - /// - /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". - /// If two manage to conflict (which is pretty unlikely), just make a new one... - /// - protected internal abstract int ClassCode { get; } - - // Note to implementers: the type of `other` is actually the same as the type of `this`. - protected internal abstract int CompareToImpl(FieldDesc other, TypeSystemComparer comparer); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FieldForInstantiatedType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FieldForInstantiatedType.Sorting.cs deleted file mode 100644 index 720ab2362ca..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FieldForInstantiatedType.Sorting.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to deterministic ordering of types and members - partial class FieldForInstantiatedType - { - protected internal override int ClassCode => 1140200283; - - protected internal override int CompareToImpl(FieldDesc other, TypeSystemComparer comparer) - { - var otherField = (FieldForInstantiatedType)other; - - int result = comparer.CompareWithinClass(_instantiatedType, otherField._instantiatedType); - if (result != 0) - return result; - - return comparer.Compare(_fieldDef, otherField._fieldDef); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FunctionPointerType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FunctionPointerType.Sorting.cs deleted file mode 100644 index d87745d39d7..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/FunctionPointerType.Sorting.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class FunctionPointerType - { - protected internal override int ClassCode => -914739489; - - protected internal sealed override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - return _signature.CompareTo(((FunctionPointerType)other)._signature, comparer); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs deleted file mode 100644 index 17b270780ce..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs +++ /dev/null @@ -1,33 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to deterministic ordering of types - partial class InstantiatedMethod - { - protected internal override int ClassCode => -873941872; - - protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) - { - var otherMethod = (InstantiatedMethod)other; - int result = _instantiation.Length - otherMethod._instantiation.Length; - if (result != 0) - return result; - - result = comparer.Compare(_methodDef, otherMethod._methodDef); - if (result != 0) - return result; - - for (int i = 0; i < _instantiation.Length; i++) - { - result = comparer.Compare(_instantiation[i], otherMethod._instantiation[i]); - if (result != 0) - break; - } - - return result; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs deleted file mode 100644 index f749b455940..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs +++ /dev/null @@ -1,33 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class InstantiatedType - { - protected internal override int ClassCode => 1150020412; - - protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - var otherType = (InstantiatedType)other; - - int result = comparer.Compare(_typeDef, otherType._typeDef); - if (result == 0) - { - Debug.Assert(_instantiation.Length == otherType._instantiation.Length); - for (int i = 0; i < _instantiation.Length; i++) - { - result = comparer.Compare(_instantiation[i], otherType._instantiation[i]); - if (result != 0) - break; - } - } - - return result; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodDesc.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodDesc.Sorting.cs deleted file mode 100644 index a8872050614..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodDesc.Sorting.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to deterministic ordering of types and members - partial class MethodDesc - { - /// - /// Gets an identifier that is the same for all instances of this - /// descendant, but different from the of any other descendant. - /// - /// - /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". - /// If two manage to conflict (which is pretty unlikely), just make a new one... - /// - protected internal abstract int ClassCode { get; } - - // Note to implementers: the type of `other` is actually the same as the type of `this`. - protected internal abstract int CompareToImpl(MethodDesc other, TypeSystemComparer comparer); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodForInstantiatedType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodForInstantiatedType.Sorting.cs deleted file mode 100644 index 3c66f37acc9..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodForInstantiatedType.Sorting.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to deterministic ordering of types - partial class MethodForInstantiatedType - { - protected internal override int ClassCode => 1359759636; - - protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) - { - var otherMethod = (MethodForInstantiatedType)other; - - int result = comparer.CompareWithinClass(_instantiatedType, otherMethod._instantiatedType); - if (result != 0) - return result; - - return comparer.Compare(_typicalMethodDef, otherMethod._typicalMethodDef); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodSignature.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodSignature.Sorting.cs deleted file mode 100644 index 162a87907ff..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/MethodSignature.Sorting.cs +++ /dev/null @@ -1,40 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class MethodSignature - { - internal int CompareTo(MethodSignature other, TypeSystemComparer comparer) - { - int result = _parameters.Length - other._parameters.Length; - if (result != 0) - return result; - - result = (int)_flags - (int)other._flags; - if (result != 0) - return result; - - result = _genericParameterCount - other._genericParameterCount; - if (result != 0) - return result; - - // Most expensive checks last - - result = comparer.Compare(_returnType, other._returnType); - if (result != 0) - return result; - - for (int i = 0; i < _parameters.Length; i++) - { - result = comparer.Compare(_parameters[i], other._parameters[i]); - if (result != 0) - break; - } - - return result; - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/PointerType.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/PointerType.Sorting.cs deleted file mode 100644 index 30d3d297c89..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/PointerType.Sorting.cs +++ /dev/null @@ -1,17 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class PointerType - { - protected internal override int ClassCode => -2124247792; - - protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - return comparer.Compare(ParameterType, ((PointerType)other).ParameterType); - } - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/SignatureVariable.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/SignatureVariable.Sorting.cs deleted file mode 100644 index cb5cae9399c..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/SignatureVariable.Sorting.cs +++ /dev/null @@ -1,40 +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; - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types - partial class SignatureVariable - { - protected internal sealed override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) - { - return ((SignatureVariable)other).Index - Index; - } - } - - partial class SignatureTypeVariable - { - protected internal override int ClassCode - { - get - { - return 1042124696; - } - } - } - - partial class SignatureMethodVariable - { - protected internal override int ClassCode - { - get - { - return 144542889; - } - } - - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/TypeDesc.Sorting.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/TypeDesc.Sorting.cs deleted file mode 100644 index b0398f960e1..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/TypeDesc.Sorting.cs +++ /dev/null @@ -1,23 +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. - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types and members - partial class TypeDesc - { - /// - /// Gets an identifier that is the same for all instances of this - /// descendant, but different from the of any other descendant. - /// - /// - /// This is really just a number, ideally produced by "new Random().Next(int.MinValue, int.MaxValue)". - /// If two manage to conflict (which is pretty unlikely), just make a new one... - /// - protected internal abstract int ClassCode { get; } - - // Note to implementers: the type of `other` is actually the same as the type of `this`. - protected internal abstract int CompareToImpl(TypeDesc other, TypeSystemComparer comparer); - } -} diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/TypeSystemComparer.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/TypeSystemComparer.cs deleted file mode 100644 index ee71c5bf245..00000000000 --- a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Sorting/TypeSystemComparer.cs +++ /dev/null @@ -1,131 +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 Debug = System.Diagnostics.Debug; - -namespace Internal.TypeSystem -{ - // Functionality related to determinstic ordering of types and members - // - // Many places within a compiler need a way to generate deterministically ordered lists - // that may be a result of non-deterministic processes. Multi-threaded compilation is a good - // example of such source of nondeterminism. Even though the order of the results of a multi-threaded - // compilation may be non-deterministic, the output of the compiler needs to be deterministic. - // The compiler achieves that by sorting the results of the compilation. - // - // While it's easy to compare types that are in the same category (e.g. named types within an assembly - // could be compared by their names or tokens), it's difficult to have a scheme where each category would know - // how to compare itself to other categories (does "array of pointers to uint" sort before a "byref - // to an object"?). The nature of the type system potentially allows for an unlimited number of TypeDesc - // descendants. - // - // We solve this problem by only requiring each TypeDesc or MethodDesc descendant to know how - // to sort itself with respect to other instances of the same type. - // Comparisons between different categories of types are centralized to a single location that - // can provide rules to sort them. - public class TypeSystemComparer - { - public int Compare(TypeDesc x, TypeDesc y) - { - if (x == y) - { - return 0; - } - - int codeX = x.ClassCode; - int codeY = y.ClassCode; - if (codeX == codeY) - { - Debug.Assert(x.GetType() == y.GetType()); - - int result = x.CompareToImpl(y, this); - - // We did a reference equality check above so an "Equal" result is not expected - Debug.Assert(result != 0); - - return result; - } - else - { - Debug.Assert(x.GetType() != y.GetType()); - return codeX > codeY ? -1 : 1; - } - } - - internal int CompareWithinClass(T x, T y) where T : TypeDesc - { - Debug.Assert(x.GetType() == y.GetType()); - - if (x == y) - return 0; - - int result = x.CompareToImpl(y, this); - - // We did a reference equality check above so an "Equal" result is not expected - Debug.Assert(result != 0); - - return result; - } - - public int Compare(MethodDesc x, MethodDesc y) - { - if (x == y) - { - return 0; - } - - int codeX = x.ClassCode; - int codeY = y.ClassCode; - if (codeX == codeY) - { - Debug.Assert(x.GetType() == y.GetType()); - - int result = x.CompareToImpl(y, this); - - // We did a reference equality check above so an "Equal" result is not expected - Debug.Assert(result != 0); - - return result; - } - else - { - Debug.Assert(x.GetType() != y.GetType()); - return codeX > codeY ? -1 : 1; - } - } - - public int Compare(FieldDesc x, FieldDesc y) - { - if (x == y) - { - return 0; - } - - int codeX = x.ClassCode; - int codeY = y.ClassCode; - if (codeX == codeY) - { - Debug.Assert(x.GetType() == y.GetType()); - - int result = x.CompareToImpl(y, this); - - // We did a reference equality check above so an "Equal" result is not expected - Debug.Assert(result != 0); - - return result; - } - else - { - Debug.Assert(x.GetType() != y.GetType()); - return codeX > codeY ? -1 : 1; - } - } - - public int Compare(MethodSignature x, MethodSignature y) - { - return x.CompareTo(y, this); - } - } -} - diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs index 93b32fabb7c..d03ab7ad29b 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs @@ -7,15 +7,13 @@ // provided with information mapping that argument into registers and/or stack locations. using System; -using System.Collections.Generic; using System.Diagnostics; -using ILCompiler; - using Internal.JitInterface; using Internal.NativeFormat; -using Internal.Runtime; using Internal.TypeSystem; +using Internal.CorConstants; + namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs index 4d04d063c17..99a4c297edf 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs @@ -3,7 +3,9 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; + using Internal.Text; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs index b2e69a5668c..b5a96a1a64f 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using Internal.JitInterface; using Internal.Text; using Internal.TypeSystem; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs index aaa4c992c4f..bd13099db1e 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs @@ -2,14 +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 Internal.TypeSystem; - using Internal.JitInterface; using Internal.Text; -using ILCompiler.DependencyAnalysisFramework; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -45,7 +41,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun if (!relocsOnly) { - SignatureContext innerContext = builder.EmitFixup(r2rFactory, ReadyToRunFixupKind.READYTORUN_FIXUP_DelegateCtor, _methodToken.Module, _signatureContext); + SignatureContext innerContext = builder.EmitFixup(r2rFactory, ReadyToRunFixupKind.DelegateCtor, _methodToken.Module, _signatureContext); builder.EmitMethodSignature( new MethodWithToken(_targetMethod.Method, _methodToken, constrainedType: null), diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ExternalMethodImport.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ExternalMethodImport.cs index 3e40e913689..f7e7c0d798f 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ExternalMethodImport.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ExternalMethodImport.cs @@ -5,6 +5,7 @@ using Internal.JitInterface; using Internal.TypeSystem; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs index 2e43606bb79..1b1d931e05e 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs @@ -8,6 +8,7 @@ using Internal.JitInterface; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FixupConstants.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FixupConstants.cs deleted file mode 100644 index 5a9b1470734..00000000000 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FixupConstants.cs +++ /dev/null @@ -1,182 +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; - -namespace ILCompiler.DependencyAnalysis.ReadyToRun -{ - public enum CorCompileImportType : byte - { - CORCOMPILE_IMPORT_TYPE_UNKNOWN = 0, - CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD = 1, - CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH = 2, - CORCOMPILE_IMPORT_TYPE_STRING_HANDLE = 3, - CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE = 4, - CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE = 5, - CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD = 6, - } - - public enum CorCompileImportFlags : ushort - { - CORCOMPILE_IMPORT_FLAGS_UNKNOWN = 0x0000, // Apparently used for string fixups by CoreCLR R2R - CORCOMPILE_IMPORT_FLAGS_EAGER = 0x0001, // Section at module load time. - CORCOMPILE_IMPORT_FLAGS_CODE = 0x0002, // Section contains code. - CORCOMPILE_IMPORT_FLAGS_PCODE = 0x0004, // Section contains pointers to code. - } - - /// - /// Constants for method and field encoding - /// - [Flags] - public enum ReadyToRunMethodSigFlags : byte - { - READYTORUN_METHOD_SIG_None = 0x00, - READYTORUN_METHOD_SIG_UnboxingStub = 0x01, - READYTORUN_METHOD_SIG_InstantiatingStub = 0x02, - READYTORUN_METHOD_SIG_MethodInstantiation = 0x04, - READYTORUN_METHOD_SIG_SlotInsteadOfToken = 0x08, - READYTORUN_METHOD_SIG_MemberRefToken = 0x10, - READYTORUN_METHOD_SIG_Constrained = 0x20, - READYTORUN_METHOD_SIG_OwnerType = 0x40, - } - - [Flags] - public enum ReadyToRunFieldSigFlags : byte - { - READYTORUN_FIELD_SIG_IndexInsteadOfToken = 0x08, - READYTORUN_FIELD_SIG_MemberRefToken = 0x10, - READYTORUN_FIELD_SIG_OwnerType = 0x40, - } - - [Flags] - public enum ReadyToRunTypeLayoutFlags : byte - { - READYTORUN_LAYOUT_HFA = 0x01, - READYTORUN_LAYOUT_Alignment = 0x02, - READYTORUN_LAYOUT_Alignment_Native = 0x04, - READYTORUN_LAYOUT_GCLayout = 0x08, - READYTORUN_LAYOUT_GCLayout_Empty = 0x10, - } - - public enum DictionaryEntryKind - { - EmptySlot = 0, - TypeHandleSlot = 1, - MethodDescSlot = 2, - MethodEntrySlot = 3, - ConstrainedMethodEntrySlot = 4, - DispatchStubAddrSlot = 5, - FieldDescSlot = 6, - DeclaringTypeHandleSlot = 7, - } - - [Flags] - public enum ReadyToRunFixupKind - { - READYTORUN_FIXUP_Invalid = 0x00, - - READYTORUN_FIXUP_ThisObjDictionaryLookup = 0x07, - READYTORUN_FIXUP_TypeDictionaryLookup = 0x08, - READYTORUN_FIXUP_MethodDictionaryLookup = 0x09, - - READYTORUN_FIXUP_TypeHandle = 0x10, - READYTORUN_FIXUP_MethodHandle = 0x11, - READYTORUN_FIXUP_FieldHandle = 0x12, - - READYTORUN_FIXUP_MethodEntry = 0x13, /* For calling a method entry point */ - READYTORUN_FIXUP_MethodEntry_DefToken = 0x14, /* Smaller version of MethodEntry - method is def token */ - READYTORUN_FIXUP_MethodEntry_RefToken = 0x15, /* Smaller version of MethodEntry - method is ref token */ - - READYTORUN_FIXUP_VirtualEntry = 0x16, /* For invoking a virtual method */ - READYTORUN_FIXUP_VirtualEntry_DefToken = 0x17, /* Smaller version of VirtualEntry - method is def token */ - READYTORUN_FIXUP_VirtualEntry_RefToken = 0x18, /* Smaller version of VirtualEntry - method is ref token */ - READYTORUN_FIXUP_VirtualEntry_Slot = 0x19, /* Smaller version of VirtualEntry - type & slot */ - - READYTORUN_FIXUP_Helper = 0x1A, /* Helper */ - READYTORUN_FIXUP_StringHandle = 0x1B, /* String handle */ - - READYTORUN_FIXUP_NewObject = 0x1C, /* Dynamically created new helper */ - READYTORUN_FIXUP_NewArray = 0x1D, - - READYTORUN_FIXUP_IsInstanceOf = 0x1E, /* Dynamically created casting helper */ - READYTORUN_FIXUP_ChkCast = 0x1F, - - READYTORUN_FIXUP_FieldAddress = 0x20, /* For accessing a cross-module static fields */ - READYTORUN_FIXUP_CctorTrigger = 0x21, /* Static constructor trigger */ - - READYTORUN_FIXUP_StaticBaseNonGC = 0x22, /* Dynamically created static base helpers */ - READYTORUN_FIXUP_StaticBaseGC = 0x23, - READYTORUN_FIXUP_ThreadStaticBaseNonGC = 0x24, - READYTORUN_FIXUP_ThreadStaticBaseGC = 0x25, - - READYTORUN_FIXUP_FieldBaseOffset = 0x26, /* Field base offset */ - READYTORUN_FIXUP_FieldOffset = 0x27, /* Field offset */ - - READYTORUN_FIXUP_TypeDictionary = 0x28, - READYTORUN_FIXUP_MethodDictionary = 0x29, - - READYTORUN_FIXUP_Check_TypeLayout = 0x2A, /* size, alignment, HFA, reference map */ - READYTORUN_FIXUP_Check_FieldOffset = 0x2B, - - READYTORUN_FIXUP_DelegateCtor = 0x2C, /* optimized delegate ctor */ - READYTORUN_FIXUP_DeclaringTypeHandle = 0x2D, - - READYTORUN_FIXUP_IndirectPInvokeTarget = 0x2E, /* Target (indirect) of an inlined pinvoke */ - READYTORUN_FIXUP_PInvokeTarget = 0x2F, /* Target of an inlined pinvoke */ - - READYTORUN_FIXUP_ModuleOverride = 0x80, - // followed by sig-encoded UInt with assemblyref index into either the assemblyref - // table of the MSIL metadata of the master context module for the signature or - // into the extra assemblyref table in the manifest metadata R2R header table - // (used in cases inlining brings in references to assemblies not seen in the MSIL). - } - - public enum CorElementType : byte - { - ELEMENT_TYPE_END = 0, - ELEMENT_TYPE_VOID = 1, - ELEMENT_TYPE_BOOLEAN = 2, - ELEMENT_TYPE_CHAR = 3, - ELEMENT_TYPE_I1 = 4, - ELEMENT_TYPE_U1 = 5, - ELEMENT_TYPE_I2 = 6, - ELEMENT_TYPE_U2 = 7, - ELEMENT_TYPE_I4 = 8, - ELEMENT_TYPE_U4 = 9, - ELEMENT_TYPE_I8 = 10, - ELEMENT_TYPE_U8 = 11, - ELEMENT_TYPE_R4 = 12, - ELEMENT_TYPE_R8 = 13, - ELEMENT_TYPE_STRING = 14, - ELEMENT_TYPE_PTR = 15, - ELEMENT_TYPE_BYREF = 16, - ELEMENT_TYPE_VALUETYPE = 17, - ELEMENT_TYPE_CLASS = 18, - ELEMENT_TYPE_VAR = 19, - ELEMENT_TYPE_ARRAY = 20, - ELEMENT_TYPE_GENERICINST = 21, - ELEMENT_TYPE_TYPEDBYREF = 22, - ELEMENT_TYPE_I = 24, - ELEMENT_TYPE_U = 25, - ELEMENT_TYPE_FNPTR = 27, - ELEMENT_TYPE_OBJECT = 28, - ELEMENT_TYPE_SZARRAY = 29, - ELEMENT_TYPE_MVAR = 30, - - ELEMENT_TYPE_CMOD_REQD = 31, - ELEMENT_TYPE_CMOD_OPT = 32, - - ELEMENT_TYPE_CANON_ZAPSIG = 62, // zapsig encoding for [mscorlib]System.__Canon - ELEMENT_TYPE_MODULE_ZAPSIG = 63, // zapsig encoding for external module id# - - ELEMENT_TYPE_HANDLE = 64, - ELEMENT_TYPE_SENTINEL = 65, - ELEMENT_TYPE_PINNED = 69 - } - - public static class ReadyToRunRuntimeConstants - { - public const int READYTORUN_PInvokeTransitionFrameSizeInPointerUnits = 11; - } -} diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GenericLookupSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GenericLookupSignature.cs index 98452c58e0c..f23f9b4107d 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GenericLookupSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GenericLookupSignature.cs @@ -9,6 +9,7 @@ using Internal.JitInterface; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -83,15 +84,15 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun switch (_runtimeLookupKind) { case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM: - fixupToEmit = ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionaryLookup; + fixupToEmit = ReadyToRunFixupKind.TypeDictionaryLookup; break; case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM: - fixupToEmit = ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionaryLookup; + fixupToEmit = ReadyToRunFixupKind.MethodDictionaryLookup; break; case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ: - fixupToEmit = ReadyToRunFixupKind.READYTORUN_FIXUP_ThisObjDictionaryLookup; + fixupToEmit = ReadyToRunFixupKind.ThisObjDictionaryLookup; contextTypeToEmit = _methodContext.ContextType; break; diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs index b984f8fc7a6..74c2b865752 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using Internal.Runtime; using Internal.Text; using Internal.TypeSystem; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -119,7 +120,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMinorVersion)); // ReadyToRunHeader.Flags - builder.EmitInt((int)ReadyToRunFlag.READYTORUN_FLAG_NONSHARED_PINVOKE_STUBS); + builder.EmitInt((int)ReadyToRunFlag.READYTORUN_FLAG_NonSharedPInvokeStubs); // ReadyToRunHeader.NumberOfSections ObjectDataBuilder.Reservation sectionCountReservation = builder.ReserveInt(); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ImportSectionNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ImportSectionNode.cs index 051102aa783..1e5955324c4 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ImportSectionNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ImportSectionNode.cs @@ -5,6 +5,8 @@ using System; using System.Collections.Generic; +using Internal.CorConstants; + namespace ILCompiler.DependencyAnalysis.ReadyToRun { public class ImportSectionNode : EmbeddedObjectNode diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ImportThunk.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ImportThunk.cs index 66da7b51fcc..d037cac18a4 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ImportThunk.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ImportThunk.cs @@ -2,9 +2,8 @@ // 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.Text; -using Internal.TypeSystem; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/LocalMethodImport.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/LocalMethodImport.cs index 06aff552430..e3c15993acf 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/LocalMethodImport.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/LocalMethodImport.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using Internal.JitInterface; -using Internal.Text; using Internal.TypeSystem; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs index 2d48af27e96..a4c9105c19f 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs @@ -8,6 +8,8 @@ using Internal.JitInterface; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.CorConstants; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -57,18 +59,18 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun ReadyToRunFixupKind fixupKind = _fixupKind; bool optimized = false; if (!_isUnboxingStub && !_isInstantiatingStub && _method.ConstrainedType == null && - fixupKind == ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry) + fixupKind == ReadyToRunFixupKind.MethodEntry) { if (!_method.Method.OwningType.HasInstantiation && !_method.Method.OwningType.IsArray) { if (_method.Token.TokenType == CorTokenType.mdtMethodDef) { - fixupKind = ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry_DefToken; + fixupKind = ReadyToRunFixupKind.MethodEntry_DefToken; optimized = true; } else if (_method.Token.TokenType == CorTokenType.mdtMemberRef) { - fixupKind = ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry_RefToken; + fixupKind = ReadyToRunFixupKind.MethodEntry_RefToken; optimized = true; } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleToken.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleToken.cs index 30bcb4d8096..3e86bfbbc0a 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleToken.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleToken.cs @@ -8,8 +8,8 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using Internal.JitInterface; -using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.CorConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs index cab398c9c9f..6769f8df9a5 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs @@ -11,6 +11,7 @@ using System.Reflection.Metadata.Ecma335; using Internal.JitInterface; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.CorConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NewArrayFixupSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NewArrayFixupSignature.cs index c830b56afa0..bff6c6cd709 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NewArrayFixupSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NewArrayFixupSignature.cs @@ -2,11 +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 Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -30,7 +29,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun dataBuilder.AddSymbol(this); EcmaModule targetModule = _signatureContext.GetTargetModule(_arrayType); - SignatureContext innerContext = dataBuilder.EmitFixup(r2rFactory, ReadyToRunFixupKind.READYTORUN_FIXUP_NewArray, targetModule, _signatureContext); + SignatureContext innerContext = dataBuilder.EmitFixup(r2rFactory, ReadyToRunFixupKind.NewArray, targetModule, _signatureContext); dataBuilder.EmitTypeSignature(_arrayType, innerContext); return dataBuilder.ToObjectData(); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NewObjectFixupSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NewObjectFixupSignature.cs index a5728fa40b8..d72e307d7b4 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NewObjectFixupSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NewObjectFixupSignature.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 ILCompiler.DependencyAnalysisFramework; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -34,7 +32,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun dataBuilder.AddSymbol(this); EcmaModule targetModule = _signatureContext.GetTargetModule(_typeDesc); - SignatureContext innerContext = dataBuilder.EmitFixup(r2rFactory, ReadyToRunFixupKind.READYTORUN_FIXUP_NewObject, targetModule, _signatureContext); + SignatureContext innerContext = dataBuilder.EmitFixup(r2rFactory, ReadyToRunFixupKind.NewObject, targetModule, _signatureContext); dataBuilder.EmitTypeSignature(_typeDesc, innerContext); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/PrecodeMethodImport.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/PrecodeMethodImport.cs index 48ce26ceded..e9d07755e2c 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/PrecodeMethodImport.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/PrecodeMethodImport.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using Internal.JitInterface; using Internal.Text; using Internal.TypeSystem; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ReadyToRunHelperSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ReadyToRunHelperSignature.cs index 084864caace..5f037bc9150 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ReadyToRunHelperSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ReadyToRunHelperSignature.cs @@ -4,7 +4,9 @@ using System; using System.Diagnostics; + using Internal.Text; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -24,7 +26,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun { ObjectDataSignatureBuilder builder = new ObjectDataSignatureBuilder(); builder.AddSymbol(this); - builder.EmitByte((byte)ReadyToRunFixupKind.READYTORUN_FIXUP_Helper); + builder.EmitByte((byte)ReadyToRunFixupKind.Helper); builder.EmitUInt((uint)_helperID); return builder.ToObjectData(); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs index 23a916e55f0..7d5ca834380 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs @@ -3,13 +3,15 @@ using System; using System.Collections.Generic; -using Debug = System.Diagnostics.Debug; using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; + using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.JitInterface; -using System.Collections.Immutable; +using Internal.CorConstants; +using Internal.ReadyToRunConstants; + +using Debug = System.Diagnostics.Debug; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -612,7 +614,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun } else { - EmitByte((byte)(fixupKind | ReadyToRunFixupKind.READYTORUN_FIXUP_ModuleOverride)); + EmitByte((byte)(fixupKind | ReadyToRunFixupKind.ModuleOverride)); EmitUInt((uint)factory.ManifestMetadataTable.ModuleToIndex(targetModule)); return outerContext.InnerContext(targetModule); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/StringImportSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/StringImportSignature.cs index ea1e3c542d5..609f7943802 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/StringImportSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/StringImportSignature.cs @@ -2,8 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Internal.JitInterface; using Internal.Text; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -27,7 +27,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun ObjectDataSignatureBuilder dataBuilder = new ObjectDataSignatureBuilder(); dataBuilder.AddSymbol(this); - dataBuilder.EmitFixup(r2rFactory, ReadyToRunFixupKind.READYTORUN_FIXUP_StringHandle, _token.Module, _signatureContext); + dataBuilder.EmitFixup(r2rFactory, ReadyToRunFixupKind.StringHandle, _token.Module, _signatureContext); dataBuilder.EmitUInt(_token.TokenRid); return dataBuilder.ToObjectData(); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs index 79767b0f7f1..ab5a633a11a 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs @@ -8,9 +8,9 @@ using System; using System.Diagnostics; -using System.Runtime.InteropServices; using Internal.TypeSystem; +using Internal.CorConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs index dc1e19f1a80..90366c1ba16 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs @@ -7,6 +7,7 @@ using System; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index e12a1c13ee0..33a39bac9e0 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -15,6 +15,8 @@ using Internal.JitInterface; using Internal.TypeSystem; using Internal.Text; using Internal.TypeSystem.Ecma; +using Internal.CorConstants; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis { @@ -263,12 +265,12 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperMethodImport( this, DispatchImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper_Obj, + ReadyToRunHelper.DelayLoad_Helper_Obj, key.Method, useVirtualCall: false, useInstantiatingStub: true, MethodSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, + ReadyToRunFixupKind.VirtualEntry, key.Method, signatureContext: key.SignatureContext, isUnboxingStub: key.IsUnboxingStub, @@ -382,7 +384,7 @@ namespace ILCompiler.DependencyAnalysis { return new PrecodeMethodImport( this, - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, + ReadyToRunFixupKind.MethodEntry, method, CreateMethodEntrypointNodeHelper(method, isUnboxingStub, isInstantiatingStub, signatureContext), isUnboxingStub, @@ -393,7 +395,7 @@ namespace ILCompiler.DependencyAnalysis { return new LocalMethodImport( this, - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, + ReadyToRunFixupKind.MethodEntry, method, CreateMethodEntrypointNodeHelper(method, isUnboxingStub, isInstantiatingStub, signatureContext), isUnboxingStub, @@ -406,7 +408,7 @@ namespace ILCompiler.DependencyAnalysis // First time we see a given external method - emit indirection cell and the import entry return new ExternalMethodImport( this, - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, + ReadyToRunFixupKind.MethodEntry, method, isUnboxingStub, isInstantiatingStub, @@ -604,21 +606,21 @@ namespace ILCompiler.DependencyAnalysis // All ready-to-run images have a module import helper which gets patched by the runtime on image load ModuleImport = new Import(EagerImports, new ReadyToRunHelperSignature( - ILCompiler.ReadyToRunHelper.Module)); + ReadyToRunHelper.Module)); graph.AddRoot(ModuleImport, "Module import is required by the R2R format spec"); if (Target.Architecture != TargetArchitecture.X86) { Import personalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature( - ILCompiler.ReadyToRunHelper.PersonalityRoutine)); + ReadyToRunHelper.PersonalityRoutine)); PersonalityRoutine = new ImportThunk( - ILCompiler.ReadyToRunHelper.PersonalityRoutine, this, personalityRoutineImport, useVirtualCall: false); + ReadyToRunHelper.PersonalityRoutine, this, personalityRoutineImport, useVirtualCall: false); graph.AddRoot(PersonalityRoutine, "Personality routine is faster to root early rather than referencing it from each unwind info"); Import filterFuncletPersonalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature( - ILCompiler.ReadyToRunHelper.PersonalityRoutineFilterFunclet)); + ReadyToRunHelper.PersonalityRoutineFilterFunclet)); FilterFuncletPersonalityRoutine = new ImportThunk( - ILCompiler.ReadyToRunHelper.PersonalityRoutineFilterFunclet, this, filterFuncletPersonalityRoutineImport, useVirtualCall: false); + ReadyToRunHelper.PersonalityRoutineFilterFunclet, this, filterFuncletPersonalityRoutineImport, useVirtualCall: false); graph.AddRoot(FilterFuncletPersonalityRoutine, "Filter funclet personality routine is faster to root early rather than referencing it from each unwind info"); } @@ -729,19 +731,19 @@ namespace ILCompiler.DependencyAnalysis switch (helperId) { case ReadyToRunHelperId.GetGCStaticBase: - r2rHelper = ILCompiler.ReadyToRunHelper.GenericGcStaticBase; + r2rHelper = ReadyToRunHelper.GenericGcStaticBase; break; case ReadyToRunHelperId.GetNonGCStaticBase: - r2rHelper = ILCompiler.ReadyToRunHelper.GenericNonGcStaticBase; + r2rHelper = ReadyToRunHelper.GenericNonGcStaticBase; break; case ReadyToRunHelperId.GetThreadStaticBase: - r2rHelper = ILCompiler.ReadyToRunHelper.GenericGcTlsBase; + r2rHelper = ReadyToRunHelper.GenericGcTlsBase; break; case ReadyToRunHelperId.GetThreadNonGcStaticBase: - r2rHelper = ILCompiler.ReadyToRunHelper.GenericNonGcTlsBase; + r2rHelper = ReadyToRunHelper.GenericNonGcTlsBase; break; default: @@ -758,7 +760,7 @@ namespace ILCompiler.DependencyAnalysis HelperImports, GetGenericStaticHelper(helperKey.HelperId), TypeSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_Invalid, + ReadyToRunFixupKind.Invalid, (TypeDesc)helperKey.Target, InputModuleContext)); } @@ -770,7 +772,7 @@ namespace ILCompiler.DependencyAnalysis HelperImports, GetGenericStaticHelper(helperKey.HelperId), TypeSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_Invalid, + ReadyToRunFixupKind.Invalid, (TypeDesc)helperKey.Target, InputModuleContext)); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs index 1a269586f4a..c6a56f4828c 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs @@ -7,6 +7,7 @@ using ILCompiler.DependencyAnalysis.ReadyToRun; using Internal.JitInterface; using Internal.TypeSystem; +using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis { @@ -58,8 +59,8 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - new FieldFixupSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldAddress, key.Field, key.SignatureContext) + ReadyToRunHelper.DelayLoad_Helper, + new FieldFixupSignature(ReadyToRunFixupKind.FieldAddress, key.Field, key.SignatureContext) ); }); @@ -67,7 +68,7 @@ namespace ILCompiler.DependencyAnalysis { return new PrecodeHelperImport( _codegenNodeFactory, - new FieldFixupSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldOffset, key.Field, key.SignatureContext) + new FieldFixupSignature(ReadyToRunFixupKind.FieldOffset, key.Field, key.SignatureContext) ); }); @@ -75,7 +76,7 @@ namespace ILCompiler.DependencyAnalysis { return new PrecodeHelperImport( _codegenNodeFactory, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldBaseOffset, key.Type, key.SignatureContext) + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.FieldBaseOffset, key.Type, key.SignatureContext) ); }); @@ -84,11 +85,11 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperMethodImport( _codegenNodeFactory, _codegenNodeFactory.DispatchImports, - ILCompiler.ReadyToRunHelper.DelayLoad_MethodCall, + ReadyToRunHelper.DelayLoad_MethodCall, cellKey.Method, useVirtualCall: true, useInstantiatingStub: false, - _codegenNodeFactory.MethodSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, + _codegenNodeFactory.MethodSignature(ReadyToRunFixupKind.VirtualEntry, cellKey.Method, cellKey.IsUnboxingStub, isInstantiatingStub: false, cellKey.SignatureContext), cellKey.SignatureContext, @@ -108,7 +109,7 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, + ReadyToRunHelper.DelayLoad_Helper, new DelegateCtorSignature(ctorKey.Type, targetMethodNode, ctorKey.Method.Token, signatureContext)); }); @@ -117,7 +118,7 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, + ReadyToRunHelper.DelayLoad_Helper, new GenericLookupSignature( key.LookupKind, key.FixupKind, @@ -133,7 +134,7 @@ namespace ILCompiler.DependencyAnalysis return new PrecodeHelperImport( _codegenNodeFactory, _codegenNodeFactory.MethodSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_IndirectPInvokeTarget, + ReadyToRunFixupKind.IndirectPInvokeTarget, key.MethodWithToken, signatureContext: key.SignatureContext, isUnboxingStub: false, @@ -262,7 +263,7 @@ namespace ILCompiler.DependencyAnalysis } } - public ISymbolNode ReadyToRunHelper(ReadyToRunHelperId id, object target, SignatureContext signatureContext) + public ISymbolNode CreateReadyToRunHelper(ReadyToRunHelperId id, object target, SignatureContext signatureContext) { return _r2rHelpers.GetOrAdd(new ReadyToRunHelperKey(id, target, signatureContext)); } @@ -272,7 +273,7 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, + ReadyToRunHelper.DelayLoad_Helper, new NewObjectFixupSignature(type, signatureContext)); } @@ -281,7 +282,7 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, + ReadyToRunHelper.DelayLoad_Helper, new NewArrayFixupSignature(type, signatureContext)); } @@ -290,8 +291,8 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_StaticBaseGC, type, signatureContext)); + ReadyToRunHelper.DelayLoad_Helper, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.StaticBaseGC, type, signatureContext)); } private ISymbolNode CreateNonGCStaticBaseHelper(TypeDesc type, SignatureContext signatureContext) @@ -299,8 +300,8 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_StaticBaseNonGC, type, signatureContext)); + ReadyToRunHelper.DelayLoad_Helper, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.StaticBaseNonGC, type, signatureContext)); } private ISymbolNode CreateThreadGcStaticBaseHelper(TypeDesc type, SignatureContext signatureContext) @@ -308,8 +309,8 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_ThreadStaticBaseGC, type, signatureContext)); + ReadyToRunHelper.DelayLoad_Helper, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.ThreadStaticBaseGC, type, signatureContext)); } private ISymbolNode CreateThreadNonGcStaticBaseHelper(TypeDesc type, SignatureContext signatureContext) @@ -317,8 +318,8 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_ThreadStaticBaseNonGC, type, signatureContext)); + ReadyToRunHelper.DelayLoad_Helper, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.ThreadStaticBaseNonGC, type, signatureContext)); } private ISymbolNode CreateIsInstanceOfHelper(TypeDesc type, SignatureContext signatureContext) @@ -326,8 +327,8 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_IsInstanceOf, type, signatureContext)); + ReadyToRunHelper.DelayLoad_Helper, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.IsInstanceOf, type, signatureContext)); } private ISymbolNode CreateCastClassHelper(TypeDesc type, SignatureContext signatureContext) @@ -335,15 +336,15 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper_Obj, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_ChkCast, type, signatureContext)); + ReadyToRunHelper.DelayLoad_Helper_Obj, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.ChkCast, type, signatureContext)); } private ISymbolNode CreateTypeHandleHelper(TypeDesc type, SignatureContext signatureContext) { return new PrecodeHelperImport( _codegenNodeFactory, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_TypeHandle, type, signatureContext)); + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.TypeHandle, type, signatureContext)); } private ISymbolNode CreateMethodHandleHelper(MethodWithToken method, SignatureContext signatureContext) @@ -359,7 +360,7 @@ namespace ILCompiler.DependencyAnalysis return new PrecodeHelperImport( _codegenNodeFactory, _codegenNodeFactory.MethodSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodHandle, + ReadyToRunFixupKind.MethodHandle, method, isUnboxingStub: useUnboxingStub, isInstantiatingStub: useInstantiatingStub, @@ -370,7 +371,7 @@ namespace ILCompiler.DependencyAnalysis { return new PrecodeHelperImport( _codegenNodeFactory, - new FieldFixupSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldHandle, field, signatureContext)); + new FieldFixupSignature(ReadyToRunFixupKind.FieldHandle, field, signatureContext)); } private ISymbolNode CreateCctorTrigger(TypeDesc type, SignatureContext signatureContext) @@ -378,15 +379,15 @@ namespace ILCompiler.DependencyAnalysis return new DelayLoadHelperImport( _codegenNodeFactory, _codegenNodeFactory.HelperImports, - ILCompiler.ReadyToRunHelper.DelayLoad_Helper, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_CctorTrigger, type, signatureContext)); + ReadyToRunHelper.DelayLoad_Helper, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.CctorTrigger, type, signatureContext)); } private ISymbolNode CreateTypeDictionary(TypeDesc type, SignatureContext signatureContext) { return new PrecodeHelperImport( _codegenNodeFactory, - _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionary, type, signatureContext) + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.TypeDictionary, type, signatureContext) ); } @@ -395,7 +396,7 @@ namespace ILCompiler.DependencyAnalysis return new PrecodeHelperImport( _codegenNodeFactory, _codegenNodeFactory.MethodSignature( - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionary, + ReadyToRunFixupKind.MethodDictionary, method, isUnboxingStub: false, isInstantiatingStub: true, @@ -606,7 +607,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.TypeHandle: return GenericLookupTypeHelper( runtimeLookupKind, - ReadyToRunFixupKind.READYTORUN_FIXUP_TypeHandle, + ReadyToRunFixupKind.TypeHandle, helperArgument, methodContext, signatureContext); @@ -614,7 +615,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.MethodHandle: return GenericLookupMethodHelper( runtimeLookupKind, - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodHandle, + ReadyToRunFixupKind.MethodHandle, (MethodWithToken)helperArgument, methodContext, signatureContext); @@ -622,7 +623,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.MethodEntry: return GenericLookupMethodHelper( runtimeLookupKind, - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, + ReadyToRunFixupKind.MethodEntry, (MethodWithToken)helperArgument, methodContext, signatureContext); @@ -630,7 +631,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.MethodDictionary: return GenericLookupMethodHelper( runtimeLookupKind, - ReadyToRunFixupKind.READYTORUN_FIXUP_MethodHandle, + ReadyToRunFixupKind.MethodHandle, (MethodWithToken)helperArgument, methodContext, signatureContext); @@ -638,7 +639,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.TypeDictionary: return GenericLookupTypeHelper( runtimeLookupKind, - ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionary, + ReadyToRunFixupKind.TypeDictionary, (TypeDesc)helperArgument, methodContext, signatureContext); @@ -646,7 +647,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.VirtualDispatchCell: return GenericLookupMethodHelper( runtimeLookupKind, - ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, + ReadyToRunFixupKind.VirtualEntry, (MethodWithToken)helperArgument, methodContext, signatureContext); @@ -654,7 +655,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.FieldHandle: return GenericLookupFieldHelper( runtimeLookupKind, - ReadyToRunFixupKind.READYTORUN_FIXUP_FieldHandle, + ReadyToRunFixupKind.FieldHandle, (FieldDesc)helperArgument, methodContext, signatureContext); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 8f87298f97b..44e8d22b91b 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -10,11 +10,10 @@ using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; -using ILCompiler.DependencyAnalysis.ReadyToRun; - using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.TypeSystem.Interop; +using Internal.CorConstants; namespace ILCompiler { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/IBC/IBCDataModel.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/IBC/IBCDataModel.cs index 9ec70b991cb..bcda4a48037 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/IBC/IBCDataModel.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/IBC/IBCDataModel.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; -using ILCompiler.DependencyAnalysis.ReadyToRun; +using Internal.ReadyToRunConstants; namespace ILCompiler.IBC { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/IBC/IBCProfileParser.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/IBC/IBCProfileParser.cs index bbea8f7d46f..c7c7d86e7de 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/IBC/IBCProfileParser.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/IBC/IBCProfileParser.cs @@ -11,8 +11,8 @@ using System.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.CorConstants; -using ILCompiler.DependencyAnalysis.ReadyToRun; using ILCompiler.Win32Resources; namespace ILCompiler.IBC diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 5cd44bc82cc..338cf173b9f 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -30,76 +30,77 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -127,7 +128,6 @@ - @@ -204,46 +204,46 @@ - + Common\ModuleHeaders.cs - + Common\Utf8String.cs - + Common\Utf8StringBuilder.cs - + Common\ArrayBuilder.cs - + IL\HelperExtensions.cs - + JitInterface\TypeString.cs - + JitInterface\CorInfoBase.cs - + JitInterface\CorInfoImpl.cs - + JitInterface\CorInfoHelpFunc.cs - + JitInterface\CorInfoTypes.cs - + JitInterface\JitConfigProvider.cs - + JitInterface\CorInfoImpl.Intrinsics.cs - + JitInterface\MemoryHelper.cs - + JitInterface\UnboxingMethodDesc.cs diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 70d61f327e3..6b0aa4658a1 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -16,13 +16,13 @@ using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.TypeSystem.Interop; +using Internal.CorConstants; +using Internal.ReadyToRunConstants; using ILCompiler; using ILCompiler.DependencyAnalysis; using ILCompiler.DependencyAnalysis.ReadyToRun; -using ReadyToRunHelper = ILCompiler.ReadyToRunHelper; - namespace Internal.JitInterface { public class MethodWithToken @@ -225,7 +225,7 @@ namespace Internal.JitInterface if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) return false; - pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.NewHelper, type, GetSignatureContext())); + pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.NewHelper, type, GetSignatureContext())); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEWARR_1: @@ -235,7 +235,7 @@ namespace Internal.JitInterface if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) return false; - pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.NewArr1, type, GetSignatureContext())); + pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.NewArr1, type, GetSignatureContext())); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_ISINSTANCEOF: @@ -248,7 +248,7 @@ namespace Internal.JitInterface if (type.IsNullable) type = type.Instantiation[0]; - pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.IsInstanceOf, type, GetSignatureContext())); + pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.IsInstanceOf, type, GetSignatureContext())); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_CHKCAST: @@ -261,7 +261,7 @@ namespace Internal.JitInterface if (type.IsNullable) type = type.Instantiation[0]; - pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.CastClass, type, GetSignatureContext())); + pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.CastClass, type, GetSignatureContext())); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE: @@ -270,7 +270,7 @@ namespace Internal.JitInterface if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) return false; - pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.CctorTrigger, type, GetSignatureContext())); + pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.CctorTrigger, type, GetSignatureContext())); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_HANDLE: @@ -1469,14 +1469,14 @@ namespace Internal.JitInterface MethodDesc canonMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); if (canonMethod.RequiresInstMethodDescArg()) { - pResult->instParamLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper( + pResult->instParamLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.MethodDictionary, new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType), signatureContext: GetSignatureContext())); } else { - pResult->instParamLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper( + pResult->instParamLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.TypeDictionary, exactType, signatureContext: GetSignatureContext())); @@ -1699,7 +1699,7 @@ namespace Internal.JitInterface switch (pResult.handleType) { case CorInfoGenericHandleType.CORINFO_HANDLETYPE_CLASS: - symbolNode = _compilation.SymbolNodeFactory.ReadyToRunHelper( + symbolNode = _compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.TypeHandle, HandleToObject(pResolvedToken.hClass), GetSignatureContext()); @@ -1715,7 +1715,7 @@ namespace Internal.JitInterface md = _unboxingThunkFactory.GetUnboxingMethod(md); } - symbolNode = _compilation.SymbolNodeFactory.ReadyToRunHelper( + symbolNode = _compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.MethodHandle, new MethodWithToken(md, HandleToModuleToken(ref pResolvedToken), constrainedType: null), GetSignatureContext()); @@ -1723,7 +1723,7 @@ namespace Internal.JitInterface break; case CorInfoGenericHandleType.CORINFO_HANDLETYPE_FIELD: - symbolNode = _compilation.SymbolNodeFactory.ReadyToRunHelper( + symbolNode = _compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.FieldHandle, HandleToObject(pResolvedToken.hField), GetSignatureContext()); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj index 2befca9bf4e..05580f8e49c 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj @@ -27,577 +27,577 @@ - + TypeSystem\Common\ArrayMethod.Diagnostic.cs - + TypeSystem\Canon\ArrayType.Canon.cs - + TypeSystem\Canon\ByRefType.Canon.cs - + TypeSystem\Canon\CanonTypes.cs - + TypeSystem\Canon\CanonTypes.Diagnostic.cs - + TypeSystem\Canon\CanonTypes.Interop.cs - + TypeSystem\Canon\CanonTypes.Sorting.cs - + TypeSystem\Canon\FunctionPointerType.Canon.cs - + TypeSystem\Canon\GenericParameterDesc.Canon.cs - + TypeSystem\Canon\StandardCanonicalizationAlgorithm.cs - + TypeSystem\Canon\DefType.Canon.cs - + TypeSystem\Canon\InstantiatedMethod.Canon.cs - + TypeSystem\Canon\InstantiatedType.Canon.cs - + TypeSystem\Canon\MetadataType.Canon.cs - + TypeSystem\Canon\MethodDelegator.Canon.cs - + TypeSystem\Canon\MethodDesc.Canon.cs - + TypeSystem\Canon\MethodForInstantiatedType.Canon.cs - + TypeSystem\Canon\ParameterizedType.Canon.cs - + TypeSystem\Canon\PointerType.Canon.cs - + TypeSystem\Canon\SignatureVariable.Canon.cs - + TypeSystem\Canon\TypeDesc.Canon.cs - + TypeSystem\Canon\TypeSystemContext.Canon.cs - + TypeSystem\CodeGen\FieldDesc.CodeGen.cs - + TypeSystem\CodeGen\MethodDelegator.CodeGen.cs - + TypeSystem\CodeGen\MethodDesc.CodeGen.cs - + TypeSystem\CodeGen\TargetDetails.CodeGen.cs - + TypeSystem\CodeGen\TypeDesc.CodeGen.cs - + Utilities\AlignmentHelper.cs - + TypeSystem\Common\CastingHelper.cs - + TypeSystem\Common\ExplicitLayoutValidator.cs - + TypeSystem\Common\FunctionPointerType.cs - + TypeSystem\Common\IAssemblyDesc.cs - + TypeSystem\Common\Instantiation.cs - + TypeSystem\Common\ModuleDesc.cs - + TypeSystem\Common\TypeSystemEntity.cs - + TypeSystem\Common\TypeSystemException.cs - + TypeSystem\Common\ThrowHelper.cs - + TypeSystem\Common\ThrowHelper.Common.cs - + Utilities\CustomAttributeTypeNameFormatter.cs - + Utilities\CustomAttributeTypeNameParser.cs - + Utilities\DebugNameFormatter.cs - + Utilities\LockFreeReaderHashtable.cs - + TypeSystem\Common\ArrayType.cs - + TypeSystem\Common\BaseTypeRuntimeInterfacesAlgorithm.cs - + TypeSystem\Common\ByRefType.cs - + TypeSystem\Common\GenericParameterDesc.cs - + TypeSystem\Common\GenericParameterDesc.Diagnostic.cs - + TypeSystem\Common\ExceptionStringID.cs - + TypeSystem\Common\FieldForInstantiatedType.cs - + TypeSystem\Common\FieldDesc.cs - + TypeSystem\Common\FieldDesc.ToString.cs - + TypeSystem\Common\FieldDesc.FieldLayout.cs - + TypeSystem\Common\FieldLayoutAlgorithm.cs - + TypeSystem\Common\InstantiatedMethod.cs - + TypeSystem\Common\InstantiatedMethod.Diagnostic.cs - + TypeSystem\Common\InstantiatedType.cs - + TypeSystem\Common\InstantiatedType.Diagnostic.cs - + TypeSystem\Common\InstantiatedType.Interfaces.cs - + TypeSystem\Common\InstantiatedType.MethodImpls.cs - + TypeSystem\Common\LayoutInt.cs - + TypeSystem\Common\MetadataType.cs - + TypeSystem\Common\DefType.Diagnostic.cs - + TypeSystem\Common\MetadataType.Interfaces.cs - + TypeSystem\Common\MetadataType.MethodImpls.cs - + TypeSystem\Common\MetadataFieldLayoutAlgorithm.cs - + TypeSystem\Common\MetadataRuntimeInterfacesAlgorithm.cs - + TypeSystem\Common\MetadataTypeSystemContext.cs - + TypeSystem\Common\MethodForInstantiatedType.cs - + TypeSystem\Common\MethodForInstantiatedType.Diagnostic.cs - + TypeSystem\Common\ParameterizedType.cs - + TypeSystem\Common\PointerType.cs - + TypeSystem\Common\PropertySignature.cs - + TypeSystem\Common\SignatureVariable.cs - + TypeSystem\Common\TargetDetails.cs - + TypeSystem\Common\TargetDetails.ToString.cs - + TypeSystem\Common\ThreadSafeFlags.cs - + TypeSystem\Common\TypeFlags.cs - + TypeSystem\Common\TypeHashingAlgorithms.cs - + TypeSystem\Common\TypeSystemContext.cs - + TypeSystem\Common\TypeSystemHelpers.cs - + Utilities\ExceptionTypeNameFormatter.cs - + Utilities\ExceptionTypeNameFormatter.Metadata.cs - + Utilities\TypeNameFormatter.cs - + TypeSystem\Common\WellKnownType.cs - + TypeSystem\Common\VirtualMethodAlgorithm.cs - + TypeSystem\Common\MethodDelegator.cs - + TypeSystem\Common\MethodDelegator.Diagnostic.cs - + TypeSystem\Common\MethodDesc.cs - + TypeSystem\Common\MethodDesc.Diagnostic.cs - + TypeSystem\Common\MethodDesc.ToString.cs - + TypeSystem\Common\StandardVirtualMethodAlgorithm.cs - + TypeSystem\Common\TypeDesc.cs - + TypeSystem\Common\TypeDesc.ToString.cs - + TypeSystem\Common\TypeDesc.Interfaces.cs - + TypeSystem\Common\DefType.cs - + TypeSystem\Common\DefType.FieldLayout.cs - + TypeSystem\Common\RuntimeInterfacesAlgorithm.cs - + Ecma\CustomAttributeTypeProvider.cs - + Ecma\EcmaAssembly.cs - + Ecma\EcmaAssembly.Symbols.cs - + Ecma\EcmaField.Sorting.cs - + Ecma\EcmaField.CodeGen.cs - + Ecma\EcmaField.Serialization.cs - + Ecma\EcmaGenericParameter.Sorting.cs - + Ecma\EcmaMethod.Sorting.cs - + Ecma\EcmaModule.Sorting.cs - + Ecma\EcmaType.Serialization.cs - + Ecma\EcmaType.Sorting.cs - + Ecma\PrimitiveTypeProvider.cs - + Ecma\EcmaModule.Symbols.cs - + Ecma\SymbolReader\PdbSymbolReader.cs - + Ecma\SymbolReader\PortablePdbSymbolReader.cs - + Ecma\SymbolReader\UnmanagedPdbSymbolReader.cs - + Ecma\EcmaField.cs - + Ecma\EcmaGenericParameter.cs - + Ecma\EcmaGenericParameter.Diagnostic.cs - + Ecma\EcmaMethod.cs - + Ecma\EcmaMethod.cs - + Ecma\EcmaModule.cs - + Ecma\EcmaSignatureParser.cs - + Ecma\EcmaType.cs - + Ecma\EcmaType.Diagnostic.cs - + Ecma\EcmaType.MethodImpls.cs - + Ecma\EcmaType.Interfaces.cs - + Ecma\MetadataExtensions.cs - + Ecma\IMetadataStringDecoderProvider.cs - + Ecma\CachingMetadataStringDecoder.cs - + IL\EcmaMethodIL.cs - + IL\EcmaMethodIL.Symbols.cs - + IL\MethodIL.cs - + IL\MethodIL.Symbols.cs - + IL\MethodILDebugView.cs - + IL\ILDisassembler.cs - + IL\InstantiatedMethodIL.cs - + IL\ILStackHelper.cs - + IL\ILOpcode.cs - + IL\ILOpcodeHelper.cs - + IL\Stubs\ILEmitter.cs - + IL\Stubs\PInvokeTargetNativeMethod.cs - + IL\Stubs\PInvokeTargetNativeMethod.Diagnostic.cs - + IL\Stubs\PInvokeTargetNativeMethod.Mangling.cs - + IL\Stubs\PInvokeTargetNativeMethod.Sorting.cs - + TypeSystem\CodeGen\FieldDesc.Serialization.cs - + TypeSystem\CodeGen\TypeDesc.Serialization.cs - + TypeSystem\Sorting\FieldDesc.Sorting.cs - + TypeSystem\Sorting\FieldForInstantiatedType.Sorting.cs - + TypeSystem\Sorting\InstantiatedMethod.Sorting.cs - + TypeSystem\Sorting\MethodDesc.Sorting.cs - + TypeSystem\Sorting\MethodForInstantiatedType.Sorting.cs - + TypeSystem\Interop\FieldDesc.Interop.cs - + TypeSystem\Interop\InstantiatedType.Interop.cs - + TypeSystem\Interop\MetadataType.Interop.cs - + TypeSystem\Interop\MethodDelegator.Interop.cs - + TypeSystem\Interop\MethodDesc.Interop.cs - + TypeSystem\Interop\MarshalAsDescriptor.cs - + TypeSystem\Mangling\IPrefixMangledMethod.cs - + TypeSystem\Mangling\IPrefixMangledType.cs - + TypeSystem\Mangling\IPrefixMangledSignature.cs - + Utilities\ArrayBuilder.cs - + TypeSystem\Common\LocalVariableDefinition.cs - + TypeSystem\RuntimeDetermined\ArrayType.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\ByRefType.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\FieldDesc.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\FunctionPointerType.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\MethodDesc.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\PointerType.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.cs - + TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.cs - + TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.Sorting.cs - + TypeSystem\RuntimeDetermined\RuntimeDeterminedCanonicalizationAlgorithm.cs - + TypeSystem\RuntimeDetermined\RuntimeDeterminedFieldLayoutAlgorithm.cs - + TypeSystem\RuntimeDetermined\DefType.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\GenericParameterDesc.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\ParameterizedType.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\RuntimeDeterminedType.cs - + TypeSystem\RuntimeDetermined\RuntimeDeterminedType.Diagnostic.cs - + TypeSystem\RuntimeDetermined\RuntimeDeterminedType.Sorting.cs - + TypeSystem\RuntimeDetermined\RuntimeDeterminedTypeUtilities.cs - + TypeSystem\RuntimeDetermined\SignatureVariable.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\TypeDesc.RuntimeDetermined.cs - + TypeSystem\RuntimeDetermined\TypeSystemContext.RuntimeDetermined.cs - + Common\System\FormattingHelpers.cs - + TypeSystem\Sorting\ArrayType.Sorting.cs - + TypeSystem\Sorting\ByRefType.Sorting.cs - + TypeSystem\Sorting\FunctionPointerType.Sorting.cs - + TypeSystem\Sorting\InstantiatedType.Sorting.cs - + TypeSystem\Sorting\MethodSignature.Sorting.cs - + TypeSystem\Sorting\PointerType.Sorting.cs - + TypeSystem\Sorting\SignatureVariable.Sorting.cs - + TypeSystem\Sorting\TypeDesc.Sorting.cs - + TypeSystem\Sorting\TypeSystemComparer.cs diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj b/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj index c8a30202d75..d5a13cb13cf 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj +++ b/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/src/coreclr/src/tools/r2rdump/R2RConstants.cs b/src/coreclr/src/tools/r2rdump/R2RConstants.cs deleted file mode 100644 index b149e1d8016..00000000000 --- a/src/coreclr/src/tools/r2rdump/R2RConstants.cs +++ /dev/null @@ -1,373 +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; - -namespace R2RDump -{ - /// - /// based on src/inc/corcompile.h CorCompileImportType - /// - public enum CorCompileImportType - { - CORCOMPILE_IMPORT_TYPE_UNKNOWN = 0, - CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD = 1, - CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH = 2, - CORCOMPILE_IMPORT_TYPE_STRING_HANDLE = 3, - CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE = 4, - CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE = 5, - CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD = 6, - }; - - /// - /// based on src/inc/corcompile.h CorCompileImportFlags - /// - public enum CorCompileImportFlags - { - CORCOMPILE_IMPORT_FLAGS_UNKNOWN = 0x0000, - CORCOMPILE_IMPORT_FLAGS_EAGER = 0x0001, // Section at module load time. - CORCOMPILE_IMPORT_FLAGS_CODE = 0x0002, // Section contains code. - CORCOMPILE_IMPORT_FLAGS_PCODE = 0x0004, // Section contains pointers to code. - }; - - /// - /// based on src/inc/corcompile.h CorCompileImportFlags - /// - public enum CORCOMPILE_FIXUP_BLOB_KIND - { - ENCODE_MODULE_OVERRIDE = 0x80, /* When the high bit is set, override of the module immediately follows */ - } - - /// - /// Constants for method and field encoding - /// - [Flags] - public enum ReadyToRunMethodSigFlags : byte - { - READYTORUN_METHOD_SIG_None = 0x00, - READYTORUN_METHOD_SIG_UnboxingStub = 0x01, - READYTORUN_METHOD_SIG_InstantiatingStub = 0x02, - READYTORUN_METHOD_SIG_MethodInstantiation = 0x04, - READYTORUN_METHOD_SIG_SlotInsteadOfToken = 0x08, - READYTORUN_METHOD_SIG_MemberRefToken = 0x10, - READYTORUN_METHOD_SIG_Constrained = 0x20, - READYTORUN_METHOD_SIG_OwnerType = 0x40, - } - - [Flags] - public enum ReadyToRunFieldSigFlags : byte - { - READYTORUN_FIELD_SIG_IndexInsteadOfToken = 0x08, - READYTORUN_FIELD_SIG_MemberRefToken = 0x10, - READYTORUN_FIELD_SIG_OwnerType = 0x40, - } - - [Flags] - public enum ReadyToRunTypeLayoutFlags : byte - { - READYTORUN_LAYOUT_HFA = 0x01, - READYTORUN_LAYOUT_Alignment = 0x02, - READYTORUN_LAYOUT_Alignment_Native = 0x04, - READYTORUN_LAYOUT_GCLayout = 0x08, - READYTORUN_LAYOUT_GCLayout_Empty = 0x10, - } - - public enum ReadyToRunFixupKind - { - READYTORUN_FIXUP_ThisObjDictionaryLookup = 0x07, - READYTORUN_FIXUP_TypeDictionaryLookup = 0x08, - READYTORUN_FIXUP_MethodDictionaryLookup = 0x09, - - READYTORUN_FIXUP_TypeHandle = 0x10, - READYTORUN_FIXUP_MethodHandle = 0x11, - READYTORUN_FIXUP_FieldHandle = 0x12, - - READYTORUN_FIXUP_MethodEntry = 0x13, /* For calling a method entry point */ - READYTORUN_FIXUP_MethodEntry_DefToken = 0x14, /* Smaller version of MethodEntry - method is def token */ - READYTORUN_FIXUP_MethodEntry_RefToken = 0x15, /* Smaller version of MethodEntry - method is ref token */ - - READYTORUN_FIXUP_VirtualEntry = 0x16, /* For invoking a virtual method */ - READYTORUN_FIXUP_VirtualEntry_DefToken = 0x17, /* Smaller version of VirtualEntry - method is def token */ - READYTORUN_FIXUP_VirtualEntry_RefToken = 0x18, /* Smaller version of VirtualEntry - method is ref token */ - READYTORUN_FIXUP_VirtualEntry_Slot = 0x19, /* Smaller version of VirtualEntry - type & slot */ - - READYTORUN_FIXUP_Helper = 0x1A, /* Helper */ - READYTORUN_FIXUP_StringHandle = 0x1B, /* String handle */ - - READYTORUN_FIXUP_NewObject = 0x1C, /* Dynamically created new helper */ - READYTORUN_FIXUP_NewArray = 0x1D, - - READYTORUN_FIXUP_IsInstanceOf = 0x1E, /* Dynamically created casting helper */ - READYTORUN_FIXUP_ChkCast = 0x1F, - - READYTORUN_FIXUP_FieldAddress = 0x20, /* For accessing a cross-module static fields */ - READYTORUN_FIXUP_CctorTrigger = 0x21, /* Static constructor trigger */ - - READYTORUN_FIXUP_StaticBaseNonGC = 0x22, /* Dynamically created static base helpers */ - READYTORUN_FIXUP_StaticBaseGC = 0x23, - READYTORUN_FIXUP_ThreadStaticBaseNonGC = 0x24, - READYTORUN_FIXUP_ThreadStaticBaseGC = 0x25, - - READYTORUN_FIXUP_FieldBaseOffset = 0x26, /* Field base offset */ - READYTORUN_FIXUP_FieldOffset = 0x27, /* Field offset */ - - READYTORUN_FIXUP_TypeDictionary = 0x28, - READYTORUN_FIXUP_MethodDictionary = 0x29, - - READYTORUN_FIXUP_Check_TypeLayout = 0x2A, /* size, alignment, HFA, reference map */ - READYTORUN_FIXUP_Check_FieldOffset = 0x2B, - - READYTORUN_FIXUP_DelegateCtor = 0x2C, /* optimized delegate ctor */ - READYTORUN_FIXUP_DeclaringTypeHandle = 0x2D, - - READYTORUN_FIXUP_IndirectPInvokeTarget = 0x2E, /* Target (indirect) of an inlined pinvoke */ - READYTORUN_FIXUP_PInvokeTarget = 0x2F, /* Target of an inlined pinvoke */ - } - - // - // Intrinsics and helpers - // - - [Flags] - public enum ReadyToRunHelper - { - READYTORUN_HELPER_Invalid = 0x00, - - // Not a real helper - handle to current module passed to delay load helpers. - READYTORUN_HELPER_Module = 0x01, - READYTORUN_HELPER_GSCookie = 0x02, - - // - // Delay load helpers - // - - // All delay load helpers use custom calling convention: - // - scratch register - address of indirection cell. 0 = address is inferred from callsite. - // - stack - section index, module handle - READYTORUN_HELPER_DelayLoad_MethodCall = 0x08, - - READYTORUN_HELPER_DelayLoad_Helper = 0x10, - READYTORUN_HELPER_DelayLoad_Helper_Obj = 0x11, - READYTORUN_HELPER_DelayLoad_Helper_ObjObj = 0x12, - - // JIT helpers - - // Exception handling helpers - READYTORUN_HELPER_Throw = 0x20, - READYTORUN_HELPER_Rethrow = 0x21, - READYTORUN_HELPER_Overflow = 0x22, - READYTORUN_HELPER_RngChkFail = 0x23, - READYTORUN_HELPER_FailFast = 0x24, - READYTORUN_HELPER_ThrowNullRef = 0x25, - READYTORUN_HELPER_ThrowDivZero = 0x26, - - // Write barriers - READYTORUN_HELPER_WriteBarrier = 0x30, - READYTORUN_HELPER_CheckedWriteBarrier = 0x31, - READYTORUN_HELPER_ByRefWriteBarrier = 0x32, - - // Array helpers - READYTORUN_HELPER_Stelem_Ref = 0x38, - READYTORUN_HELPER_Ldelema_Ref = 0x39, - - READYTORUN_HELPER_MemSet = 0x40, - READYTORUN_HELPER_MemCpy = 0x41, - - // PInvoke helpers - READYTORUN_HELPER_PInvokeBegin = 0x42, - READYTORUN_HELPER_PInvokeEnd = 0x43, - READYTORUN_HELPER_GCPoll = 0x44, - - // Get string handle lazily - READYTORUN_HELPER_GetString = 0x50, - - // Used by /Tuning for Profile optimizations - READYTORUN_HELPER_LogMethodEnter = 0x51, - - // Reflection helpers - READYTORUN_HELPER_GetRuntimeTypeHandle = 0x54, - READYTORUN_HELPER_GetRuntimeMethodHandle = 0x55, - READYTORUN_HELPER_GetRuntimeFieldHandle = 0x56, - - READYTORUN_HELPER_Box = 0x58, - READYTORUN_HELPER_Box_Nullable = 0x59, - READYTORUN_HELPER_Unbox = 0x5A, - READYTORUN_HELPER_Unbox_Nullable = 0x5B, - READYTORUN_HELPER_NewMultiDimArr = 0x5C, - READYTORUN_HELPER_NewMultiDimArr_NonVarArg = 0x5D, - - // Helpers used with generic handle lookup cases - READYTORUN_HELPER_NewObject = 0x60, - READYTORUN_HELPER_NewArray = 0x61, - READYTORUN_HELPER_CheckCastAny = 0x62, - READYTORUN_HELPER_CheckInstanceAny = 0x63, - READYTORUN_HELPER_GenericGcStaticBase = 0x64, - READYTORUN_HELPER_GenericNonGcStaticBase = 0x65, - READYTORUN_HELPER_GenericGcTlsBase = 0x66, - READYTORUN_HELPER_GenericNonGcTlsBase = 0x67, - READYTORUN_HELPER_VirtualFuncPtr = 0x68, - - // Long mul/div/shift ops - READYTORUN_HELPER_LMul = 0xC0, - READYTORUN_HELPER_LMulOfv = 0xC1, - READYTORUN_HELPER_ULMulOvf = 0xC2, - READYTORUN_HELPER_LDiv = 0xC3, - READYTORUN_HELPER_LMod = 0xC4, - READYTORUN_HELPER_ULDiv = 0xC5, - READYTORUN_HELPER_ULMod = 0xC6, - READYTORUN_HELPER_LLsh = 0xC7, - READYTORUN_HELPER_LRsh = 0xC8, - READYTORUN_HELPER_LRsz = 0xC9, - READYTORUN_HELPER_Lng2Dbl = 0xCA, - READYTORUN_HELPER_ULng2Dbl = 0xCB, - - // 32-bit division helpers - READYTORUN_HELPER_Div = 0xCC, - READYTORUN_HELPER_Mod = 0xCD, - READYTORUN_HELPER_UDiv = 0xCE, - READYTORUN_HELPER_UMod = 0xCF, - - // Floating point conversions - READYTORUN_HELPER_Dbl2Int = 0xD0, - READYTORUN_HELPER_Dbl2IntOvf = 0xD1, - READYTORUN_HELPER_Dbl2Lng = 0xD2, - READYTORUN_HELPER_Dbl2LngOvf = 0xD3, - READYTORUN_HELPER_Dbl2UInt = 0xD4, - READYTORUN_HELPER_Dbl2UIntOvf = 0xD5, - READYTORUN_HELPER_Dbl2ULng = 0xD6, - READYTORUN_HELPER_Dbl2ULngOvf = 0xD7, - - // Floating point ops - READYTORUN_HELPER_DblRem = 0xE0, - READYTORUN_HELPER_FltRem = 0xE1, - READYTORUN_HELPER_DblRound = 0xE2, - READYTORUN_HELPER_FltRound = 0xE3, - - // Personality rountines - READYTORUN_HELPER_PersonalityRoutine = 0xF0, - READYTORUN_HELPER_PersonalityRoutineFilterFunclet = 0xF1, - - // Synchronized methods - READYTORUN_HELPER_MonitorEnter = 0xF8, - READYTORUN_HELPER_MonitorExit = 0xF9, - - // - // Deprecated/legacy - // - - // JIT32 x86-specific write barriers - READYTORUN_HELPER_WriteBarrier_EAX = 0x100, - READYTORUN_HELPER_WriteBarrier_EBX = 0x101, - READYTORUN_HELPER_WriteBarrier_ECX = 0x102, - READYTORUN_HELPER_WriteBarrier_ESI = 0x103, - READYTORUN_HELPER_WriteBarrier_EDI = 0x104, - READYTORUN_HELPER_WriteBarrier_EBP = 0x105, - READYTORUN_HELPER_CheckedWriteBarrier_EAX = 0x106, - READYTORUN_HELPER_CheckedWriteBarrier_EBX = 0x107, - READYTORUN_HELPER_CheckedWriteBarrier_ECX = 0x108, - READYTORUN_HELPER_CheckedWriteBarrier_ESI = 0x109, - READYTORUN_HELPER_CheckedWriteBarrier_EDI = 0x10A, - READYTORUN_HELPER_CheckedWriteBarrier_EBP = 0x10B, - - // JIT32 x86-specific exception handling - READYTORUN_HELPER_EndCatch = 0x110, - - READYTORUN_HELPER_StackProbe = 0x111, - } - - public enum CorElementType : byte - { - Invalid = 0, - ELEMENT_TYPE_VOID = 1, - ELEMENT_TYPE_BOOLEAN = 2, - ELEMENT_TYPE_CHAR = 3, - ELEMENT_TYPE_I1 = 4, - ELEMENT_TYPE_U1 = 5, - ELEMENT_TYPE_I2 = 6, - ELEMENT_TYPE_U2 = 7, - ELEMENT_TYPE_I4 = 8, - ELEMENT_TYPE_U4 = 9, - ELEMENT_TYPE_I8 = 10, - ELEMENT_TYPE_U8 = 11, - ELEMENT_TYPE_R4 = 12, - ELEMENT_TYPE_R8 = 13, - ELEMENT_TYPE_STRING = 14, - ELEMENT_TYPE_PTR = 15, - ELEMENT_TYPE_BYREF = 16, - ELEMENT_TYPE_VALUETYPE = 17, - ELEMENT_TYPE_CLASS = 18, - ELEMENT_TYPE_VAR = 19, - ELEMENT_TYPE_ARRAY = 20, - ELEMENT_TYPE_GENERICINST = 21, - ELEMENT_TYPE_TYPEDBYREF = 22, - ELEMENT_TYPE_I = 24, - ELEMENT_TYPE_U = 25, - ELEMENT_TYPE_FNPTR = 27, - ELEMENT_TYPE_OBJECT = 28, - ELEMENT_TYPE_SZARRAY = 29, - ELEMENT_TYPE_MVAR = 30, - ELEMENT_TYPE_CMOD_REQD = 31, - ELEMENT_TYPE_CMOD_OPT = 32, - - // ZapSig encoding for ELEMENT_TYPE_VAR and ELEMENT_TYPE_MVAR. It is always followed - // by the RID of a GenericParam token, encoded as a compressed integer. - ELEMENT_TYPE_VAR_ZAPSIG = 0x3b, - - // ZapSig encoding for an array MethodTable to allow it to remain such after decoding - // (rather than being transformed into the TypeHandle representing that array) - // - // The element is always followed by ELEMENT_TYPE_SZARRAY or ELEMENT_TYPE_ARRAY - ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG = 0x3c, - - // ZapSig encoding for native value types in IL stubs. IL stub signatures may contain - // ELEMENT_TYPE_INTERNAL followed by ParamTypeDesc with ELEMENT_TYPE_VALUETYPE element - // type. It acts like a modifier to the underlying structure making it look like its - // unmanaged view (size determined by unmanaged layout, blittable, no GC pointers). - // - // ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG is used when encoding such types to NGEN images. - // The signature looks like this: ET_NATIVE_VALUETYPE_ZAPSIG ET_VALUETYPE . - // See code:ZapSig.GetSignatureForTypeHandle and code:SigPointer.GetTypeHandleThrowing - // where the encoding/decoding takes place. - ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG = 0x3d, - - ELEMENT_TYPE_CANON_ZAPSIG = 0x3e, // zapsig encoding for [mscorlib]System.__Canon - ELEMENT_TYPE_MODULE_ZAPSIG = 0x3f, // zapsig encoding for external module id# - - ELEMENT_TYPE_HANDLE = 64, - ELEMENT_TYPE_SENTINEL = 65, - ELEMENT_TYPE_PINNED = 69, - } - - public enum CorTokenType - { - mdtModule = 0x00000000, - mdtTypeRef = 0x01000000, - mdtTypeDef = 0x02000000, - mdtFieldDef = 0x04000000, - mdtMethodDef = 0x06000000, - mdtParamDef = 0x08000000, - mdtInterfaceImpl = 0x09000000, - mdtMemberRef = 0x0a000000, - mdtCustomAttribute = 0x0c000000, - mdtPermission = 0x0e000000, - mdtSignature = 0x11000000, - mdtEvent = 0x14000000, - mdtProperty = 0x17000000, - mdtMethodImpl = 0x19000000, - mdtModuleRef = 0x1a000000, - mdtTypeSpec = 0x1b000000, - mdtAssembly = 0x20000000, - mdtAssemblyRef = 0x23000000, - mdtFile = 0x26000000, - mdtExportedType = 0x27000000, - mdtManifestResource = 0x28000000, - mdtGenericParam = 0x2a000000, - mdtMethodSpec = 0x2b000000, - mdtGenericParamConstraint = 0x2c000000, - - mdtString = 0x70000000, - mdtName = 0x71000000, - mdtBaseType = 0x72000000, - } -} diff --git a/src/coreclr/src/tools/r2rdump/R2RDump.csproj b/src/coreclr/src/tools/r2rdump/R2RDump.csproj index f165c423406..28645dcc716 100644 --- a/src/coreclr/src/tools/r2rdump/R2RDump.csproj +++ b/src/coreclr/src/tools/r2rdump/R2RDump.csproj @@ -14,6 +14,11 @@ $(BinDir) + + + + + 1.0.1-prerelease-00005 diff --git a/src/coreclr/src/tools/r2rdump/R2RHeader.cs b/src/coreclr/src/tools/r2rdump/R2RHeader.cs index f237e379889..1c39e297d90 100644 --- a/src/coreclr/src/tools/r2rdump/R2RHeader.cs +++ b/src/coreclr/src/tools/r2rdump/R2RHeader.cs @@ -6,6 +6,8 @@ using System; using System.Collections.Generic; using System.Text; +using Internal.ReadyToRunConstants; + namespace R2RDump { /// @@ -13,15 +15,6 @@ namespace R2RDump /// public class R2RHeader { - [Flags] - public enum ReadyToRunFlag - { - READYTORUN_FLAG_PLATFORM_NEUTRAL_SOURCE = 0x00000001, // Set if the original IL assembly was platform-neutral - READYTORUN_FLAG_SKIP_TYPE_VALIDATION = 0x00000002, // Set of methods with native code was determined using profile data - READYTORUN_FLAG_PARTIAL = 0x00000004, - READYTORUN_FLAG_CROSSGEN2_IMAGE = 0x00000008 // Set if image was compiled using crossgen2 - } - /// /// The expected signature of a ReadyToRun header /// diff --git a/src/coreclr/src/tools/r2rdump/R2RImportSection.cs b/src/coreclr/src/tools/r2rdump/R2RImportSection.cs index ec1d4185fa6..65f266e2311 100644 --- a/src/coreclr/src/tools/r2rdump/R2RImportSection.cs +++ b/src/coreclr/src/tools/r2rdump/R2RImportSection.cs @@ -6,9 +6,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Reflection.PortableExecutable; -using System.Text; using System.Xml.Serialization; +using Internal.CorConstants; + namespace R2RDump { /// diff --git a/src/coreclr/src/tools/r2rdump/R2RReader.cs b/src/coreclr/src/tools/r2rdump/R2RReader.cs index 4877cdf8bb1..c9348829fce 100644 --- a/src/coreclr/src/tools/r2rdump/R2RReader.cs +++ b/src/coreclr/src/tools/r2rdump/R2RReader.cs @@ -12,6 +12,9 @@ using System.Runtime.InteropServices; using System.Text; using System.Xml.Serialization; +using Internal.CorConstants; +using Internal.ReadyToRunConstants; + namespace R2RDump { /// diff --git a/src/coreclr/src/tools/r2rdump/R2RSignature.cs b/src/coreclr/src/tools/r2rdump/R2RSignature.cs index 264e1050402..b08e50750b3 100644 --- a/src/coreclr/src/tools/r2rdump/R2RSignature.cs +++ b/src/coreclr/src/tools/r2rdump/R2RSignature.cs @@ -3,14 +3,12 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; using System.Text; -using System.Xml.Serialization; + +using Internal.CorConstants; +using Internal.ReadyToRunConstants; namespace R2RDump { @@ -632,13 +630,13 @@ namespace R2RDump { uint fixupType = ReadByte(); EmitInlineSignatureBinaryBytes(builder, 1); - bool moduleOverride = (fixupType & (byte)CORCOMPILE_FIXUP_BLOB_KIND.ENCODE_MODULE_OVERRIDE) != 0; + bool moduleOverride = (fixupType & (byte)ReadyToRunFixupKind.ModuleOverride) != 0; SignatureDecoder moduleDecoder = this; // Check first byte for a module override being encoded if (moduleOverride) { - fixupType &= ~(uint)CORCOMPILE_FIXUP_BLOB_KIND.ENCODE_MODULE_OVERRIDE; + fixupType &= ~(uint)ReadyToRunFixupKind.ModuleOverride; int moduleIndex = (int)ReadUIntAndEmitInlineSignatureBinary(builder); EcmaMetadataReader refAsmEcmaReader = _contextReader.OpenReferenceAssembly(moduleIndex); moduleDecoder = new SignatureDecoder(_options, refAsmEcmaReader, _image, _offset, _contextReader); @@ -657,75 +655,75 @@ namespace R2RDump { switch (fixupType) { - case ReadyToRunFixupKind.READYTORUN_FIXUP_ThisObjDictionaryLookup: + case ReadyToRunFixupKind.ThisObjDictionaryLookup: builder.Append("THISOBJ_DICTIONARY_LOOKUP @ "); ParseType(builder); builder.Append(": "); ParseSignature(builder); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionaryLookup: + case ReadyToRunFixupKind.TypeDictionaryLookup: builder.Append("TYPE_DICTIONARY_LOOKUP: "); ParseSignature(builder); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionaryLookup: + case ReadyToRunFixupKind.MethodDictionaryLookup: builder.Append("METHOD_DICTIONARY_LOOKUP: "); ParseSignature(builder); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_TypeHandle: + case ReadyToRunFixupKind.TypeHandle: ParseType(builder); builder.Append(" (TYPE_HANDLE)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodHandle: + case ReadyToRunFixupKind.MethodHandle: ParseMethod(builder); builder.Append(" (METHOD_HANDLE)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_FieldHandle: + case ReadyToRunFixupKind.FieldHandle: ParseField(builder); builder.Append(" (FIELD_HANDLE)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry: + case ReadyToRunFixupKind.MethodEntry: ParseMethod(builder); builder.Append(" (METHOD_ENTRY)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry_DefToken: + case ReadyToRunFixupKind.MethodEntry_DefToken: ParseMethodDefToken(builder, owningTypeOverride: null); builder.Append(" (METHOD_ENTRY"); builder.Append(_options.Naked ? ")" : "_DEF_TOKEN)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry_RefToken: + case ReadyToRunFixupKind.MethodEntry_RefToken: ParseMethodRefToken(builder, owningTypeOverride: null); builder.Append(" (METHOD_ENTRY"); builder.Append(_options.Naked ? ")" : "_REF_TOKEN)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry: + case ReadyToRunFixupKind.VirtualEntry: ParseMethod(builder); builder.Append(" (VIRTUAL_ENTRY)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry_DefToken: + case ReadyToRunFixupKind.VirtualEntry_DefToken: ParseMethodDefToken(builder, owningTypeOverride: null); builder.Append(" (VIRTUAL_ENTRY"); builder.Append(_options.Naked ? ")" : "_DEF_TOKEN)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry_RefToken: + case ReadyToRunFixupKind.VirtualEntry_RefToken: ParseMethodRefToken(builder, owningTypeOverride: null); builder.Append(" (VIRTUAL_ENTRY"); builder.Append(_options.Naked ? ")" : "_REF_TOKEN)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry_Slot: + case ReadyToRunFixupKind.VirtualEntry_Slot: { uint slot = ReadUIntAndEmitInlineSignatureBinary(builder); ParseType(builder); @@ -735,123 +733,123 @@ namespace R2RDump break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_Helper: + case ReadyToRunFixupKind.Helper: ParseHelper(builder); builder.Append(" (HELPER)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_StringHandle: + case ReadyToRunFixupKind.StringHandle: ParseStringHandle(builder); builder.Append(" (STRING_HANDLE)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_NewObject: + case ReadyToRunFixupKind.NewObject: ParseType(builder); builder.Append(" (NEW_OBJECT)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_NewArray: + case ReadyToRunFixupKind.NewArray: ParseType(builder); builder.Append(" (NEW_ARRAY)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_IsInstanceOf: + case ReadyToRunFixupKind.IsInstanceOf: ParseType(builder); builder.Append(" (IS_INSTANCE_OF)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_ChkCast: + case ReadyToRunFixupKind.ChkCast: ParseType(builder); builder.Append(" (CHK_CAST)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_FieldAddress: + case ReadyToRunFixupKind.FieldAddress: ParseField(builder); builder.Append(" (FIELD_ADDRESS)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_CctorTrigger: + case ReadyToRunFixupKind.CctorTrigger: ParseType(builder); builder.Append(" (CCTOR_TRIGGER)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_StaticBaseNonGC: + case ReadyToRunFixupKind.StaticBaseNonGC: ParseType(builder); builder.Append(" (STATIC_BASE_NON_GC)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_StaticBaseGC: + case ReadyToRunFixupKind.StaticBaseGC: ParseType(builder); builder.Append(" (STATIC_BASE_GC)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_ThreadStaticBaseNonGC: + case ReadyToRunFixupKind.ThreadStaticBaseNonGC: ParseType(builder); builder.Append(" (THREAD_STATIC_BASE_NON_GC)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_ThreadStaticBaseGC: + case ReadyToRunFixupKind.ThreadStaticBaseGC: ParseType(builder); builder.Append(" (THREAD_STATIC_BASE_GC)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_FieldBaseOffset: + case ReadyToRunFixupKind.FieldBaseOffset: ParseType(builder); builder.Append(" (FIELD_BASE_OFFSET)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_FieldOffset: + case ReadyToRunFixupKind.FieldOffset: ParseField(builder); builder.Append(" (FIELD_OFFSET)"); // TODO break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionary: + case ReadyToRunFixupKind.TypeDictionary: ParseType(builder); builder.Append(" (TYPE_DICTIONARY)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionary: + case ReadyToRunFixupKind.MethodDictionary: ParseMethod(builder); builder.Append(" (METHOD_DICTIONARY)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_Check_TypeLayout: + case ReadyToRunFixupKind.Check_TypeLayout: ParseType(builder); builder.Append(" (CHECK_TYPE_LAYOUT)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_Check_FieldOffset: + case ReadyToRunFixupKind.Check_FieldOffset: builder.Append("CHECK_FIELD_OFFSET"); // TODO break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_DelegateCtor: + case ReadyToRunFixupKind.DelegateCtor: ParseMethod(builder); builder.Append(" => "); ParseType(builder); builder.Append(" (DELEGATE_CTOR)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_DeclaringTypeHandle: + case ReadyToRunFixupKind.DeclaringTypeHandle: ParseType(builder); builder.Append(" (DECLARING_TYPE_HANDLE)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_IndirectPInvokeTarget: + case ReadyToRunFixupKind.IndirectPInvokeTarget: ParseMethod(builder); builder.Append(" (INDIRECT_PINVOKE_TARGET)"); break; - case ReadyToRunFixupKind.READYTORUN_FIXUP_PInvokeTarget: + case ReadyToRunFixupKind.PInvokeTarget: ParseMethod(builder); builder.Append(" (PINVOKE_TARGET)"); break; @@ -1261,16 +1259,16 @@ namespace R2RDump switch ((ReadyToRunHelper)helperType) { - case ReadyToRunHelper.READYTORUN_HELPER_Invalid: + case ReadyToRunHelper.Invalid: builder.Append("INVALID"); break; // Not a real helper - handle to current module passed to delay load helpers. - case ReadyToRunHelper.READYTORUN_HELPER_Module: + case ReadyToRunHelper.Module: builder.Append("MODULE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_GSCookie: + case ReadyToRunHelper.GSCookie: builder.Append("GC_COOKIE"); break; @@ -1282,298 +1280,298 @@ namespace R2RDump // All delay load helpers use custom calling convention: // - scratch register - address of indirection cell. 0 = address is inferred from callsite. // - stack - section index, module handle - case ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_MethodCall: + case ReadyToRunHelper.DelayLoad_MethodCall: builder.Append("DELAYLOAD_METHODCALL"); break; - case ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper: + case ReadyToRunHelper.DelayLoad_Helper: builder.Append("DELAYLOAD_HELPER"); break; - case ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper_Obj: + case ReadyToRunHelper.DelayLoad_Helper_Obj: builder.Append("DELAYLOAD_HELPER_OBJ"); break; - case ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper_ObjObj: + case ReadyToRunHelper.DelayLoad_Helper_ObjObj: builder.Append("DELAYLOAD_HELPER_OBJ_OBJ"); break; // JIT helpers // Exception handling helpers - case ReadyToRunHelper.READYTORUN_HELPER_Throw: + case ReadyToRunHelper.Throw: builder.Append("THROW"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Rethrow: + case ReadyToRunHelper.Rethrow: builder.Append("RETHROW"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Overflow: + case ReadyToRunHelper.Overflow: builder.Append("OVERFLOW"); break; - case ReadyToRunHelper.READYTORUN_HELPER_RngChkFail: + case ReadyToRunHelper.RngChkFail: builder.Append("RNG_CHK_FAIL"); break; - case ReadyToRunHelper.READYTORUN_HELPER_FailFast: + case ReadyToRunHelper.FailFast: builder.Append("FAIL_FAST"); break; - case ReadyToRunHelper.READYTORUN_HELPER_ThrowNullRef: + case ReadyToRunHelper.ThrowNullRef: builder.Append("THROW_NULL_REF"); break; - case ReadyToRunHelper.READYTORUN_HELPER_ThrowDivZero: + case ReadyToRunHelper.ThrowDivZero: builder.Append("THROW_DIV_ZERO"); break; // Write barriers - case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier: + case ReadyToRunHelper.WriteBarrier: builder.Append("WRITE_BARRIER"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier: + case ReadyToRunHelper.CheckedWriteBarrier: builder.Append("CHECKED_WRITE_BARRIER"); break; - case ReadyToRunHelper.READYTORUN_HELPER_ByRefWriteBarrier: + case ReadyToRunHelper.ByRefWriteBarrier: builder.Append("BYREF_WRITE_BARRIER"); break; // Array helpers - case ReadyToRunHelper.READYTORUN_HELPER_Stelem_Ref: + case ReadyToRunHelper.Stelem_Ref: builder.Append("STELEM_REF"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Ldelema_Ref: + case ReadyToRunHelper.Ldelema_Ref: builder.Append("LDELEMA_REF"); break; - case ReadyToRunHelper.READYTORUN_HELPER_MemSet: + case ReadyToRunHelper.MemSet: builder.Append("MEM_SET"); break; - case ReadyToRunHelper.READYTORUN_HELPER_MemCpy: + case ReadyToRunHelper.MemCpy: builder.Append("MEM_CPY"); break; // PInvoke helpers - case ReadyToRunHelper.READYTORUN_HELPER_PInvokeBegin: + case ReadyToRunHelper.PInvokeBegin: builder.Append("PINVOKE_BEGIN"); break; - case ReadyToRunHelper.READYTORUN_HELPER_PInvokeEnd: + case ReadyToRunHelper.PInvokeEnd: builder.Append("PINVOKE_END"); break; - case ReadyToRunHelper.READYTORUN_HELPER_GCPoll: + case ReadyToRunHelper.GCPoll: builder.Append("GCPOLL"); break; // Get string handle lazily - case ReadyToRunHelper.READYTORUN_HELPER_GetString: + case ReadyToRunHelper.GetString: builder.Append("GET_STRING"); break; // Used by /Tuning for Profile optimizations - case ReadyToRunHelper.READYTORUN_HELPER_LogMethodEnter: + case ReadyToRunHelper.LogMethodEnter: builder.Append("LOG_METHOD_ENTER"); break; // Reflection helpers - case ReadyToRunHelper.READYTORUN_HELPER_GetRuntimeTypeHandle: + case ReadyToRunHelper.GetRuntimeTypeHandle: builder.Append("GET_RUNTIME_TYPE_HANDLE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_GetRuntimeMethodHandle: + case ReadyToRunHelper.GetRuntimeMethodHandle: builder.Append("GET_RUNTIME_METHOD_HANDLE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_GetRuntimeFieldHandle: + case ReadyToRunHelper.GetRuntimeFieldHandle: builder.Append("GET_RUNTIME_FIELD_HANDLE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Box: + case ReadyToRunHelper.Box: builder.Append("BOX"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Box_Nullable: + case ReadyToRunHelper.Box_Nullable: builder.Append("BOX_NULLABLE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Unbox: + case ReadyToRunHelper.Unbox: builder.Append("UNBOX"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Unbox_Nullable: + case ReadyToRunHelper.Unbox_Nullable: builder.Append("UNBOX_NULLABLE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_NewMultiDimArr: + case ReadyToRunHelper.NewMultiDimArr: builder.Append("NEW_MULTI_DIM_ARR"); break; - case ReadyToRunHelper.READYTORUN_HELPER_NewMultiDimArr_NonVarArg: + case ReadyToRunHelper.NewMultiDimArr_NonVarArg: builder.Append("NEW_MULTI_DIM_ARR__NON_VAR_ARG"); break; // Helpers used with generic handle lookup cases - case ReadyToRunHelper.READYTORUN_HELPER_NewObject: + case ReadyToRunHelper.NewObject: builder.Append("NEW_OBJECT"); break; - case ReadyToRunHelper.READYTORUN_HELPER_NewArray: + case ReadyToRunHelper.NewArray: builder.Append("NEW_ARRAY"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckCastAny: + case ReadyToRunHelper.CheckCastAny: builder.Append("CHECK_CAST_ANY"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckInstanceAny: + case ReadyToRunHelper.CheckInstanceAny: builder.Append("CHECK_INSTANCE_ANY"); break; - case ReadyToRunHelper.READYTORUN_HELPER_GenericGcStaticBase: + case ReadyToRunHelper.GenericGcStaticBase: builder.Append("GENERIC_GC_STATIC_BASE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_GenericNonGcStaticBase: + case ReadyToRunHelper.GenericNonGcStaticBase: builder.Append("GENERIC_NON_GC_STATIC_BASE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_GenericGcTlsBase: + case ReadyToRunHelper.GenericGcTlsBase: builder.Append("GENERIC_GC_TLS_BASE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_GenericNonGcTlsBase: + case ReadyToRunHelper.GenericNonGcTlsBase: builder.Append("GENERIC_NON_GC_TLS_BASE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_VirtualFuncPtr: + case ReadyToRunHelper.VirtualFuncPtr: builder.Append("VIRTUAL_FUNC_PTR"); break; // Long mul/div/shift ops - case ReadyToRunHelper.READYTORUN_HELPER_LMul: + case ReadyToRunHelper.LMul: builder.Append("LMUL"); break; - case ReadyToRunHelper.READYTORUN_HELPER_LMulOfv: + case ReadyToRunHelper.LMulOfv: builder.Append("LMUL_OFV"); break; - case ReadyToRunHelper.READYTORUN_HELPER_ULMulOvf: + case ReadyToRunHelper.ULMulOvf: builder.Append("ULMUL_OVF"); break; - case ReadyToRunHelper.READYTORUN_HELPER_LDiv: + case ReadyToRunHelper.LDiv: builder.Append("LDIV"); break; - case ReadyToRunHelper.READYTORUN_HELPER_LMod: + case ReadyToRunHelper.LMod: builder.Append("LMOD"); break; - case ReadyToRunHelper.READYTORUN_HELPER_ULDiv: + case ReadyToRunHelper.ULDiv: builder.Append("ULDIV"); break; - case ReadyToRunHelper.READYTORUN_HELPER_ULMod: + case ReadyToRunHelper.ULMod: builder.Append("ULMOD"); break; - case ReadyToRunHelper.READYTORUN_HELPER_LLsh: + case ReadyToRunHelper.LLsh: builder.Append("LLSH"); break; - case ReadyToRunHelper.READYTORUN_HELPER_LRsh: + case ReadyToRunHelper.LRsh: builder.Append("LRSH"); break; - case ReadyToRunHelper.READYTORUN_HELPER_LRsz: + case ReadyToRunHelper.LRsz: builder.Append("LRSZ"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Lng2Dbl: + case ReadyToRunHelper.Lng2Dbl: builder.Append("LNG2DBL"); break; - case ReadyToRunHelper.READYTORUN_HELPER_ULng2Dbl: + case ReadyToRunHelper.ULng2Dbl: builder.Append("ULNG2DBL"); break; // 32-bit division helpers - case ReadyToRunHelper.READYTORUN_HELPER_Div: + case ReadyToRunHelper.Div: builder.Append("DIV"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Mod: + case ReadyToRunHelper.Mod: builder.Append("MOD"); break; - case ReadyToRunHelper.READYTORUN_HELPER_UDiv: + case ReadyToRunHelper.UDiv: builder.Append("UDIV"); break; - case ReadyToRunHelper.READYTORUN_HELPER_UMod: + case ReadyToRunHelper.UMod: builder.Append("UMOD"); break; // Floating point conversions - case ReadyToRunHelper.READYTORUN_HELPER_Dbl2Int: + case ReadyToRunHelper.Dbl2Int: builder.Append("DBL2INT"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Dbl2IntOvf: + case ReadyToRunHelper.Dbl2IntOvf: builder.Append("DBL2INTOVF"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Dbl2Lng: + case ReadyToRunHelper.Dbl2Lng: builder.Append("DBL2LNG"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Dbl2LngOvf: + case ReadyToRunHelper.Dbl2LngOvf: builder.Append("DBL2LNGOVF"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Dbl2UInt: + case ReadyToRunHelper.Dbl2UInt: builder.Append("DBL2UINT"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Dbl2UIntOvf: + case ReadyToRunHelper.Dbl2UIntOvf: builder.Append("DBL2UINTOVF"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Dbl2ULng: + case ReadyToRunHelper.Dbl2ULng: builder.Append("DBL2ULNG"); break; - case ReadyToRunHelper.READYTORUN_HELPER_Dbl2ULngOvf: + case ReadyToRunHelper.Dbl2ULngOvf: builder.Append("DBL2ULNGOVF"); break; // Floating point ops - case ReadyToRunHelper.READYTORUN_HELPER_DblRem: + case ReadyToRunHelper.DblRem: builder.Append("DBL_REM"); break; - case ReadyToRunHelper.READYTORUN_HELPER_FltRem: + case ReadyToRunHelper.FltRem: builder.Append("FLT_REM"); break; - case ReadyToRunHelper.READYTORUN_HELPER_DblRound: + case ReadyToRunHelper.DblRound: builder.Append("DBL_ROUND"); break; - case ReadyToRunHelper.READYTORUN_HELPER_FltRound: + case ReadyToRunHelper.FltRound: builder.Append("FLT_ROUND"); break; // Personality rountines - case ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutine: + case ReadyToRunHelper.PersonalityRoutine: builder.Append("PERSONALITY_ROUTINE"); break; - case ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutineFilterFunclet: + case ReadyToRunHelper.PersonalityRoutineFilterFunclet: builder.Append("PERSONALITY_ROUTINE_FILTER_FUNCLET"); break; @@ -1582,49 +1580,49 @@ namespace R2RDump // // JIT32 x86-specific write barriers - case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_EAX: + case ReadyToRunHelper.WriteBarrier_EAX: builder.Append("WRITE_BARRIER_EAX"); break; - case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_EBX: + case ReadyToRunHelper.WriteBarrier_EBX: builder.Append("WRITE_BARRIER_EBX"); break; - case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_ECX: + case ReadyToRunHelper.WriteBarrier_ECX: builder.Append("WRITE_BARRIER_ECX"); break; - case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_ESI: + case ReadyToRunHelper.WriteBarrier_ESI: builder.Append("WRITE_BARRIER_ESI"); break; - case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_EDI: + case ReadyToRunHelper.WriteBarrier_EDI: builder.Append("WRITE_BARRIER_EDI"); break; - case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_EBP: + case ReadyToRunHelper.WriteBarrier_EBP: builder.Append("WRITE_BARRIER_EBP"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_EAX: + case ReadyToRunHelper.CheckedWriteBarrier_EAX: builder.Append("CHECKED_WRITE_BARRIER_EAX"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_EBX: + case ReadyToRunHelper.CheckedWriteBarrier_EBX: builder.Append("CHECKED_WRITE_BARRIER_EBX"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_ECX: + case ReadyToRunHelper.CheckedWriteBarrier_ECX: builder.Append("CHECKED_WRITE_BARRIER_ECX"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_ESI: + case ReadyToRunHelper.CheckedWriteBarrier_ESI: builder.Append("CHECKED_WRITE_BARRIER_ESI"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_EDI: + case ReadyToRunHelper.CheckedWriteBarrier_EDI: builder.Append("CHECKED_WRITE_BARRIER_EDI"); break; - case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_EBP: + case ReadyToRunHelper.CheckedWriteBarrier_EBP: builder.Append("CHECKED_WRITE_BARRIER_EBP"); break; // JIT32 x86-specific exception handling - case ReadyToRunHelper.READYTORUN_HELPER_EndCatch: + case ReadyToRunHelper.EndCatch: builder.Append("END_CATCH"); break; - case ReadyToRunHelper.READYTORUN_HELPER_StackProbe: + case ReadyToRunHelper.StackProbe: builder.Append("STACK_PROBE"); break;