Use "ikvm.exports" map for "wildcard exports" (i.e. assemblies that are referenced and whose types are available thru the assembly class loader).

This commit is contained in:
jfrijters 2009-02-19 08:12:05 +00:00
Родитель a7e9899995
Коммит 9803e4805b
2 изменённых файлов: 85 добавлений и 45 удалений

Просмотреть файл

@ -422,15 +422,20 @@ namespace IKVM.Internal
((DynamicClassLoader)this.GetTypeWrapperFactory()).FinishAll(); ((DynamicClassLoader)this.GetTypeWrapperFactory()).FinishAll();
ModuleBuilder mb = GetTypeWrapperFactory().ModuleBuilder; ModuleBuilder mb = GetTypeWrapperFactory().ModuleBuilder;
// HACK force all referenced assemblies to end up as references in the assembly if(targetIsModule)
// (even if they are otherwise unused), to make sure that the assembly class loader
// delegates to them at runtime.
for(int i = 0;i < referencedAssemblies.Length; i++)
{ {
Type[] types = referencedAssemblies[i].MainAssembly.GetExportedTypes(); // HACK force all referenced assemblies to end up as references in the assembly
if(types.Length > 0) // (even if they are otherwise unused), to make sure that the assembly class loader
// delegates to them at runtime.
// NOTE now we only do this for modules, when we're an assembly we store the exported
// assemblies in the ikvm.exports resource.
for(int i = 0;i < referencedAssemblies.Length; i++)
{ {
mb.GetTypeToken(types[0]); Type[] types = referencedAssemblies[i].MainAssembly.GetExportedTypes();
if(types.Length > 0)
{
mb.GetTypeToken(types[0]);
}
} }
} }
mb.CreateGlobalFunctions(); mb.CreateGlobalFunctions();
@ -454,18 +459,19 @@ namespace IKVM.Internal
mb.SetCustomAttribute(cab); mb.SetCustomAttribute(cab);
} }
// add a package list // add a package list and export map
if(options.sharedclassloader == null || options.sharedclassloader[0] == this) if(options.sharedclassloader == null || options.sharedclassloader[0] == this)
{ {
string[] list = new string[packages.Count]; string[] list = new string[packages.Count];
packages.Keys.CopyTo(list, 0); packages.Keys.CopyTo(list, 0);
mb.SetCustomAttribute(new CustomAttributeBuilder(JVM.LoadType(typeof(PackageListAttribute)).GetConstructor(new Type[] { typeof(string[]) }), new object[] { list })); mb.SetCustomAttribute(new CustomAttributeBuilder(JVM.LoadType(typeof(PackageListAttribute)).GetConstructor(new Type[] { typeof(string[]) }), new object[] { list }));
} // We can't add the resource when we're a module, because a multi-module assembly has a single resource namespace
// and since you cannot combine -target:module with -sharedclassloader we don't need an export map
// if we're the main assembly in a shared class loader group, add a resource that lists all the types available in the other assemblies // (the wildcard exports have already been added above, by making sure that we statically reference the assemblies).
if(options.sharedclassloader != null && options.sharedclassloader.Count > 1 && options.sharedclassloader[0] == this) if(!targetIsModule)
{ {
WriteExportMap(); WriteExportMap();
}
} }
if(targetIsModule) if(targetIsModule)
@ -482,40 +488,51 @@ namespace IKVM.Internal
} }
} }
private static void AddExportMapEntry(Dictionary<CompilerClassLoader, List<string>> map, CompilerClassLoader ccl, string name) private static void AddExportMapEntry(Dictionary<AssemblyName, List<string>> map, CompilerClassLoader ccl, string name)
{ {
AssemblyName asm = ccl.assemblyBuilder.GetName();
List<string> list; List<string> list;
if (!map.TryGetValue(ccl, out list)) if (!map.TryGetValue(asm, out list))
{ {
list = new List<string>(); list = new List<string>();
map.Add(ccl, list); map.Add(asm, list);
}
if (list != null) // if list is null, we already have a wildcard export for this assembly
{
list.Add(name);
} }
list.Add(name);
} }
private void WriteExportMap() private void WriteExportMap()
{ {
Dictionary<CompilerClassLoader, List<string>> exportedNamesPerAssembly = new Dictionary<CompilerClassLoader, List<string>>(); Dictionary<AssemblyName, List<string>> exportedNamesPerAssembly = new Dictionary<AssemblyName, List<string>>();
foreach (AssemblyClassLoader acl in referencedAssemblies)
{
exportedNamesPerAssembly.Add(acl.MainAssembly.GetName(), null);
}
foreach (TypeWrapper tw in dynamicallyImportedTypes) foreach (TypeWrapper tw in dynamicallyImportedTypes)
{ {
AddExportMapEntry(exportedNamesPerAssembly, (CompilerClassLoader)tw.GetClassLoader(), tw.Name); AddExportMapEntry(exportedNamesPerAssembly, (CompilerClassLoader)tw.GetClassLoader(), tw.Name);
} }
foreach (CompilerClassLoader ccl in options.sharedclassloader) if (options.sharedclassloader != null)
{ {
if (ccl != this) foreach (CompilerClassLoader ccl in options.sharedclassloader)
{ {
if (ccl.options.resources != null) if (ccl != this)
{ {
foreach (string name in ccl.options.resources.Keys) if (ccl.options.resources != null)
{ {
AddExportMapEntry(exportedNamesPerAssembly, ccl, name); foreach (string name in ccl.options.resources.Keys)
{
AddExportMapEntry(exportedNamesPerAssembly, ccl, name);
}
} }
} if (ccl.options.externalResources != null)
if (ccl.options.externalResources != null)
{
foreach (string name in ccl.options.externalResources.Keys)
{ {
AddExportMapEntry(exportedNamesPerAssembly, ccl, name); foreach (string name in ccl.options.externalResources.Keys)
{
AddExportMapEntry(exportedNamesPerAssembly, ccl, name);
}
} }
} }
} }
@ -523,13 +540,22 @@ namespace IKVM.Internal
MemoryStream ms = new MemoryStream(); MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms); BinaryWriter bw = new BinaryWriter(ms);
bw.Write(exportedNamesPerAssembly.Count); bw.Write(exportedNamesPerAssembly.Count);
foreach (KeyValuePair<CompilerClassLoader, List<string>> kv in exportedNamesPerAssembly) foreach (KeyValuePair<AssemblyName, List<string>> kv in exportedNamesPerAssembly)
{ {
bw.Write(kv.Key.assemblyBuilder.GetName().FullName); bw.Write(kv.Key.FullName);
bw.Write(kv.Value.Count); if (kv.Value == null)
foreach (string name in kv.Value)
{ {
bw.Write(JVM.PersistableHash(name)); // wildcard export
bw.Write(0);
}
else
{
Debug.Assert(kv.Value.Count != 0);
bw.Write(kv.Value.Count);
foreach (string name in kv.Value)
{
bw.Write(JVM.PersistableHash(name));
}
} }
} }
ms.Position = 0; ms.Position = 0;
@ -2332,10 +2358,6 @@ namespace IKVM.Internal
{ {
compiler.EmitRemappedTypes2ndPass(); compiler.EmitRemappedTypes2ndPass();
} }
if (!compilingCoreAssembly)
{
ClassLoaderWrapper.SetBootstrapClassLoader(ClassLoaderWrapper.GetAssemblyClassLoader(JVM.CoreAssembly));
}
Dictionary<CompilerClassLoader, CustomAttributeBuilder> mainAssemblyCabs = new Dictionary<CompilerClassLoader, CustomAttributeBuilder>(); Dictionary<CompilerClassLoader, CustomAttributeBuilder> mainAssemblyCabs = new Dictionary<CompilerClassLoader, CustomAttributeBuilder>();
foreach (CompilerClassLoader compiler in compilers) foreach (CompilerClassLoader compiler in compilers)
{ {

Просмотреть файл

@ -71,6 +71,7 @@ namespace IKVM.Internal
#if STATIC_COMPILER #if STATIC_COMPILER
// HACK this is used by the ahead-of-time compiler to overrule the bootstrap classloader // HACK this is used by the ahead-of-time compiler to overrule the bootstrap classloader
// when we're compiling the core class libraries
internal static void SetBootstrapClassLoader(ClassLoaderWrapper bootstrapClassLoader) internal static void SetBootstrapClassLoader(ClassLoaderWrapper bootstrapClassLoader)
{ {
Debug.Assert(ClassLoaderWrapper.bootstrapClassLoader == null); Debug.Assert(ClassLoaderWrapper.bootstrapClassLoader == null);
@ -1057,11 +1058,15 @@ namespace IKVM.Internal
return loader; return loader;
} }
} }
#if !STATIC_COMPILER && !FIRST_PASS
if(assembly == JVM.CoreAssembly) if(assembly == JVM.CoreAssembly)
{ {
return GetBootstrapClassLoader(); // This cast is necessary for ikvmc and a no-op for the runtime.
// Note that the cast cannot fail, because ikvmc will only return a non AssemblyClassLoader
// from GetBootstrapClassLoader() when compiling the core assembly and in that case JVM.CoreAssembly
// will be null.
return (AssemblyClassLoader)GetBootstrapClassLoader();
} }
#if !STATIC_COMPILER && !FIRST_PASS
if(!assembly.ReflectionOnly) if(!assembly.ReflectionOnly)
{ {
Type customClassLoaderClass = null; Type customClassLoaderClass = null;
@ -1678,20 +1683,20 @@ namespace IKVM.Internal
} }
internal AssemblyClassLoader(Assembly assembly, object javaClassLoader, bool hasCustomClassLoader) internal AssemblyClassLoader(Assembly assembly, object javaClassLoader, bool hasCustomClassLoader)
: this(assembly, assembly.GetReferencedAssemblies(), javaClassLoader, hasCustomClassLoader) : this(assembly, null, javaClassLoader, hasCustomClassLoader)
{ {
} }
internal AssemblyClassLoader(Assembly assembly, AssemblyName[] references, object javaClassLoader, bool hasCustomClassLoader) internal AssemblyClassLoader(Assembly assembly, AssemblyName[] fixedReferences, object javaClassLoader, bool hasCustomClassLoader)
: base(CodeGenOptions.None, javaClassLoader) : base(CodeGenOptions.None, javaClassLoader)
{ {
this.assemblyLoader = new AssemblyLoader(assembly); this.assemblyLoader = new AssemblyLoader(assembly);
this.references = references; this.references = fixedReferences;
this.isReflectionOnly = assembly.ReflectionOnly; this.isReflectionOnly = assembly.ReflectionOnly;
this.hasCustomClassLoader = hasCustomClassLoader; this.hasCustomClassLoader = hasCustomClassLoader;
delegates = new AssemblyClassLoader[references.Length]; if(assembly.GetManifestResourceInfo("ikvm.exports") != null)
if(assembly.GetType("__<MainAssembly>") != null)
{ {
List<AssemblyName> wildcardExports = new List<AssemblyName>();
using(Stream stream = assembly.GetManifestResourceStream("ikvm.exports")) using(Stream stream = assembly.GetManifestResourceStream("ikvm.exports"))
{ {
BinaryReader rdr = new BinaryReader(stream); BinaryReader rdr = new BinaryReader(stream);
@ -1704,6 +1709,10 @@ namespace IKVM.Internal
{ {
exportedAssemblyNames[i] = new AssemblyName(rdr.ReadString()); exportedAssemblyNames[i] = new AssemblyName(rdr.ReadString());
int typeCount = rdr.ReadInt32(); int typeCount = rdr.ReadInt32();
if(typeCount == 0 && references == null)
{
wildcardExports.Add(exportedAssemblyNames[i]);
}
for(int j = 0; j < typeCount; j++) for(int j = 0; j < typeCount; j++)
{ {
int hash = rdr.ReadInt32(); int hash = rdr.ReadInt32();
@ -1717,7 +1726,16 @@ namespace IKVM.Internal
} }
} }
} }
if(references == null)
{
references = wildcardExports.ToArray();
}
} }
else
{
references = assembly.GetReferencedAssemblies();
}
delegates = new AssemblyClassLoader[references.Length];
} }
internal Assembly MainAssembly internal Assembly MainAssembly