diff --git a/classpath/ikvm/internal/AssemblyClassLoader.java b/classpath/ikvm/internal/AssemblyClassLoader.java index 2b58443b..5cdb23a8 100644 --- a/classpath/ikvm/internal/AssemblyClassLoader.java +++ b/classpath/ikvm/internal/AssemblyClassLoader.java @@ -159,6 +159,7 @@ public final class AssemblyClassLoader extends ClassLoader private static native Assembly[] FindResourceAssemblies(Object classLoader, String name, boolean firstOnly); private static native int GetGenericClassLoaderId(AssemblyClassLoader classLoader); private static native Assembly GetBootClassLoaderAssembly(); + private static native String GetGenericClassLoaderName(Object classLoader); // also used by VMClassLoader public static native String[] GetPackages(Object classLoader); @@ -268,8 +269,7 @@ public final class AssemblyClassLoader extends ClassLoader { return assembly.get_FullName(); } - // TODO make this string more meaningful - return "GenericClassLoader"; + return GetGenericClassLoaderName(this); } private URL getCodeBase() diff --git a/ikvmc/CompilerClassLoader.cs b/ikvmc/CompilerClassLoader.cs index dad709de..97f4f991 100644 --- a/ikvmc/CompilerClassLoader.cs +++ b/ikvmc/CompilerClassLoader.cs @@ -2371,7 +2371,10 @@ namespace IKVM.Internal { if(wrapper.GetClassLoader() != loader) { - StaticCompiler.IssueMessage(Message.SkippingReferencedClass, s, ((AssemblyClassLoader)wrapper.GetClassLoader()).Assembly.FullName); + if(!(wrapper.GetClassLoader() is GenericClassLoader)) + { + StaticCompiler.IssueMessage(Message.SkippingReferencedClass, s, ((AssemblyClassLoader)wrapper.GetClassLoader()).Assembly.FullName); + } continue; } if(map == null) diff --git a/ikvmstub/ikvmstub.cs b/ikvmstub/ikvmstub.cs index 2c182c7c..454a8300 100644 --- a/ikvmstub/ikvmstub.cs +++ b/ikvmstub/ikvmstub.cs @@ -221,8 +221,18 @@ public class NetExp private static bool IsGenericType(java.lang.Class c) { - // HACK huge hack, we look for the backtick +#if WHIDBEY + Type t = ikvm.runtime.Util.getInstanceTypeFromClass(c); + while(t == null && c.getDeclaringClass() != null) + { + // dynamic only inner class, so we look at the declaring class + c = c.getDeclaringClass(); + t = ikvm.runtime.Util.getInstanceTypeFromClass(c); + } + return t.IsGenericType; +#else return c.getName().IndexOf("$$0060") > 0; +#endif } private static void ProcessClass(java.lang.Class c) diff --git a/runtime/ClassLoaderWrapper.cs b/runtime/ClassLoaderWrapper.cs index d2b7159c..9eed894c 100644 --- a/runtime/ClassLoaderWrapper.cs +++ b/runtime/ClassLoaderWrapper.cs @@ -223,25 +223,22 @@ namespace IKVM.Internal string dotnetAssembly = f.IKVMAssemblyAttribute; if(dotnetAssembly != null) { - // The sole purpose of the stub class is to let us load the assembly that the class lives in, - // once we've done that, all types in it become visible. - Assembly asm; + // It's a stub class generated by ikvmstub (or generated by the runtime when getResource was + // called on a statically compiled class). + ClassLoaderWrapper loader; try { -#if WHIDBEY && STATIC_COMPILER - asm = Assembly.ReflectionOnlyLoad(dotnetAssembly); -#else - asm = Assembly.Load(dotnetAssembly); -#endif + loader = ClassLoaderWrapper.GetAssemblyClassLoaderByName(dotnetAssembly); } catch(Exception x) { + // TODO don't catch all exceptions here throw new NoClassDefFoundError(f.Name + " (" + x.Message + ")"); } - TypeWrapper tw = ClassLoaderWrapper.GetAssemblyClassLoader(asm).LoadClassByDottedNameFast(f.Name); + TypeWrapper tw = loader.LoadClassByDottedNameFast(f.Name); if(tw == null) { - throw new NoClassDefFoundError(f.Name + " (type not found in " + asm.FullName + ")"); + throw new NoClassDefFoundError(f.Name + " (type not found in " + dotnetAssembly + ")"); } return RegisterInitiatingLoader(tw); } @@ -465,7 +462,7 @@ namespace IKVM.Internal { return null; } - Type type = GetBootstrapClassLoader().GetType(DotNetTypeWrapper.DemangleTypeName(name.Substring(0, pos))); + Type type = GetType(DotNetTypeWrapper.DemangleTypeName(name.Substring(0, pos))); if(type == null || !Whidbey.IsGenericTypeDefinition(type)) { return null; @@ -518,8 +515,13 @@ namespace IKVM.Internal for(int i = 0; i < typeArguments.Length; i++) { string s = (string)typeParamNames[i]; - s = s.Replace("__", "."); - s = s.Replace("$$005F$$005F", "__"); + // only do the unmangling for non-generic types (because we don't want to convert + // the double underscores in two adjacent _$$$_ or _$$$$_ markers) + if(s.IndexOf("_$$$_") == -1) + { + s = s.Replace("__", "."); + s = s.Replace("$$005F$$005F", "__"); + } int dims = 0; while(s.Length > dims && s[dims] == 'A') { @@ -874,7 +876,13 @@ namespace IKVM.Internal } } ClassLoaderWrapper[] key = (ClassLoaderWrapper[])list.ToArray(typeof(ClassLoaderWrapper)); - ClassLoaderWrapper matchingLoader = null; + ClassLoaderWrapper matchingLoader = GetGenericClassLoaderByKey(key); + matchingLoader.RegisterInitiatingLoader(wrapper); + return matchingLoader; + } + + private static ClassLoaderWrapper GetGenericClassLoaderByKey(ClassLoaderWrapper[] key) + { lock(wrapperLock) { if(genericClassLoaders == null) @@ -885,25 +893,76 @@ namespace IKVM.Internal { if(loader.Matches(key)) { - matchingLoader = loader; - break; + return loader; } } - if(matchingLoader == null) + object javaClassLoader = null; +#if !STATIC_COMPILER + javaClassLoader = JVM.Library.newAssemblyClassLoader(null); +#endif + GenericClassLoader newLoader = new GenericClassLoader(key, javaClassLoader); +#if !STATIC_COMPILER + JVM.Library.setWrapperForClassLoader(javaClassLoader, newLoader); +#endif + genericClassLoaders.Add(newLoader); + return newLoader; + } + } + + internal static ClassLoaderWrapper GetGenericClassLoaderByName(string name) + { + Debug.Assert(name.StartsWith("[[") && name.EndsWith("]]")); + Stack stack = new Stack(); + ArrayList list = null; + for(int i = 0; i < name.Length; i++) + { + if(name[i] == '[') { - object javaClassLoader = null; -#if !STATIC_COMPILER - javaClassLoader = JVM.Library.newAssemblyClassLoader(null); -#endif - matchingLoader = new GenericClassLoader(key, javaClassLoader); -#if !STATIC_COMPILER - JVM.Library.setWrapperForClassLoader(javaClassLoader, matchingLoader); -#endif - genericClassLoaders.Add(matchingLoader); + if(name[i + 1] == '[') + { + stack.Push(list); + list = new ArrayList(); + if(name[i + 2] == '[') + { + i++; + } + } + else + { + int start = i + 1; + i = name.IndexOf(']', i); + list.Add(ClassLoaderWrapper.GetAssemblyClassLoaderByName(name.Substring(start, i - start))); + } + } + else if(name[i] == ']') + { + ClassLoaderWrapper loader = GetGenericClassLoaderByKey((ClassLoaderWrapper[])list.ToArray(typeof(ClassLoaderWrapper))); + list = (ArrayList)stack.Pop(); + if(list == null) + { + return loader; + } + list.Add(loader); + } + else + { + throw new InvalidOperationException(); } } - matchingLoader.RegisterInitiatingLoader(wrapper); - return matchingLoader; + throw new InvalidOperationException(); + } + + internal static ClassLoaderWrapper GetAssemblyClassLoaderByName(string name) + { + if(name.StartsWith("[[")) + { + return GetGenericClassLoaderByName(name); + } +#if WHIDBEY && STATIC_COMPILER + return ClassLoaderWrapper.GetAssemblyClassLoader(Assembly.ReflectionOnlyLoad(name)); +#else + return ClassLoaderWrapper.GetAssemblyClassLoader(Assembly.Load(name)); +#endif } internal static int GetGenericClassLoaderId(ClassLoaderWrapper wrapper) @@ -1067,6 +1126,28 @@ namespace IKVM.Internal } return null; } + + internal string GetName() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.Append('['); + foreach(ClassLoaderWrapper loader in delegates) + { + sb.Append('['); + GenericClassLoader gcl = loader as GenericClassLoader; + if(gcl != null) + { + sb.Append(gcl.GetName()); + } + else + { + sb.Append(((AssemblyClassLoader)loader).Assembly.FullName); + } + sb.Append(']'); + } + sb.Append(']'); + return sb.ToString(); + } } class AssemblyClassLoader : ClassLoaderWrapper diff --git a/runtime/TypeWrapper.cs b/runtime/TypeWrapper.cs index ef5d6e83..ba313cfb 100644 --- a/runtime/TypeWrapper.cs +++ b/runtime/TypeWrapper.cs @@ -8706,8 +8706,13 @@ namespace IKVM.Internal else { string s = tw.Name; - s = s.Replace("__", "$$005F$$005F"); - s = s.Replace(".", "__"); + // only do the mangling for non-generic types (because we don't want to convert + // the double underscores in two adjacent _$$$_ or _$$$$_ markers) + if (s.IndexOf("_$$$_") == -1) + { + s = s.Replace("__", "$$005F$$005F"); + s = s.Replace(".", "__"); + } sb.Append('L').Append(s); } sep = "_$$_"; diff --git a/runtime/classpath.cs b/runtime/classpath.cs index e10af72d..04eebf44 100644 --- a/runtime/classpath.cs +++ b/runtime/classpath.cs @@ -1583,6 +1583,11 @@ namespace IKVM.NativeCode.ikvm.@internal { return ((IKVM.Internal.AssemblyClassLoader)ClassLoaderWrapper.GetBootstrapClassLoader()).Assembly; } + + public static string GetGenericClassLoaderName(object classLoader) + { + return ((GenericClassLoader)JVM.Library.getWrapperFromClassLoader(classLoader)).GetName(); + } } namespace stubgen @@ -1599,8 +1604,7 @@ namespace IKVM.NativeCode.ikvm.@internal } else { - // TODO - return "TODO: implement support for generic types referencing multiple assemblies in their IKVM.NET.Assembly attribute"; + return ((IKVM.Internal.GenericClassLoader)loader).GetName(); } } @@ -1717,6 +1721,10 @@ namespace IKVM.NativeCode.ikvm.runtime public static Type GetInstanceTypeFromTypeWrapper(object wrapperObject) { TypeWrapper wrapper = (TypeWrapper)wrapperObject; + if(wrapper.IsDynamicOnly) + { + return null; + } if(wrapper.IsRemapped && wrapper.IsFinal) { return wrapper.TypeAsTBD;