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();
ModuleBuilder mb = GetTypeWrapperFactory().ModuleBuilder;
// HACK force all referenced assemblies to end up as references in the assembly
// (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++)
if(targetIsModule)
{
Type[] types = referencedAssemblies[i].MainAssembly.GetExportedTypes();
if(types.Length > 0)
// HACK force all referenced assemblies to end up as references in the assembly
// (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();
@ -454,18 +459,19 @@ namespace IKVM.Internal
mb.SetCustomAttribute(cab);
}
// add a package list
// add a package list and export map
if(options.sharedclassloader == null || options.sharedclassloader[0] == this)
{
string[] list = new string[packages.Count];
packages.Keys.CopyTo(list, 0);
mb.SetCustomAttribute(new CustomAttributeBuilder(JVM.LoadType(typeof(PackageListAttribute)).GetConstructor(new Type[] { typeof(string[]) }), new object[] { list }));
}
// 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
if(options.sharedclassloader != null && options.sharedclassloader.Count > 1 && options.sharedclassloader[0] == this)
{
WriteExportMap();
// 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
// (the wildcard exports have already been added above, by making sure that we statically reference the assemblies).
if(!targetIsModule)
{
WriteExportMap();
}
}
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;
if (!map.TryGetValue(ccl, out list))
if (!map.TryGetValue(asm, out list))
{
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()
{
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)
{
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)
{
foreach (string name in ccl.options.externalResources.Keys)
if (ccl.options.externalResources != null)
{
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();
BinaryWriter bw = new BinaryWriter(ms);
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.Value.Count);
foreach (string name in kv.Value)
bw.Write(kv.Key.FullName);
if (kv.Value == null)
{
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;
@ -2332,10 +2358,6 @@ namespace IKVM.Internal
{
compiler.EmitRemappedTypes2ndPass();
}
if (!compilingCoreAssembly)
{
ClassLoaderWrapper.SetBootstrapClassLoader(ClassLoaderWrapper.GetAssemblyClassLoader(JVM.CoreAssembly));
}
Dictionary<CompilerClassLoader, CustomAttributeBuilder> mainAssemblyCabs = new Dictionary<CompilerClassLoader, CustomAttributeBuilder>();
foreach (CompilerClassLoader compiler in compilers)
{

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

@ -71,6 +71,7 @@ namespace IKVM.Internal
#if STATIC_COMPILER
// 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)
{
Debug.Assert(ClassLoaderWrapper.bootstrapClassLoader == null);
@ -1057,11 +1058,15 @@ namespace IKVM.Internal
return loader;
}
}
#if !STATIC_COMPILER && !FIRST_PASS
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)
{
Type customClassLoaderClass = null;
@ -1678,20 +1683,20 @@ namespace IKVM.Internal
}
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)
{
this.assemblyLoader = new AssemblyLoader(assembly);
this.references = references;
this.references = fixedReferences;
this.isReflectionOnly = assembly.ReflectionOnly;
this.hasCustomClassLoader = hasCustomClassLoader;
delegates = new AssemblyClassLoader[references.Length];
if(assembly.GetType("__<MainAssembly>") != null)
if(assembly.GetManifestResourceInfo("ikvm.exports") != null)
{
List<AssemblyName> wildcardExports = new List<AssemblyName>();
using(Stream stream = assembly.GetManifestResourceStream("ikvm.exports"))
{
BinaryReader rdr = new BinaryReader(stream);
@ -1704,6 +1709,10 @@ namespace IKVM.Internal
{
exportedAssemblyNames[i] = new AssemblyName(rdr.ReadString());
int typeCount = rdr.ReadInt32();
if(typeCount == 0 && references == null)
{
wildcardExports.Add(exportedAssemblyNames[i]);
}
for(int j = 0; j < typeCount; j++)
{
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