Skip to content

Commit 4cc3020

Browse files
huoyaoyuanjkotas
andauthored
Delete manifest resource cache for NativeAOT (#116471)
* Remove resource cache * Use hash table of assembly name * Expand GetManifestResourceStream * Move argument verification to public api surface * Remove iterator implementation --------- Co-authored-by: Jan Kotas <[email protected]>
1 parent 694fa07 commit 4cc3020

File tree

2 files changed

+67
-82
lines changed

2 files changed

+67
-82
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ protected sealed override IEnumerable<TypeForwardInfo> TypeForwardInfos
113113

114114
public sealed override ManifestResourceInfo GetManifestResourceInfo(string resourceName)
115115
{
116+
ArgumentNullException.ThrowIfNull(resourceName);
116117
return ReflectionCoreExecution.ExecutionEnvironment.GetManifestResourceInfo(this, resourceName);
117118
}
118119

@@ -123,6 +124,7 @@ public sealed override string[] GetManifestResourceNames()
123124

124125
public sealed override Stream GetManifestResourceStream(string name)
125126
{
127+
ArgumentNullException.ThrowIfNull(name);
126128
return ReflectionCoreExecution.ExecutionEnvironment.GetManifestResourceStream(this, name);
127129
}
128130

src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.ManifestResources.cs

Lines changed: 65 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using Internal.NativeFormat;
1111
using Internal.Reflection.Core.Execution;
1212
using Internal.Runtime;
13-
using Internal.Runtime.Augments;
1413
using Internal.Runtime.TypeLoader;
1514

1615
namespace Internal.Reflection.Execution
@@ -22,53 +21,65 @@ internal sealed partial class ExecutionEnvironmentImplementation : ExecutionEnvi
2221
{
2322
public sealed override ManifestResourceInfo GetManifestResourceInfo(Assembly assembly, string resourceName)
2423
{
25-
LowLevelList<ResourceInfo> resourceInfos = GetExtractedResources(assembly);
26-
for (int i = 0; i < resourceInfos.Count; i++)
24+
if (FindResourceWithName(assembly, resourceName).Module != null)
2725
{
28-
if (resourceName == resourceInfos[i].Name)
29-
{
30-
return new ManifestResourceInfo(null, null, ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile);
31-
}
26+
return new ManifestResourceInfo(null, null, ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile);
3227
}
28+
3329
return null;
3430
}
3531

3632
public sealed override string[] GetManifestResourceNames(Assembly assembly)
3733
{
38-
LowLevelList<ResourceInfo> resourceInfos = GetExtractedResources(assembly);
39-
string[] names = new string[resourceInfos.Count];
40-
for (int i = 0; i < resourceInfos.Count; i++)
34+
string assemblyName = assembly.GetName().FullName;
35+
int assemblyNameHash = TypeHashingAlgorithms.ComputeNameHashCode(assemblyName);
36+
ArrayBuilder<string> arrayBuilder = default;
37+
38+
foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
4139
{
42-
names[i] = resourceInfos[i].Name;
40+
if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.BlobIdResourceIndex, out NativeReader reader))
41+
{
42+
continue;
43+
}
44+
NativeParser indexParser = new NativeParser(reader, 0);
45+
NativeHashtable indexHashTable = new NativeHashtable(indexParser);
46+
47+
var lookup = indexHashTable.Lookup(assemblyNameHash);
48+
NativeParser entryParser;
49+
while (!(entryParser = lookup.GetNext()).IsNull)
50+
{
51+
if (entryParser.StringEquals(assemblyName))
52+
{
53+
entryParser.SkipString(); // assemblyName
54+
arrayBuilder.Add(entryParser.GetString());
55+
}
56+
else
57+
{
58+
entryParser.SkipString(); // assemblyName
59+
entryParser.SkipString(); // resourceName
60+
}
61+
entryParser.SkipInteger(); // offset
62+
entryParser.SkipInteger(); // length
63+
}
4364
}
44-
return names;
65+
66+
return arrayBuilder.ToArray();
4567
}
4668

4769
public sealed override Stream GetManifestResourceStream(Assembly assembly, string name)
4870
{
49-
ArgumentNullException.ThrowIfNull(name);
50-
51-
// This was most likely an embedded resource which the toolchain should have embedded
52-
// into an assembly.
53-
LowLevelList<ResourceInfo> resourceInfos = GetExtractedResources(assembly);
54-
for (int i = 0; i < resourceInfos.Count; i++)
71+
ResourceInfo resourceInfo = FindResourceWithName(assembly, name);
72+
if (resourceInfo.Module != null)
5573
{
56-
ResourceInfo resourceInfo = resourceInfos[i];
57-
if (name == resourceInfo.Name)
58-
{
59-
return ReadResourceFromBlob(resourceInfo);
60-
}
74+
return ReadResourceFromBlob(resourceInfo);
6175
}
6276

6377
return null;
6478
}
6579

