diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs index 2ca7967bcffc5b..88bf56df206558 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs @@ -113,6 +113,7 @@ protected sealed override IEnumerable TypeForwardInfos public sealed override ManifestResourceInfo GetManifestResourceInfo(string resourceName) { + ArgumentNullException.ThrowIfNull(resourceName); return ReflectionCoreExecution.ExecutionEnvironment.GetManifestResourceInfo(this, resourceName); } @@ -123,6 +124,7 @@ public sealed override string[] GetManifestResourceNames() public sealed override Stream GetManifestResourceStream(string name) { + ArgumentNullException.ThrowIfNull(name); return ReflectionCoreExecution.ExecutionEnvironment.GetManifestResourceStream(this, name); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.ManifestResources.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.ManifestResources.cs index 182a3333d6a9d0..c692a9ddbaffad 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.ManifestResources.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.ManifestResources.cs @@ -10,7 +10,6 @@ using Internal.NativeFormat; using Internal.Reflection.Core.Execution; using Internal.Runtime; -using Internal.Runtime.Augments; using Internal.Runtime.TypeLoader; namespace Internal.Reflection.Execution @@ -22,42 +21,57 @@ internal sealed partial class ExecutionEnvironmentImplementation : ExecutionEnvi { public sealed override ManifestResourceInfo GetManifestResourceInfo(Assembly assembly, string resourceName) { - LowLevelList resourceInfos = GetExtractedResources(assembly); - for (int i = 0; i < resourceInfos.Count; i++) + if (FindResourceWithName(assembly, resourceName).Module != null) { - if (resourceName == resourceInfos[i].Name) - { - return new ManifestResourceInfo(null, null, ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile); - } + return new ManifestResourceInfo(null, null, ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile); } + return null; } public sealed override string[] GetManifestResourceNames(Assembly assembly) { - LowLevelList resourceInfos = GetExtractedResources(assembly); - string[] names = new string[resourceInfos.Count]; - for (int i = 0; i < resourceInfos.Count; i++) + string assemblyName = assembly.GetName().FullName; + int assemblyNameHash = TypeHashingAlgorithms.ComputeNameHashCode(assemblyName); + ArrayBuilder arrayBuilder = default; + + foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) { - names[i] = resourceInfos[i].Name; + if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.BlobIdResourceIndex, out NativeReader reader)) + { + continue; + } + NativeParser indexParser = new NativeParser(reader, 0); + NativeHashtable indexHashTable = new NativeHashtable(indexParser); + + var lookup = indexHashTable.Lookup(assemblyNameHash); + NativeParser entryParser; + while (!(entryParser = lookup.GetNext()).IsNull) + { + if (entryParser.StringEquals(assemblyName)) + { + entryParser.SkipString(); // assemblyName + arrayBuilder.Add(entryParser.GetString()); + } + else + { + entryParser.SkipString(); // assemblyName + entryParser.SkipString(); // resourceName + } + entryParser.SkipInteger(); // offset + entryParser.SkipInteger(); // length + } } - return names; + + return arrayBuilder.ToArray(); } public sealed override Stream GetManifestResourceStream(Assembly assembly, string name) { - ArgumentNullException.ThrowIfNull(name); - - // This was most likely an embedded resource which the toolchain should have embedded - // into an assembly. - LowLevelList resourceInfos = GetExtractedResources(assembly); - for (int i = 0; i < resourceInfos.Count; i++) + ResourceInfo resourceInfo = FindResourceWithName(assembly, name); + if (resourceInfo.Module != null) { - ResourceInfo resourceInfo = resourceInfos[i]; - if (name == resourceInfo.Name) - { - return ReadResourceFromBlob(resourceInfo); - } + return ReadResourceFromBlob(resourceInfo); } return null; @@ -65,10 +79,7 @@ public sealed override Stream GetManifestResourceStream(Assembly assembly, strin private static unsafe UnmanagedMemoryStream ReadResourceFromBlob(ResourceInfo resourceInfo) { - byte* pBlob; - uint cbBlob; - - if (!resourceInfo.Module.TryFindBlob((int)ReflectionMapBlob.BlobIdResourceData, out pBlob, out cbBlob)) + if (!resourceInfo.Module.TryFindBlob((int)ReflectionMapBlob.BlobIdResourceData, out byte* pBlob, out uint cbBlob)) { throw new BadImageFormatException(); } @@ -78,85 +89,57 @@ private static unsafe UnmanagedMemoryStream ReadResourceFromBlob(ResourceInfo re return new UnmanagedMemoryStream(pBlob + resourceInfo.Index, resourceInfo.Length); } - private static LowLevelList GetExtractedResources(Assembly assembly) + private static ResourceInfo FindResourceWithName(Assembly assembly, string resourceName) { - LowLevelDictionary> extractedResourceDictionary = ExtractedResourceDictionary; string assemblyName = assembly.GetName().FullName; - LowLevelList resourceInfos; - if (!extractedResourceDictionary.TryGetValue(assemblyName, out resourceInfos)) - return new LowLevelList(); - return resourceInfos; - } + int assemblyNameHash = TypeHashingAlgorithms.ComputeNameHashCode(assemblyName); - private static LowLevelDictionary> ExtractedResourceDictionary - { - get + foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) { - if (s_extractedResourceDictionary == null) + if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.BlobIdResourceIndex, out NativeReader reader)) { - // Lazily create the extracted resource dictionary. If two threads race here, we may construct two dictionaries - // and overwrite one - this is ok since the dictionaries are read-only once constructed and they contain the identical data. - - LowLevelDictionary> dict = new LowLevelDictionary>(); + continue; + } + NativeParser indexParser = new NativeParser(reader, 0); + NativeHashtable indexHashTable = new NativeHashtable(indexParser); - foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) + var lookup = indexHashTable.Lookup(assemblyNameHash); + NativeParser entryParser; + while (!(entryParser = lookup.GetNext()).IsNull) + { + if (entryParser.StringEquals(assemblyName)) { - NativeReader reader; - if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.BlobIdResourceIndex, out reader)) - { - continue; - } - NativeParser indexParser = new NativeParser(reader, 0); - NativeHashtable indexHashTable = new NativeHashtable(indexParser); - - var entryEnumerator = indexHashTable.EnumerateAllEntries(); - NativeParser entryParser; - while (!(entryParser = entryEnumerator.GetNext()).IsNull) + entryParser.SkipString(); // assemblyName + if (entryParser.StringEquals(resourceName)) { - string assemblyName = entryParser.GetString(); - string resourceName = entryParser.GetString(); + entryParser.SkipString(); // resourceName int resourceOffset = (int)entryParser.GetUnsigned(); int resourceLength = (int)entryParser.GetUnsigned(); - - ResourceInfo resourceInfo = new ResourceInfo(resourceName, resourceOffset, resourceLength, module); - - LowLevelList assemblyResources; - if (!dict.TryGetValue(assemblyName, out assemblyResources)) - { - assemblyResources = new LowLevelList(); - dict[assemblyName] = assemblyResources; - } - - assemblyResources.Add(resourceInfo); + return new ResourceInfo(resourceOffset, resourceLength, module); } } - - s_extractedResourceDictionary = dict; + else + { + entryParser.SkipString(); // assemblyName + } + entryParser.SkipString(); // resourceName + entryParser.SkipInteger(); // offset + entryParser.SkipInteger(); // length } - return s_extractedResourceDictionary; } - } - /// - /// This dictionary gets us from assembly + resource name to the offset of a resource - /// inside the resource data blob - /// - /// The dictionary's key is a Fusion-style assembly name. - /// The dictionary's value is a list of (resourcename,index) tuples. - /// - private static volatile LowLevelDictionary> s_extractedResourceDictionary; + return default; + } private struct ResourceInfo { - public ResourceInfo(string name, int index, int length, NativeFormatModuleInfo module) + public ResourceInfo(int index, int length, NativeFormatModuleInfo module) { - Name = name; Index = index; Length = length; Module = module; } - public string Name { get; } public int Index { get; } public int Length { get; } public NativeFormatModuleInfo Module { get; }