6680
private static unsafe UnmanagedMemoryStream ReadResourceFromBlob(ResourceInfo resourceInfo)
6781
{
68-
byte* pBlob;
69-
uint cbBlob;
70-
71-
if (!resourceInfo.Module.TryFindBlob((int)ReflectionMapBlob.BlobIdResourceData, out pBlob, out cbBlob))
82+
if (!resourceInfo.Module.TryFindBlob((int)ReflectionMapBlob.BlobIdResourceData, out byte* pBlob, out uint cbBlob))
7283
{
7384
throw new BadImageFormatException();
7485
}
@@ -78,85 +89,57 @@ private static unsafe UnmanagedMemoryStream ReadResourceFromBlob(ResourceInfo re
7889
return new UnmanagedMemoryStream(pBlob + resourceInfo.Index, resourceInfo.Length);
7990
}
8091

81-
private static LowLevelList<ResourceInfo> GetExtractedResources(Assembly assembly)
92+
private static ResourceInfo FindResourceWithName(Assembly assembly, string resourceName)
8293
{
83-
LowLevelDictionary<string, LowLevelList<ResourceInfo>> extractedResourceDictionary = ExtractedResourceDictionary;
8494
string assemblyName = assembly.GetName().FullName;
85-
LowLevelList<ResourceInfo> resourceInfos;
86-
if (!extractedResourceDictionary.TryGetValue(assemblyName, out resourceInfos))
87-
return new LowLevelList<ResourceInfo>();
88-
return resourceInfos;
89-
}
95+
int assemblyNameHash = TypeHashingAlgorithms.ComputeNameHashCode(assemblyName);
9096

91-
private static LowLevelDictionary<string, LowLevelList<ResourceInfo>> ExtractedResourceDictionary
92-
{
93-
get
97+
foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
9498
{
95-
if (s_extractedResourceDictionary == null)
99+
if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.BlobIdResourceIndex, out NativeReader reader))
96100
{
97-
// Lazily create the extracted resource dictionary. If two threads race here, we may construct two dictionaries
98-
// and overwrite one - this is ok since the dictionaries are read-only once constructed and they contain the identical data.
99-
100-
LowLevelDictionary<string, LowLevelList<ResourceInfo>> dict = new LowLevelDictionary<string, LowLevelList<ResourceInfo>>();
101+
continue;
102+
}
103+
NativeParser indexParser = new NativeParser(reader, 0);
104+
NativeHashtable indexHashTable = new NativeHashtable(indexParser);
101105

102-
foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
106+
var lookup = indexHashTable.Lookup(assemblyNameHash);
107+
NativeParser entryParser;
108+
while (!(entryParser = lookup.GetNext()).IsNull)
109+
{
110+
if (entryParser.StringEquals(assemblyName))
103111
{
104-
NativeReader reader;
105-
if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.BlobIdResourceIndex, out reader))
106-
{
107-
continue;
108-
}
109-
NativeParser indexParser = new NativeParser(reader, 0);
110-
NativeHashtable indexHashTable = new NativeHashtable(indexParser);
111-
112-
var entryEnumerator = indexHashTable.EnumerateAllEntries();
113-
NativeParser entryParser;
114-
while (!(entryParser = entryEnumerator.GetNext()).IsNull)
112+
entryParser.SkipString(); // assemblyName
113+
if (entryParser.StringEquals(resourceName))
115114
{
116-
string assemblyName = entryParser.GetString();
117-
string resourceName = entryParser.GetString();
115+
entryParser.SkipString(); // resourceName
118116
int resourceOffset = (int)entryParser.GetUnsigned();
119117
int resourceLength = (int)entryParser.GetUnsigned();
120-
121-
ResourceInfo resourceInfo = new ResourceInfo(resourceName, resourceOffset, resourceLength, module);
122-
123-
LowLevelList<ResourceInfo> assemblyResources;
124-
if (!dict.TryGetValue(assemblyName, out assemblyResources))
125-
{
126-
assemblyResources = new LowLevelList<ResourceInfo>();
127-
dict[assemblyName] = assemblyResources;
128-
}
129-
130-
assemblyResources.Add(resourceInfo);
118+
return new ResourceInfo(resourceOffset, resourceLength, module);
131119
}
132120
}
133-
134-
s_extractedResourceDictionary = dict;
121+
else
122+
{
123+
entryParser.SkipString(); // assemblyName
124+
}
125+
entryParser.SkipString(); // resourceName
126+
entryParser.SkipInteger(); // offset
127+
entryParser.SkipInteger(); // length
135128
}
136-
return s_extractedResourceDictionary;
137129
}
138-
}
139130

140-
/// <summary>
141-
/// This dictionary gets us from assembly + resource name to the offset of a resource
142-
/// inside the resource data blob
143-
///
144-
/// The dictionary's key is a Fusion-style assembly name.
145-
/// The dictionary's value is a list of (resourcename,index) tuples.
146-
/// </summary>
147-
private static volatile LowLevelDictionary<string, LowLevelList<ResourceInfo>> s_extractedResourceDictionary;
131+
return default;
132+
}
148133

149134
private struct ResourceInfo
150135
{
151-
public ResourceInfo(string name, int index, int length, NativeFormatModuleInfo module)
136+
public ResourceInfo(int index, int length, NativeFormatModuleInfo module)
152137
{
153-
Name = name;
154138
Index = index;
155139
Length = length;
156140
Module = module;
157141
}
158142

159-
public string Name { get; }
160143
public int Index { get; }
161144
public int Length { get; }
162145
public NativeFormatModuleInfo Module { get; }

0 commit comments

Comments
 (0)