ikvm-fork/runtime/ClassLoaderWrapper.cs

2343 строки
61 KiB
C#
Исходник Обычный вид История

2002-12-18 19:00:25 +03:00
/*
Copyright (C) 2002-2009 Jeroen Frijters
2002-12-18 19:00:25 +03:00
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Reflection;
#if IKVM_REF_EMIT
using IKVM.Reflection.Emit;
#elif !COMPACT_FRAMEWORK
2005-12-07 12:06:32 +03:00
using System.Reflection.Emit;
#endif
2002-12-18 19:00:25 +03:00
using System.IO;
2008-08-15 16:01:06 +04:00
using System.Collections.Generic;
2002-12-18 19:00:25 +03:00
using System.Diagnostics;
2006-10-10 20:24:48 +04:00
using System.Threading;
using System.Runtime.CompilerServices;
2004-09-09 15:17:55 +04:00
using IKVM.Attributes;
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
namespace IKVM.Internal
2002-12-18 19:00:25 +03:00
{
2006-07-06 17:53:51 +04:00
abstract class TypeWrapperFactory
{
#if !COMPACT_FRAMEWORK
internal abstract ModuleBuilder ModuleBuilder { get; }
#endif
2008-08-15 16:01:06 +04:00
internal abstract TypeWrapper DefineClassImpl(Dictionary<string, TypeWrapper> types, ClassFile f, ClassLoaderWrapper classLoader, object protectionDomain);
2007-06-12 13:46:53 +04:00
internal abstract bool ReserveName(string name);
internal abstract Type DefineUnloadable(string name);
2006-07-06 17:53:51 +04:00
}
class ClassLoaderWrapper
2002-12-18 19:00:25 +03:00
{
2005-12-07 12:06:32 +03:00
private static readonly object wrapperLock = new object();
private static readonly Dictionary<Type, TypeWrapper> globalTypeToTypeWrapper = new Dictionary<Type, TypeWrapper>();
2006-08-14 11:57:03 +04:00
#if STATIC_COMPILER
2005-06-01 13:49:30 +04:00
private static ClassLoaderWrapper bootstrapClassLoader;
2009-03-07 11:33:33 +03:00
private TypeWrapper circularDependencyHack;
2006-08-14 11:57:03 +04:00
#else
private static AssemblyClassLoader bootstrapClassLoader;
2006-04-10 13:09:09 +04:00
#endif
2008-08-15 16:01:06 +04:00
private static readonly Dictionary<Assembly, AssemblyClassLoader> assemblyClassLoaders = new Dictionary<Assembly, AssemblyClassLoader>();
private static List<GenericClassLoader> genericClassLoaders;
#if !STATIC_COMPILER && !FIRST_PASS
private readonly java.lang.ClassLoader javaClassLoader;
private static bool customClassLoaderRedirectsLoaded;
2008-08-15 16:01:06 +04:00
private static Dictionary<string, string> customClassLoaderRedirects;
#endif
private TypeWrapperFactory factory;
2008-08-15 16:01:06 +04:00
private Dictionary<string, TypeWrapper> types = new Dictionary<string, TypeWrapper>();
private readonly Dictionary<string, Thread> defineClassInProgress = new Dictionary<string, Thread>();
private List<IntPtr> nativeLibraries;
2006-09-01 11:53:36 +04:00
private CodeGenOptions codegenoptions;
#if CLASSGC
private Dictionary<Type, TypeWrapper> typeToTypeWrapper;
private static ConditionalWeakTable<Assembly, ClassLoaderWrapper> dynamicAssemblies;
#endif
2008-08-15 16:01:06 +04:00
private static Dictionary<Type, string> remappedTypes = new Dictionary<Type, string>();
2002-12-18 19:00:25 +03:00
2006-08-14 11:57:03 +04:00
#if STATIC_COMPILER
2005-06-01 13:49:30 +04:00
// HACK this is used by the ahead-of-time compiler to overrule the bootstrap classloader
// when we're compiling the core class libraries
2005-06-01 13:49:30 +04:00
internal static void SetBootstrapClassLoader(ClassLoaderWrapper bootstrapClassLoader)
{
Debug.Assert(ClassLoaderWrapper.bootstrapClassLoader == null);
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
ClassLoaderWrapper.bootstrapClassLoader = bootstrapClassLoader;
}
2006-08-14 11:57:03 +04:00
#endif
2004-03-08 18:18:47 +03:00
2005-06-01 13:49:30 +04:00
static ClassLoaderWrapper()
{
globalTypeToTypeWrapper[PrimitiveTypeWrapper.BOOLEAN.TypeAsTBD] = PrimitiveTypeWrapper.BOOLEAN;
globalTypeToTypeWrapper[PrimitiveTypeWrapper.BYTE.TypeAsTBD] = PrimitiveTypeWrapper.BYTE;
globalTypeToTypeWrapper[PrimitiveTypeWrapper.CHAR.TypeAsTBD] = PrimitiveTypeWrapper.CHAR;
globalTypeToTypeWrapper[PrimitiveTypeWrapper.DOUBLE.TypeAsTBD] = PrimitiveTypeWrapper.DOUBLE;
globalTypeToTypeWrapper[PrimitiveTypeWrapper.FLOAT.TypeAsTBD] = PrimitiveTypeWrapper.FLOAT;
globalTypeToTypeWrapper[PrimitiveTypeWrapper.INT.TypeAsTBD] = PrimitiveTypeWrapper.INT;
globalTypeToTypeWrapper[PrimitiveTypeWrapper.LONG.TypeAsTBD] = PrimitiveTypeWrapper.LONG;
globalTypeToTypeWrapper[PrimitiveTypeWrapper.SHORT.TypeAsTBD] = PrimitiveTypeWrapper.SHORT;
globalTypeToTypeWrapper[PrimitiveTypeWrapper.VOID.TypeAsTBD] = PrimitiveTypeWrapper.VOID;
2005-06-01 13:49:30 +04:00
LoadRemappedTypes();
}
2004-12-21 17:59:29 +03:00
2005-06-01 13:49:30 +04:00
internal static void LoadRemappedTypes()
2002-12-18 19:00:25 +03:00
{
2005-12-07 12:06:32 +03:00
// if we're compiling the core, coreAssembly will be null
Assembly coreAssembly = JVM.CoreAssembly;
if(coreAssembly != null)
2004-03-08 18:18:47 +03:00
{
try
{
Tracer.Info(Tracer.Runtime, "Core assembly: {0}", coreAssembly.Location);
}
catch(System.Security.SecurityException)
{
}
2005-12-07 12:06:32 +03:00
RemappedClassAttribute[] remapped = AttributeHelper.GetRemappedClasses(coreAssembly);
2005-06-01 13:49:30 +04:00
if(remapped.Length > 0)
{
foreach(RemappedClassAttribute r in remapped)
{
Tracer.Info(Tracer.Runtime, "Remapping type {0} to {1}", r.RemappedType, r.Name);
remappedTypes.Add(r.RemappedType, r.Name);
}
}
else
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
JVM.CriticalFailure("Failed to find core classes in core library", null);
2004-03-08 18:18:47 +03:00
}
}
2002-12-18 19:00:25 +03:00
}
2004-03-08 18:18:47 +03:00
2006-09-01 11:53:36 +04:00
internal ClassLoaderWrapper(CodeGenOptions codegenoptions, object javaClassLoader)
2004-08-17 13:05:21 +04:00
{
2006-09-01 11:53:36 +04:00
this.codegenoptions = codegenoptions;
#if !STATIC_COMPILER && !FIRST_PASS
this.javaClassLoader = (java.lang.ClassLoader)javaClassLoader;
#endif
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal static bool IsRemappedType(Type type)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
return remappedTypes.ContainsKey(type);
2004-08-17 13:05:21 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal void SetRemappedType(Type type, TypeWrapper tw)
{
2008-08-15 16:01:06 +04:00
lock(types)
{
types.Add(tw.Name, tw);
}
lock(globalTypeToTypeWrapper)
2008-08-15 16:01:06 +04:00
{
globalTypeToTypeWrapper.Add(type, tw);
2008-08-15 16:01:06 +04:00
}
remappedTypes.Add(type, tw.Name);
2005-06-01 13:49:30 +04:00
}
2002-12-18 19:00:25 +03:00
// return the TypeWrapper if it is already loaded, this exists for DynamicTypeWrapper.SetupGhosts
// and ClassLoader.findLoadedClass()
internal virtual TypeWrapper GetLoadedClass(string name)
2004-08-17 13:05:21 +04:00
{
2008-08-15 16:01:06 +04:00
lock(types)
2005-06-01 13:49:30 +04:00
{
2008-08-15 16:01:06 +04:00
TypeWrapper tw;
types.TryGetValue(name, out tw);
return tw;
2005-06-01 13:49:30 +04:00
}
2004-08-17 13:05:21 +04:00
}
2003-12-20 01:19:18 +03:00
2006-07-26 13:03:44 +04:00
internal TypeWrapper RegisterInitiatingLoader(TypeWrapper tw)
2005-07-27 19:57:55 +04:00
{
2006-07-11 15:34:44 +04:00
Debug.Assert(tw != null);
Debug.Assert(!tw.IsUnloadable);
Debug.Assert(!tw.IsPrimitive);
2005-07-27 19:57:55 +04:00
2008-08-15 16:01:06 +04:00
lock(types)
2005-07-27 19:57:55 +04:00
{
2008-08-15 16:01:06 +04:00
TypeWrapper existing;
types.TryGetValue(tw.Name, out existing);
2005-07-27 19:57:55 +04:00
if(existing != tw)
{
if(existing != null)
{
2006-07-10 18:40:31 +04:00
// another thread beat us to it, discard the new TypeWrapper and
// return the previous one
2008-08-15 16:01:06 +04:00
return existing;
2005-07-27 19:57:55 +04:00
}
// NOTE if types.ContainsKey(tw.Name) is true (i.e. the value is null),
// we currently have a DefineClass in progress on another thread and we've
// beaten that thread to the punch by loading the class from a parent class
// loader instead. This is ok as DefineClass will throw a LinkageError when
// it is done.
types[tw.Name] = tw;
}
}
return tw;
}
2006-08-29 10:28:34 +04:00
internal bool EmitDebugInfo
{
get
{
2006-09-01 11:53:36 +04:00
return (codegenoptions & CodeGenOptions.Debug) != 0;
2006-08-29 10:28:34 +04:00
}
}
internal bool EmitStackTraceInfo
{
get
{
2006-09-01 11:53:36 +04:00
// NOTE we're negating the flag here!
return (codegenoptions & CodeGenOptions.NoStackTraceInfo) == 0;
2006-08-29 10:28:34 +04:00
}
}
internal bool StrictFinalFieldSemantics
{
get
{
2006-09-01 11:53:36 +04:00
return (codegenoptions & CodeGenOptions.StrictFinalFieldSemantics) != 0;
2006-08-29 10:28:34 +04:00
}
}
internal bool NoJNI
{
get
{
2006-09-01 11:53:36 +04:00
return (codegenoptions & CodeGenOptions.NoJNI) != 0;
2006-08-29 10:28:34 +04:00
}
}
internal bool RemoveAsserts
{
get
{
return (codegenoptions & CodeGenOptions.RemoveAsserts) != 0;
}
}
2006-08-29 10:28:34 +04:00
internal virtual string SourcePath
{
get
{
return null;
}
}
2009-03-07 11:33:33 +03:00
#if STATIC_COMPILER
internal TypeWrapper LoadCircularDependencyHack(TypeWrapper tw, string name)
{
if (circularDependencyHack == null)
{
circularDependencyHack = tw;
try
{
return LoadClassByDottedNameFast(name);
}
finally
{
circularDependencyHack = null;
}
}
else if (circularDependencyHack.Name == name)
{
return circularDependencyHack;
}
else
{
return LoadClassByDottedNameFast(name);
}
}
#endif
protected virtual void CheckDefineClassAllowed(string className)
{
// this hook exists so that AssemblyClassLoader can prevent DefineClass when the name is already present in the assembly
}
2006-07-06 17:53:51 +04:00
internal TypeWrapper DefineClass(ClassFile f, object protectionDomain)
{
string dotnetAssembly = f.IKVMAssemblyAttribute;
if(dotnetAssembly != null)
{
// It's a stub class generated by ikvmstub (or generated by the runtime when getResource was
// called on a statically compiled class).
ClassLoaderWrapper loader;
2006-07-06 17:53:51 +04:00
try
{
loader = ClassLoaderWrapper.GetAssemblyClassLoaderByName(dotnetAssembly);
2006-07-06 17:53:51 +04:00
}
catch(Exception x)
{
// TODO don't catch all exceptions here
2006-07-06 17:53:51 +04:00
throw new NoClassDefFoundError(f.Name + " (" + x.Message + ")");
}
TypeWrapper tw = loader.LoadClassByDottedNameFast(f.Name);
2006-07-06 17:53:51 +04:00
if(tw == null)
{
throw new NoClassDefFoundError(f.Name + " (type not found in " + dotnetAssembly + ")");
2006-07-06 17:53:51 +04:00
}
return RegisterInitiatingLoader(tw);
}
CheckDefineClassAllowed(f.Name);
2008-08-15 16:01:06 +04:00
lock(types)
2006-07-06 17:53:51 +04:00
{
2006-10-10 20:24:48 +04:00
if(types.ContainsKey(f.Name))
2006-07-11 15:34:44 +04:00
{
2006-10-10 20:24:48 +04:00
throw new LinkageError("duplicate class definition: " + f.Name);
2006-07-11 15:34:44 +04:00
}
2006-10-10 20:24:48 +04:00
// mark the type as "loading in progress", so that we can detect circular dependencies.
types.Add(f.Name, null);
defineClassInProgress.Add(f.Name, Thread.CurrentThread);
}
try
{
return GetTypeWrapperFactory().DefineClassImpl(types, f, this, protectionDomain);
}
finally
{
2008-08-15 16:01:06 +04:00
lock(types)
2006-07-06 17:53:51 +04:00
{
2006-10-10 20:24:48 +04:00
if(types[f.Name] == null)
2006-07-06 17:53:51 +04:00
{
2006-10-10 20:24:48 +04:00
// if loading the class fails, we remove the indicator that we're busy loading the class,
// because otherwise we get a ClassCircularityError if we try to load the class again.
types.Remove(f.Name);
2006-07-06 17:53:51 +04:00
}
2006-10-10 20:24:48 +04:00
defineClassInProgress.Remove(f.Name);
2008-08-15 16:01:06 +04:00
Monitor.PulseAll(types);
2006-07-06 17:53:51 +04:00
}
}
}
2006-03-11 21:35:29 +03:00
2006-07-26 18:16:52 +04:00
internal TypeWrapperFactory GetTypeWrapperFactory()
{
2006-07-06 17:53:51 +04:00
#if COMPACT_FRAMEWORK
throw new NoClassDefFoundError("Class loading is not supported on the Compact Framework");
#else
2006-09-12 13:57:36 +04:00
if(factory == null)
{
lock(this)
{
if(factory == null)
{
#if CLASSGC
if(dynamicAssemblies == null)
{
Interlocked.CompareExchange(ref dynamicAssemblies, new ConditionalWeakTable<Assembly, ClassLoaderWrapper>(), null);
}
typeToTypeWrapper = new Dictionary<Type, TypeWrapper>();
DynamicClassLoader instance = DynamicClassLoader.Get(this);
dynamicAssemblies.Add(instance.ModuleBuilder.Assembly.ManifestModule.Assembly, this);
this.factory = instance;
#else
factory = DynamicClassLoader.Get(this);
#endif
}
}
2006-09-12 13:57:36 +04:00
}
return factory;
2006-07-06 17:53:51 +04:00
#endif
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper LoadClassByDottedName(string name)
2003-03-17 17:02:46 +03:00
{
2006-07-11 15:34:44 +04:00
TypeWrapper type = LoadClassByDottedNameFastImpl(name, true);
2005-06-01 13:49:30 +04:00
if(type != null)
{
2006-07-11 15:34:44 +04:00
return RegisterInitiatingLoader(type);
2005-06-01 13:49:30 +04:00
}
throw new ClassNotFoundException(name);
2003-03-17 17:02:46 +03:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper LoadClassByDottedNameFast(string name)
2005-08-25 11:46:57 +04:00
{
2006-07-11 15:34:44 +04:00
TypeWrapper type = LoadClassByDottedNameFastImpl(name, false);
if(type != null)
{
return RegisterInitiatingLoader(type);
}
return null;
2005-08-25 11:46:57 +04:00
}
2006-07-10 18:40:31 +04:00
private TypeWrapper LoadClassByDottedNameFastImpl(string name, bool throwClassNotFoundException)
2003-02-15 12:20:26 +03:00
{
2005-06-01 13:49:30 +04:00
// .NET 1.1 has a limit of 1024 characters for type names
2006-05-15 13:08:01 +04:00
if(name.Length >= 1024 || name.Length == 0)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return null;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
Profiler.Enter("LoadClassByDottedName");
try
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper type;
2008-08-15 16:01:06 +04:00
lock(types)
2002-12-18 19:00:25 +03:00
{
if(types.TryGetValue(name, out type) && type == null)
2003-08-26 15:24:17 +04:00
{
2008-08-15 16:01:06 +04:00
Thread defineThread;
if(defineClassInProgress.TryGetValue(name, out defineThread))
2006-07-10 13:37:06 +04:00
{
2006-10-10 20:24:48 +04:00
if(Thread.CurrentThread == defineThread)
2006-07-11 15:34:44 +04:00
{
throw new ClassCircularityError(name);
}
2006-10-10 20:24:48 +04:00
// the requested class is currently being defined by another thread,
// so we have to wait on that
while(defineClassInProgress.ContainsKey(name))
{
2008-08-15 16:01:06 +04:00
Monitor.Wait(types);
2006-10-10 20:24:48 +04:00
}
2008-08-15 16:01:06 +04:00
// the defineClass may have failed, so we need to use TryGetValue
types.TryGetValue(name, out type);
2006-07-10 13:37:06 +04:00
}
2003-08-26 15:24:17 +04:00
}
2006-07-11 15:34:44 +04:00
}
2006-10-10 20:24:48 +04:00
if(type != null)
{
return type;
}
2006-07-11 15:34:44 +04:00
if(name.Length > 1 && name[0] == '[')
{
return LoadArrayClass(name);
2005-06-01 13:49:30 +04:00
}
2006-07-10 18:40:31 +04:00
return LoadClassImpl(name, throwClassNotFoundException);
2006-07-10 13:37:06 +04:00
}
finally
{
Profiler.Leave("LoadClassByDottedName");
}
}
2006-07-11 15:34:44 +04:00
private TypeWrapper LoadArrayClass(string name)
{
int dims = 1;
while(name[dims] == '[')
{
dims++;
if(dims == name.Length)
{
// malformed class name
return null;
}
}
if(name[dims] == 'L')
{
if(!name.EndsWith(";") || name.Length <= dims + 2 || name[dims + 1] == '[')
{
// malformed class name
return null;
}
string elemClass = name.Substring(dims + 1, name.Length - dims - 2);
// NOTE it's important that we're registered as the initiating loader
// for the element type here
TypeWrapper type = LoadClassByDottedNameFast(elemClass);
if(type != null)
{
type = type.GetClassLoader().CreateArrayType(name, type, dims);
}
return type;
}
if(name.Length != dims + 1)
{
// malformed class name
return null;
}
switch(name[dims])
{
case 'B':
return GetBootstrapClassLoader().CreateArrayType(name, PrimitiveTypeWrapper.BYTE, dims);
case 'C':
return GetBootstrapClassLoader().CreateArrayType(name, PrimitiveTypeWrapper.CHAR, dims);
case 'D':
return GetBootstrapClassLoader().CreateArrayType(name, PrimitiveTypeWrapper.DOUBLE, dims);
case 'F':
return GetBootstrapClassLoader().CreateArrayType(name, PrimitiveTypeWrapper.FLOAT, dims);
case 'I':
return GetBootstrapClassLoader().CreateArrayType(name, PrimitiveTypeWrapper.INT, dims);
case 'J':
return GetBootstrapClassLoader().CreateArrayType(name, PrimitiveTypeWrapper.LONG, dims);
case 'S':
return GetBootstrapClassLoader().CreateArrayType(name, PrimitiveTypeWrapper.SHORT, dims);
case 'Z':
return GetBootstrapClassLoader().CreateArrayType(name, PrimitiveTypeWrapper.BOOLEAN, dims);
default:
return null;
}
}
internal TypeWrapper LoadGenericClass(string name)
2006-07-21 14:18:13 +04:00
{
// generic class name grammar:
//
2006-07-26 11:57:18 +04:00
// mangled(open_generic_type_name) "_$$$_" M(parameter_class_name) ( "_$$_" M(parameter_class_name) )* "_$$$$_"
//
// mangled() is the normal name mangling algorithm
// M() is a replacement of "__" with "$$005F$$005F" followed by a replace of "." with "__"
//
2006-07-21 14:18:13 +04:00
int pos = name.IndexOf("_$$$_");
if(pos <= 0 || !name.EndsWith("_$$$$_"))
2006-07-21 14:18:13 +04:00
{
return null;
}
Type type = GetGenericTypeDefinition(DotNetTypeWrapper.DemangleTypeName(name.Substring(0, pos)));
if(type == null)
2006-07-21 14:18:13 +04:00
{
return null;
}
2008-08-15 16:01:06 +04:00
List<string> typeParamNames = new List<string>();
2006-07-21 14:18:13 +04:00
pos += 5;
int start = pos;
int nest = 0;
for(;;)
{
pos = name.IndexOf("_$$", pos);
if(pos == -1)
{
return null;
}
if(name.IndexOf("_$$_", pos, 4) == pos)
{
if(nest == 0)
{
typeParamNames.Add(name.Substring(start, pos - start));
start = pos + 4;
}
pos += 4;
}
else if(name.IndexOf("_$$$_", pos, 5) == pos)
{
nest++;
pos += 5;
}
else if(name.IndexOf("_$$$$_", pos, 6) == pos)
{
if(nest == 0)
{
if(pos + 6 != name.Length)
{
return null;
}
typeParamNames.Add(name.Substring(start, pos - start));
break;
}
nest--;
pos += 6;
}
else
{
pos += 3;
}
}
Type[] typeArguments = new Type[typeParamNames.Count];
for(int i = 0; i < typeArguments.Length; i++)
{
2006-07-26 11:57:18 +04:00
string s = (string)typeParamNames[i];
// 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", "__");
}
2006-07-26 11:57:18 +04:00
int dims = 0;
while(s.Length > dims && s[dims] == 'A')
{
dims++;
}
if(s.Length == dims)
{
return null;
}
TypeWrapper tw = null;
switch(s[dims])
{
case 'L':
tw = LoadClassByDottedNameFast(s.Substring(dims + 1));
tw.Finish();
2006-07-26 11:57:18 +04:00
break;
case 'Z':
tw = PrimitiveTypeWrapper.BOOLEAN;
break;
case 'B':
tw = PrimitiveTypeWrapper.BYTE;
break;
case 'S':
tw = PrimitiveTypeWrapper.SHORT;
break;
case 'C':
tw = PrimitiveTypeWrapper.CHAR;
break;
case 'I':
tw = PrimitiveTypeWrapper.INT;
break;
case 'F':
tw = PrimitiveTypeWrapper.FLOAT;
break;
case 'J':
tw = PrimitiveTypeWrapper.LONG;
break;
case 'D':
tw = PrimitiveTypeWrapper.DOUBLE;
break;
}
2006-07-21 14:18:13 +04:00
if(tw == null)
{
return null;
}
2006-07-26 11:57:18 +04:00
if(dims > 0)
{
tw = tw.MakeArrayType(dims);
}
2006-07-21 14:18:13 +04:00
typeArguments[i] = tw.TypeAsSignatureType;
}
2006-07-27 18:44:51 +04:00
try
{
2007-11-26 12:01:35 +03:00
type = type.MakeGenericType(typeArguments);
2006-07-27 18:44:51 +04:00
}
catch(ArgumentException)
{
// one of the typeArguments failed to meet the constraints
return null;
}
TypeWrapper wrapper = GetWrapperFromType(type);
if(wrapper != null && wrapper.Name != name)
{
// the name specified was not in canonical form
return null;
}
return wrapper;
2006-07-21 14:18:13 +04:00
}
2006-07-10 13:37:06 +04:00
protected virtual TypeWrapper LoadClassImpl(string name, bool throwClassNotFoundException)
{
TypeWrapper tw = LoadGenericClass(name);
if(tw != null)
{
return tw;
}
#if !STATIC_COMPILER && !FIRST_PASS
2006-08-06 13:27:20 +04:00
Profiler.Enter("ClassLoader.loadClass");
try
2006-07-10 13:37:06 +04:00
{
java.lang.Class c = javaClassLoader.loadClassInternal(name);
if(c == null)
{
return null;
}
TypeWrapper type = TypeWrapper.FromClass(c);
if(type.Name != name)
2006-08-21 09:15:51 +04:00
{
// the class loader is trying to trick us
return null;
}
#if CLASSGC
// FXBUG because the AppDomain.TypeResolve event still doesn't work across assemblies
// (at least as of .NET 4.0 beta 1), we eagerly finish types loaded by another class loader
if(type.GetClassLoader() != this)
{
try
{
type.Finish();
}
catch(RetargetableJavaException x)
{
throw x.ToJava();
}
}
#endif
return type;
2006-08-06 13:27:20 +04:00
}
catch(java.lang.ClassNotFoundException x)
2006-08-06 13:27:20 +04:00
{
if(throwClassNotFoundException)
2006-03-11 21:35:29 +03:00
{
throw new ClassLoadingException(ikvm.runtime.Util.mapException(x));
2002-12-29 19:27:00 +03:00
}
return null;
}
catch(Exception x)
{
throw new ClassLoadingException(ikvm.runtime.Util.mapException(x));
2006-08-06 13:27:20 +04:00
}
finally
{
Profiler.Leave("ClassLoader.loadClass");
2006-07-10 13:37:06 +04:00
}
2006-04-10 13:09:09 +04:00
#else
2006-07-10 13:37:06 +04:00
return null;
2006-04-10 13:09:09 +04:00
#endif
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE this method can actually return null if the resulting array type name would be too long
// for .NET to handle.
private TypeWrapper CreateArrayType(string name, TypeWrapper elementTypeWrapper, int dims)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(new String('[', dims) + elementTypeWrapper.SigName == name);
Debug.Assert(!elementTypeWrapper.IsUnloadable && !elementTypeWrapper.IsVerifierType && !elementTypeWrapper.IsArray);
Debug.Assert(dims >= 1);
Type elementType = elementTypeWrapper.TypeAsArrayType;
2006-07-11 11:29:32 +04:00
// .NET 1.1 has a limit of 1024 characters for type names
if(elementType.FullName.Length >= 1024 - dims * 2)
{
return null;
}
2006-07-27 18:44:51 +04:00
return RegisterInitiatingLoader(new ArrayTypeWrapper(elementTypeWrapper, name));
2005-06-01 13:49:30 +04:00
}
internal object GetJavaClassLoader()
2003-12-20 01:19:18 +03:00
{
#if FIRST_PASS || STATIC_COMPILER
return null;
#else
2006-06-28 12:07:29 +04:00
return javaClassLoader;
#endif
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper ExpressionTypeWrapper(string type)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(!type.StartsWith("Lret;"));
Debug.Assert(type != "Lnull");
int index = 0;
return SigDecoderWrapper(ref index, type);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE this exposes potentially unfinished types
internal Type[] ArgTypeListFromSig(string sig)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(sig[1] == ')')
{
2005-12-07 12:06:32 +03:00
#if COMPACT_FRAMEWORK
return new Type[0];
#else
2005-06-01 13:49:30 +04:00
return Type.EmptyTypes;
2005-12-07 12:06:32 +03:00
#endif
2005-06-01 13:49:30 +04:00
}
TypeWrapper[] wrappers = ArgTypeWrapperListFromSig(sig);
Type[] types = new Type[wrappers.Length];
for(int i = 0; i < wrappers.Length; i++)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
types[i] = wrappers[i].TypeAsSignatureType;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
return types;
}
// NOTE: this will ignore anything following the sig marker (so that it can be used to decode method signatures)
private TypeWrapper SigDecoderWrapper(ref int index, string sig)
{
switch(sig[index++])
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
case 'B':
return PrimitiveTypeWrapper.BYTE;
case 'C':
return PrimitiveTypeWrapper.CHAR;
case 'D':
return PrimitiveTypeWrapper.DOUBLE;
case 'F':
return PrimitiveTypeWrapper.FLOAT;
case 'I':
return PrimitiveTypeWrapper.INT;
case 'J':
return PrimitiveTypeWrapper.LONG;
case 'L':
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
int pos = index;
index = sig.IndexOf(';', index) + 1;
return LoadClassByDottedName(sig.Substring(pos, index - pos - 1));
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
case 'S':
return PrimitiveTypeWrapper.SHORT;
case 'Z':
return PrimitiveTypeWrapper.BOOLEAN;
case 'V':
return PrimitiveTypeWrapper.VOID;
case '[':
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO this can be optimized
string array = "[";
while(sig[index] == '[')
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
index++;
array += "[";
}
switch(sig[index])
{
case 'L':
{
int pos = index;
index = sig.IndexOf(';', index) + 1;
return LoadClassByDottedName(array + sig.Substring(pos, index - pos));
}
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 'Z':
return LoadClassByDottedName(array + sig[index++]);
default:
throw new InvalidOperationException(sig.Substring(index));
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
default:
throw new InvalidOperationException(sig.Substring(index));
2002-12-18 19:00:25 +03:00
}
}
2004-03-16 20:10:09 +03:00
2005-06-01 13:49:30 +04:00
internal TypeWrapper FieldTypeWrapperFromSig(string sig)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
int index = 0;
return SigDecoderWrapper(ref index, sig);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper RetTypeWrapperFromSig(string sig)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
int index = sig.IndexOf(')') + 1;
return SigDecoderWrapper(ref index, sig);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper[] ArgTypeWrapperListFromSig(string sig)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(sig[1] == ')')
{
return TypeWrapper.EmptyArray;
}
2008-08-15 16:01:06 +04:00
List<TypeWrapper> list = new List<TypeWrapper>();
2005-06-01 13:49:30 +04:00
for(int i = 1; sig[i] != ')';)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
list.Add(SigDecoderWrapper(ref i, sig));
2004-08-17 13:05:21 +04:00
}
2008-08-15 16:01:06 +04:00
return list.ToArray();
2002-12-18 19:00:25 +03:00
}
2004-09-09 15:17:55 +04:00
2006-08-14 11:57:03 +04:00
#if STATIC_COMPILER
2005-06-01 13:49:30 +04:00
internal static ClassLoaderWrapper GetBootstrapClassLoader()
2006-08-14 11:57:03 +04:00
#else
internal static AssemblyClassLoader GetBootstrapClassLoader()
#endif
2004-10-04 23:30:53 +04:00
{
2006-03-23 14:57:41 +03:00
lock(wrapperLock)
2005-06-01 13:49:30 +04:00
{
if(bootstrapClassLoader == null)
{
bootstrapClassLoader = new BootstrapClassLoader();
2005-06-01 13:49:30 +04:00
}
return bootstrapClassLoader;
}
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
2006-04-10 13:09:09 +04:00
#if !STATIC_COMPILER
2005-06-01 13:49:30 +04:00
internal static ClassLoaderWrapper GetClassLoaderWrapper(object javaClassLoader)
2002-12-18 19:00:25 +03:00
{
2006-06-28 12:07:29 +04:00
if(javaClassLoader == null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
return GetBootstrapClassLoader();
}
2005-09-06 12:06:04 +04:00
lock(wrapperLock)
2005-06-01 13:49:30 +04:00
{
#if FIRST_PASS
ClassLoaderWrapper wrapper = null;
#else
ClassLoaderWrapper wrapper =
#if __MonoCS__
// MONOBUG the redundant cast to ClassLoaderWrapper is to workaround an mcs bug
(ClassLoaderWrapper)(object)
#endif
((java.lang.ClassLoader)javaClassLoader).wrapper;
#endif
2005-06-01 13:49:30 +04:00
if(wrapper == null)
{
2006-09-01 11:53:36 +04:00
CodeGenOptions opt = CodeGenOptions.None;
if(JVM.EmitSymbols)
2006-09-01 11:53:36 +04:00
{
opt |= CodeGenOptions.Debug;
}
wrapper = new ClassLoaderWrapper(opt, javaClassLoader);
SetWrapperForClassLoader(javaClassLoader, wrapper);
2005-06-01 13:49:30 +04:00
}
return wrapper;
2004-08-17 13:05:21 +04:00
}
2002-12-18 19:00:25 +03:00
}
2006-04-10 13:09:09 +04:00
#endif
2002-12-18 19:00:25 +03:00
#if CLASSGC
internal static ClassLoaderWrapper GetClassLoaderForDynamicJavaAssembly(Assembly asm)
{
ClassLoaderWrapper loader;
dynamicAssemblies.TryGetValue(asm, out loader);
return loader;
}
#endif // CLASSGC
2006-07-11 11:29:32 +04:00
internal static TypeWrapper GetWrapperFromType(Type type)
2002-12-18 19:00:25 +03:00
{
2006-07-11 11:29:32 +04:00
//Tracer.Info(Tracer.Runtime, "GetWrapperFromType: {0}", type.AssemblyQualifiedName);
2005-06-01 13:49:30 +04:00
TypeWrapper.AssertFinished(type);
2007-11-26 12:01:35 +03:00
Debug.Assert(!type.ContainsGenericParameters);
2006-07-11 11:29:32 +04:00
Debug.Assert(!type.IsPointer);
Debug.Assert(!type.IsByRef);
2008-08-15 16:01:06 +04:00
TypeWrapper wrapper;
lock(globalTypeToTypeWrapper)
2008-08-15 16:01:06 +04:00
{
globalTypeToTypeWrapper.TryGetValue(type, out wrapper);
2008-08-15 16:01:06 +04:00
}
2006-07-11 11:29:32 +04:00
if(wrapper != null)
2003-02-15 21:52:32 +03:00
{
2006-07-11 11:29:32 +04:00
return wrapper;
2003-02-15 21:52:32 +03:00
}
2008-08-15 16:01:06 +04:00
string remapped;
if(remappedTypes.TryGetValue(type, out remapped))
2003-02-17 13:13:16 +03:00
{
2006-07-11 11:29:32 +04:00
wrapper = LoadClassCritical(remapped);
}
2007-01-16 13:14:47 +03:00
else if(IsVector(type))
2006-07-11 11:29:32 +04:00
{
// it might be an array of a dynamically compiled Java type
int rank = 1;
Type elem = type.GetElementType();
2007-01-16 13:14:47 +03:00
while(IsVector(elem))
2003-02-17 13:13:16 +03:00
{
2006-07-11 11:29:32 +04:00
rank++;
elem = elem.GetElementType();
2003-02-17 13:13:16 +03:00
}
2006-07-11 11:29:32 +04:00
wrapper = GetWrapperFromType(elem).MakeArrayType(rank);
}
else
{
Assembly asm = type.Assembly;
#if CLASSGC
ClassLoaderWrapper loader;
if(dynamicAssemblies != null && dynamicAssemblies.TryGetValue(asm, out loader))
{
lock(loader.typeToTypeWrapper)
{
return loader.typeToTypeWrapper[type];
}
}
#endif
2005-06-01 13:49:30 +04:00
// if the wrapper doesn't already exist, that must mean that the type
// is a .NET type (or a pre-compiled Java class), which means that it
2006-05-15 13:08:01 +04:00
// was "loaded" by an assembly classloader
wrapper = GetAssemblyClassLoader(asm).GetWrapperFromAssemblyType(type);
2003-02-17 13:13:16 +03:00
}
#if CLASSGC
if(type.Assembly.IsDynamic())
2008-08-15 16:01:06 +04:00
{
// don't cache types in dynamic assemblies, because they might live in a RunAndCollect assembly
// TODO we also shouldn't cache generic type instances that have a GCable type parameter
return wrapper;
}
#endif
lock(globalTypeToTypeWrapper)
{
globalTypeToTypeWrapper[type] = wrapper;
2008-08-15 16:01:06 +04:00
}
2005-06-01 13:49:30 +04:00
return wrapper;
2002-12-18 19:00:25 +03:00
}
internal static bool IsVector(Type type)
2007-01-16 13:14:47 +03:00
{
// NOTE it looks like there's no API to distinguish an array of rank 1 from a vector,
// so we check if the type name ends in [], which indicates it's a vector
// (non-vectors will have [*] or [,]).
return type.IsArray && type.Name.EndsWith("[]");
}
internal virtual Type GetGenericTypeDefinition(string name)
2006-07-21 14:18:13 +04:00
{
return null;
}
2006-07-26 14:33:52 +04:00
internal static ClassLoaderWrapper GetGenericClassLoader(TypeWrapper wrapper)
{
Type type = wrapper.TypeAsTBD;
2007-11-26 12:01:35 +03:00
Debug.Assert(type.IsGenericType);
Debug.Assert(!type.ContainsGenericParameters);
2006-07-26 14:33:52 +04:00
2008-08-15 16:01:06 +04:00
List<ClassLoaderWrapper> list = new List<ClassLoaderWrapper>();
2006-07-26 14:33:52 +04:00
list.Add(GetAssemblyClassLoader(type.Assembly));
2007-11-26 12:01:35 +03:00
foreach(Type arg in type.GetGenericArguments())
2006-07-26 14:33:52 +04:00
{
ClassLoaderWrapper loader = GetWrapperFromType(arg).GetClassLoader();
if(!list.Contains(loader))
{
list.Add(loader);
}
}
2008-08-15 16:01:06 +04:00
ClassLoaderWrapper[] key = list.ToArray();
ClassLoaderWrapper matchingLoader = GetGenericClassLoaderByKey(key);
matchingLoader.RegisterInitiatingLoader(wrapper);
return matchingLoader;
}
#if !STATIC_COMPILER && !FIRST_PASS
internal static object DoPrivileged(java.security.PrivilegedAction action)
{
return java.security.AccessController.doPrivileged(action, ikvm.@internal.CallerID.create(typeof(java.lang.ClassLoader).TypeHandle));
}
#endif
private static ClassLoaderWrapper GetGenericClassLoaderByKey(ClassLoaderWrapper[] key)
{
2006-07-26 14:33:52 +04:00
lock(wrapperLock)
{
if(genericClassLoaders == null)
{
2008-08-15 16:01:06 +04:00
genericClassLoaders = new List<GenericClassLoader>();
2006-07-26 14:33:52 +04:00
}
foreach(GenericClassLoader loader in genericClassLoaders)
{
if(loader.Matches(key))
{
return loader;
2006-07-26 14:33:52 +04:00
}
}
object javaClassLoader = null;
#if !STATIC_COMPILER && !FIRST_PASS
javaClassLoader = DoPrivileged(new CreateAssemblyClassLoader(null));
2006-08-14 11:57:03 +04:00
#endif
GenericClassLoader newLoader = new GenericClassLoader(key, javaClassLoader);
SetWrapperForClassLoader(javaClassLoader, newLoader);
genericClassLoaders.Add(newLoader);
return newLoader;
}
}
#if !STATIC_COMPILER && __MonoCS__
// MONOBUG this weird hack is to work around an mcs bug
private static void SetClassLoadWrapperHack<T>(ref T field, ClassLoaderWrapper wrapper)
{
field = (T)(object)wrapper;
}
#endif
private static void SetWrapperForClassLoader(object javaClassLoader, ClassLoaderWrapper wrapper)
{
#if !STATIC_COMPILER && !FIRST_PASS
#if __MonoCS__
SetClassLoadWrapperHack(ref ((java.lang.ClassLoader)javaClassLoader).wrapper, wrapper);
#else
((java.lang.ClassLoader)javaClassLoader).wrapper = wrapper;
#endif
#endif
}
internal static ClassLoaderWrapper GetGenericClassLoaderByName(string name)
{
Debug.Assert(name.StartsWith("[[") && name.EndsWith("]]"));
2008-08-15 16:01:06 +04:00
Stack<List<ClassLoaderWrapper>> stack = new Stack<List<ClassLoaderWrapper>>();
List<ClassLoaderWrapper> list = null;
for(int i = 0; i < name.Length; i++)
{
if(name[i] == '[')
{
if(name[i + 1] == '[')
{
stack.Push(list);
2008-08-15 16:01:06 +04:00
list = new List<ClassLoaderWrapper>();
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] == ']')
{
2008-08-15 16:01:06 +04:00
ClassLoaderWrapper loader = GetGenericClassLoaderByKey(list.ToArray());
list = stack.Pop();
if(list == null)
{
return loader;
}
list.Add(loader);
}
else
{
throw new InvalidOperationException();
2006-07-26 14:33:52 +04:00
}
}
throw new InvalidOperationException();
}
internal static ClassLoaderWrapper GetAssemblyClassLoaderByName(string name)
{
if(name.StartsWith("[["))
{
return GetGenericClassLoaderByName(name);
}
#if STATIC_COMPILER
return ClassLoaderWrapper.GetAssemblyClassLoader(Assembly.ReflectionOnlyLoad(name));
#else
return ClassLoaderWrapper.GetAssemblyClassLoader(Assembly.Load(name));
#endif
2006-07-26 14:33:52 +04:00
}
2006-12-05 10:52:25 +03:00
internal static int GetGenericClassLoaderId(ClassLoaderWrapper wrapper)
{
lock(wrapperLock)
{
2008-08-15 16:01:06 +04:00
return genericClassLoaders.IndexOf(wrapper as GenericClassLoader);
2006-12-05 10:52:25 +03:00
}
}
internal static ClassLoaderWrapper GetGenericClassLoaderById(int id)
{
lock(wrapperLock)
{
2008-08-15 16:01:06 +04:00
return genericClassLoaders[id];
2006-12-05 10:52:25 +03:00
}
}
2006-05-15 13:08:01 +04:00
// this method only supports .NET or pre-compiled Java assemblies
2006-08-14 11:57:03 +04:00
internal static AssemblyClassLoader GetAssemblyClassLoader(Assembly assembly)
2006-05-15 13:08:01 +04:00
{
#if !COMPACT_FRAMEWORK && !IKVM_REF_EMIT
2006-05-15 13:08:01 +04:00
Debug.Assert(!(assembly is AssemblyBuilder));
2006-07-06 17:53:51 +04:00
#endif // !COMPACT_FRAMEWORK
2006-05-15 13:08:01 +04:00
ConstructorInfo customClassLoaderCtor = null;
AssemblyClassLoader loader;
object javaClassLoader = null;
2006-08-14 11:57:03 +04:00
lock(wrapperLock)
2006-05-15 13:08:01 +04:00
{
2008-08-15 16:01:06 +04:00
if(!assemblyClassLoaders.TryGetValue(assembly, out loader))
2006-05-15 13:08:01 +04:00
{
// If the assembly is a part of a multi-assembly shared class loader,
// it will export the __<MainAssembly> type from the main assembly in the group.
Type forwarder = assembly.GetType("__<MainAssembly>");
if(forwarder != null)
{
Assembly mainAssembly = forwarder.Assembly;
if(mainAssembly != assembly)
{
loader = GetAssemblyClassLoader(mainAssembly);
assemblyClassLoaders[assembly] = loader;
return loader;
}
}
if(assembly == JVM.CoreAssembly)
{
// 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
2007-11-26 12:01:35 +03:00
if(!assembly.ReflectionOnly)
{
Type customClassLoaderClass = null;
LoadCustomClassLoaderRedirects();
if(customClassLoaderRedirects != null)
{
string assemblyName = assembly.FullName;
2008-08-15 16:01:06 +04:00
foreach(KeyValuePair<string, string> kv in customClassLoaderRedirects)
{
2008-08-15 16:01:06 +04:00
string asm = kv.Key;
// we only support matching on the assembly's simple name,
// because there appears to be no viable alternative.
// On .NET 2.0 there is AssemblyName.ReferenceMatchesDefinition()
// but it is broken (and .NET 2.0 specific).
if(assemblyName.StartsWith(asm + ","))
{
try
{
2008-08-15 16:01:06 +04:00
customClassLoaderClass = Type.GetType(kv.Value, true);
}
catch(Exception x)
{
2008-08-15 16:01:06 +04:00
Tracer.Error(Tracer.Runtime, "Unable to load custom class loader {0} specified in app.config for assembly {1}: {2}", kv.Value, assembly, x);
}
break;
}
}
}
if(customClassLoaderClass == null)
{
object[] attribs = assembly.GetCustomAttributes(typeof(CustomAssemblyClassLoaderAttribute), false);
if(attribs.Length == 1)
{
customClassLoaderClass = ((CustomAssemblyClassLoaderAttribute)attribs[0]).Type;
}
}
if(customClassLoaderClass != null)
{
try
{
if(!customClassLoaderClass.IsPublic && !customClassLoaderClass.Assembly.Equals(assembly))
{
throw new Exception("Type not accessible");
}
// NOTE we're creating an uninitialized instance of the custom class loader here, so that getClassLoader will return the proper object
// when it is called during the construction of the custom class loader later on. This still doesn't make it safe to use the custom
// class loader before it is constructed, but at least the object instance is valid and should anyone cache it, they will get the
// right object to use later on.
// Note also that we're not running the constructor here, because we don't want to run user code while holding a global lock.
javaClassLoader = (java.lang.ClassLoader)CreateUnitializedCustomClassLoader(customClassLoaderClass);
customClassLoaderCtor = customClassLoaderClass.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Assembly) }, null);
if(customClassLoaderCtor == null)
{
javaClassLoader = null;
throw new Exception("No constructor");
}
if(!customClassLoaderCtor.IsPublic && !customClassLoaderClass.Assembly.Equals(assembly))
{
javaClassLoader = null;
throw new Exception("Constructor not accessible");
}
Tracer.Info(Tracer.Runtime, "Created custom assembly class loader {0} for assembly {1}", customClassLoaderClass.FullName, assembly);
}
catch(Exception x)
{
Tracer.Error(Tracer.Runtime, "Unable to create custom assembly class loader {0} for {1}: {2}", customClassLoaderClass.FullName, assembly, x);
}
}
}
if(javaClassLoader == null)
2006-08-14 11:57:03 +04:00
{
javaClassLoader = DoPrivileged(new CreateAssemblyClassLoader(assembly));
2006-08-14 11:57:03 +04:00
}
#endif
loader = new AssemblyClassLoader(assembly, javaClassLoader, customClassLoaderCtor != null);
2006-08-14 11:57:03 +04:00
assemblyClassLoaders[assembly] = loader;
#if !STATIC_COMPILER
if(customClassLoaderCtor != null)
{
loader.SetInitInProgress();
}
2006-08-14 11:57:03 +04:00
if(javaClassLoader != null)
{
SetWrapperForClassLoader(javaClassLoader, loader);
2006-08-14 11:57:03 +04:00
}
#endif
2006-05-15 13:08:01 +04:00
}
}
#if !STATIC_COMPILER && !FIRST_PASS
if(customClassLoaderCtor != null)
{
try
{
DoPrivileged(new CustomClassLoaderCtorCaller(customClassLoaderCtor, javaClassLoader, assembly));
}
finally
{
loader.SetInitDone();
}
}
loader.WaitInitDone();
#endif
return loader;
}
#if !STATIC_COMPILER && !FIRST_PASS
private static object CreateUnitializedCustomClassLoader(Type customClassLoaderClass)
{
return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(customClassLoaderClass);
}
private static void LoadCustomClassLoaderRedirects()
{
// this method assumes that we hold a global lock
if(!customClassLoaderRedirectsLoaded)
{
customClassLoaderRedirectsLoaded = true;
try
{
foreach(string key in System.Configuration.ConfigurationManager.AppSettings.AllKeys)
{
const string prefix = "ikvm-classloader:";
if(key.StartsWith(prefix))
{
if(customClassLoaderRedirects == null)
{
2008-08-15 16:01:06 +04:00
customClassLoaderRedirects = new Dictionary<string, string>();
}
customClassLoaderRedirects[key.Substring(prefix.Length)] = System.Configuration.ConfigurationManager.AppSettings.Get(key);
}
}
}
catch(Exception x)
{
Tracer.Error(Tracer.Runtime, "Error while reading custom class loader redirects: {0}", x);
}
2006-05-15 13:08:01 +04:00
}
}
sealed class CreateAssemblyClassLoader : java.security.PrivilegedAction
{
private Assembly assembly;
internal CreateAssemblyClassLoader(Assembly assembly)
{
this.assembly = assembly;
}
public object run()
{
return new ikvm.runtime.AssemblyClassLoader(assembly);
}
}
sealed class CustomClassLoaderCtorCaller : java.security.PrivilegedAction
{
private ConstructorInfo ctor;
private object classLoader;
private Assembly assembly;
internal CustomClassLoaderCtorCaller(ConstructorInfo ctor, object classLoader, Assembly assembly)
{
this.ctor = ctor;
this.classLoader = classLoader;
this.assembly = assembly;
}
public object run()
{
ctor.Invoke(classLoader, new object[] { assembly });
return null;
}
}
#endif
internal void SetWrapperForType(Type type, TypeWrapper wrapper)
2005-06-01 13:49:30 +04:00
{
TypeWrapper.AssertFinished(type);
Dictionary<Type, TypeWrapper> dict;
#if CLASSGC
dict = typeToTypeWrapper ?? globalTypeToTypeWrapper;
#else
dict = globalTypeToTypeWrapper;
#endif
lock (dict)
2008-08-15 16:01:06 +04:00
{
dict.Add(type, wrapper);
2008-08-15 16:01:06 +04:00
}
2007-08-08 16:50:48 +04:00
}
2005-06-01 13:49:30 +04:00
internal static TypeWrapper LoadClassCritical(string name)
2003-12-24 14:51:41 +03:00
{
2005-06-01 13:49:30 +04:00
try
{
return GetBootstrapClassLoader().LoadClassByDottedName(name);
}
catch(Exception x)
{
JVM.CriticalFailure("Loading of critical class failed", x);
return null;
}
2003-12-24 14:51:41 +03:00
}
2004-08-30 19:56:23 +04:00
2005-06-01 13:49:30 +04:00
internal void RegisterNativeLibrary(IntPtr p)
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
lock(this)
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
if(nativeLibraries == null)
{
2008-08-15 16:01:06 +04:00
nativeLibraries = new List<IntPtr>();
2005-06-01 13:49:30 +04:00
}
nativeLibraries.Add(p);
2004-08-30 19:56:23 +04:00
}
}
internal void UnregisterNativeLibrary(IntPtr p)
{
lock(this)
{
nativeLibraries.Remove(p);
}
}
2005-06-01 13:49:30 +04:00
internal IntPtr[] GetNativeLibraries()
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
lock(this)
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
if(nativeLibraries == null)
{
return new IntPtr[0];
}
2008-08-15 16:01:06 +04:00
return nativeLibraries.ToArray();
2004-08-30 19:56:23 +04:00
}
}
2005-02-23 15:56:15 +03:00
#if !STATIC_COMPILER && !FIRST_PASS
2005-06-01 13:49:30 +04:00
public override string ToString()
2005-02-23 15:56:15 +03:00
{
2005-06-01 13:49:30 +04:00
if(javaClassLoader == null)
{
return "null";
}
return String.Format("{0}@{1:X}", GetWrapperFromType(javaClassLoader.GetType()).Name, javaClassLoader.GetHashCode());
2005-02-23 15:56:15 +03:00
}
#endif
internal virtual bool InternalsVisibleToImpl(TypeWrapper wrapper, TypeWrapper friend)
{
Debug.Assert(wrapper.GetClassLoader() == this);
return this == friend.GetClassLoader();
}
2005-02-23 15:56:15 +03:00
}
2006-02-22 17:44:07 +03:00
2006-08-14 11:57:03 +04:00
class GenericClassLoader : ClassLoaderWrapper
2006-02-22 17:44:07 +03:00
{
2006-08-14 11:57:03 +04:00
private ClassLoaderWrapper[] delegates;
internal GenericClassLoader(ClassLoaderWrapper[] delegates, object javaClassLoader)
2006-09-01 11:53:36 +04:00
: base(CodeGenOptions.None, javaClassLoader)
2006-02-22 17:44:07 +03:00
{
2006-08-14 11:57:03 +04:00
this.delegates = delegates;
2006-02-22 17:44:07 +03:00
}
2006-07-10 13:37:06 +04:00
2006-08-14 11:57:03 +04:00
internal bool Matches(ClassLoaderWrapper[] key)
2006-07-10 13:37:06 +04:00
{
2006-08-14 11:57:03 +04:00
if(key.Length == delegates.Length)
2006-07-10 13:37:06 +04:00
{
2006-08-14 11:57:03 +04:00
for(int i = 0; i < key.Length; i++)
{
if(key[i] != delegates[i])
{
return false;
}
}
return true;
2006-07-10 13:37:06 +04:00
}
2006-08-14 11:57:03 +04:00
return false;
2006-07-10 13:37:06 +04:00
}
internal override Type GetGenericTypeDefinition(string name)
2006-07-10 13:37:06 +04:00
{
2006-08-14 11:57:03 +04:00
foreach(ClassLoaderWrapper loader in delegates)
2006-07-10 13:37:06 +04:00
{
Type t = loader.GetGenericTypeDefinition(name);
2006-08-14 11:57:03 +04:00
if(t != null)
{
return t;
}
2006-07-10 13:37:06 +04:00
}
2006-08-14 11:57:03 +04:00
return null;
}
protected override TypeWrapper LoadClassImpl(string name, bool throwClassNotFoundException)
{
TypeWrapper tw = LoadGenericClass(name);
if(tw != null)
{
return tw;
}
2006-08-14 11:57:03 +04:00
foreach(ClassLoaderWrapper loader in delegates)
2006-07-10 13:37:06 +04:00
{
tw = loader.LoadClassByDottedNameFast(name);
2006-08-14 11:57:03 +04:00
if(tw != null)
{
return tw;
}
2006-07-10 13:37:06 +04:00
}
2006-08-14 11:57:03 +04:00
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).MainAssembly.FullName);
}
sb.Append(']');
}
sb.Append(']');
return sb.ToString();
}
2006-08-14 11:57:03 +04:00
}
class AssemblyClassLoader : ClassLoaderWrapper
{
private AssemblyLoader assemblyLoader;
private string[] references;
2006-08-14 11:57:03 +04:00
private AssemblyClassLoader[] delegates;
private bool isReflectionOnly;
#if !STATIC_COMPILER
private Thread initializerThread;
private volatile object protectionDomain;
#endif
private bool hasCustomClassLoader;
private Dictionary<int, List<int>> exports;
private string[] exportedAssemblyNames;
private AssemblyLoader[] exportedAssemblies;
private Dictionary<Assembly, AssemblyLoader> exportedLoaders;
2006-08-14 11:57:03 +04:00
private sealed class AssemblyLoader
2006-08-14 11:57:03 +04:00
{
private readonly Assembly assembly;
private bool[] isJavaModule;
private Module[] modules;
private Dictionary<string, string> nameMap;
private bool hasDotNetModule;
private AssemblyName[] internalsVisibleTo;
internal AssemblyLoader(Assembly assembly)
2006-07-10 13:37:06 +04:00
{
this.assembly = assembly;
modules = assembly.GetModules(false);
isJavaModule = new bool[modules.Length];
for (int i = 0; i < modules.Length; i++)
2006-07-10 13:37:06 +04:00
{
object[] attr;
try
{
attr = AttributeHelper.GetJavaModuleAttributes(modules[i]);
}
catch (Exception x)
{
// HACK we handle exceptions here, because there is at least one obfuscator that produces
// invalid assemblies that cause Module.GetCustomAttributes() to throw an exception
JVM.CriticalFailure("Unexpected exception", x);
throw null;
}
if (attr.Length > 0)
2006-07-10 13:37:06 +04:00
{
isJavaModule[i] = true;
foreach (JavaModuleAttribute jma in attr)
2006-08-14 11:57:03 +04:00
{
string[] map = jma.GetClassMap();
if (map != null)
2006-08-14 11:57:03 +04:00
{
if (nameMap == null)
{
nameMap = new Dictionary<string, string>();
}
for (int j = 0; j < map.Length; j += 2)
{
string key = map[j];
string val = map[j + 1];
// TODO if there is a name clash between modules, this will throw.
// Figure out how to handle that.
nameMap.Add(key, val);
}
2006-10-09 12:29:42 +04:00
}
}
}
else
{
hasDotNetModule = true;
}
}
}
internal bool HasJavaModule
{
get
{
for (int i = 0; i < isJavaModule.Length; i++)
{
if (isJavaModule[i])
{
return true;
}
}
return false;
}
}
internal Assembly Assembly
{
get { return assembly; }
}
private Type GetType(string name)
{
try
{
return assembly.GetType(name);
}
catch (FileLoadException x)
{
// this can only happen if the assembly was loaded in the ReflectionOnly
// context and the requested type references a type in another assembly
// that cannot be found in the ReflectionOnly context
// TODO figure out what other exceptions Assembly.GetType() can throw
Tracer.Info(Tracer.Runtime, x.Message);
}
return null;
}
private Type GetType(Module mod, string name)
{
try
{
return mod.GetType(name);
}
catch (FileLoadException x)
{
// this can only happen if the assembly was loaded in the ReflectionOnly
// context and the requested type references a type in another assembly
// that cannot be found in the ReflectionOnly context
// TODO figure out what other exceptions Assembly.GetType() can throw
Tracer.Info(Tracer.Runtime, x.Message);
}
return null;
}
private Type GetJavaType(Module mod, string name)
{
try
{
string n = null;
if (nameMap != null)
{
nameMap.TryGetValue(name, out n);
}
Type t = GetType(mod, n != null ? n : name);
if (t == null)
{
n = name.Replace('$', '+');
if (!ReferenceEquals(n, name))
{
t = GetType(n);
}
}
if (t != null
&& !AttributeHelper.IsHideFromJava(t)
&& !t.IsArray
&& !t.IsPointer
&& !t.IsByRef)
{
return t;
}
}
catch (ArgumentException x)
{
// we can end up here because we replace the $ with a plus sign
// (or client code did a Class.forName() on an invalid name)
Tracer.Info(Tracer.Runtime, x.Message);
}
return null;
}
internal TypeWrapper DoLoad(string name)
{
for (int i = 0; i < modules.Length; i++)
{
if (isJavaModule[i])
{
Type type = GetJavaType(modules[i], name);
if (type != null)
{
// check the name to make sure that the canonical name was used
if (CompiledTypeWrapper.GetName(type) == name)
2006-10-09 12:29:42 +04:00
{
return CompiledTypeWrapper.newInstance(name, type);
2006-08-14 11:57:03 +04:00
}
}
2006-07-10 13:37:06 +04:00
}
else
{
// TODO should we catch ArgumentException and prohibit array, pointer and byref here?
Type type = GetType(modules[i], DotNetTypeWrapper.DemangleTypeName(name));
if (type != null && DotNetTypeWrapper.IsAllowedOutside(type))
{
// check the name to make sure that the canonical name was used
if (DotNetTypeWrapper.GetName(type) == name)
{
return new DotNetTypeWrapper(type, name);
}
}
}
}
if (hasDotNetModule)
{
// for fake types, we load the declaring outer type (the real one) and
// let that generated the manufactured nested classes
TypeWrapper outer = null;
if (name.EndsWith(DotNetTypeWrapper.DelegateInterfaceSuffix))
{
outer = DoLoad(name.Substring(0, name.Length - DotNetTypeWrapper.DelegateInterfaceSuffix.Length));
}
else if (name.EndsWith(DotNetTypeWrapper.AttributeAnnotationSuffix))
{
outer = DoLoad(name.Substring(0, name.Length - DotNetTypeWrapper.AttributeAnnotationSuffix.Length));
}
else if (name.EndsWith(DotNetTypeWrapper.AttributeAnnotationReturnValueSuffix))
{
outer = DoLoad(name.Substring(0, name.Length - DotNetTypeWrapper.AttributeAnnotationReturnValueSuffix.Length));
}
else if (name.EndsWith(DotNetTypeWrapper.AttributeAnnotationMultipleSuffix))
{
outer = DoLoad(name.Substring(0, name.Length - DotNetTypeWrapper.AttributeAnnotationMultipleSuffix.Length));
}
else if (name.EndsWith(DotNetTypeWrapper.EnumEnumSuffix))
{
outer = DoLoad(name.Substring(0, name.Length - DotNetTypeWrapper.EnumEnumSuffix.Length));
}
if (outer != null && outer.IsFakeTypeContainer)
{
foreach (TypeWrapper tw in outer.InnerClasses)
{
if (tw.Name == name)
{
return tw;
}
}
}
}
return null;
}
internal TypeWrapper CreateWrapperForAssemblyType(Type type)
{
Module mod = type.Module;
int moduleIndex = -1;
for (int i = 0; i < modules.Length; i++)
{
if (modules[i] == mod)
{
moduleIndex = i;
break;
}
}
string name;
if (isJavaModule[moduleIndex])
{
name = CompiledTypeWrapper.GetName(type);
}
else
{
name = DotNetTypeWrapper.GetName(type);
if (name == null)
{
return null;
}
}
if (isJavaModule[moduleIndex])
{
if (AttributeHelper.IsHideFromJava(type))
{
return null;
}
// since this type was compiled from Java source, we have to look for our
// attributes
return CompiledTypeWrapper.newInstance(name, type);
2006-07-10 13:37:06 +04:00
}
else
{
if (!DotNetTypeWrapper.IsAllowedOutside(type))
{
return null;
}
// since this type was not compiled from Java source, we don't need to
// look for our attributes, but we do need to filter unrepresentable
// stuff (and transform some other stuff)
return new DotNetTypeWrapper(type, name);
}
2006-07-10 13:37:06 +04:00
}
internal bool InternalsVisibleTo(AssemblyName otherName)
{
if (internalsVisibleTo == null)
{
internalsVisibleTo = AttributeHelper.GetInternalsVisibleToAttributes(assembly);
}
foreach (AssemblyName name in internalsVisibleTo)
{
if (AssemblyName.ReferenceMatchesDefinition(name, otherName))
{
return true;
}
}
return false;
}
2006-08-14 11:57:03 +04:00
}
internal AssemblyClassLoader(Assembly assembly, object javaClassLoader, bool hasCustomClassLoader)
: this(assembly, null, javaClassLoader, hasCustomClassLoader)
2006-08-14 11:57:03 +04:00
{
}
internal AssemblyClassLoader(Assembly assembly, string[] fixedReferences, object javaClassLoader, bool hasCustomClassLoader)
: base(CodeGenOptions.None, javaClassLoader)
2006-08-14 11:57:03 +04:00
{
this.assemblyLoader = new AssemblyLoader(assembly);
this.references = fixedReferences;
this.isReflectionOnly = assembly.ReflectionOnly;
this.hasCustomClassLoader = hasCustomClassLoader;
}
private void DoInitializeExports()
{
lock (this)
{
if (delegates == null)
{
if (!(ReflectUtil.IsDynamicAssembly(assemblyLoader.Assembly)) && assemblyLoader.Assembly.GetManifestResourceInfo("ikvm.exports") != null)
{
List<string> wildcardExports = new List<string>();
using (Stream stream = assemblyLoader.Assembly.GetManifestResourceStream("ikvm.exports"))
{
BinaryReader rdr = new BinaryReader(stream);
int assemblyCount = rdr.ReadInt32();
exports = new Dictionary<int, List<int>>();
exportedAssemblies = new AssemblyLoader[assemblyCount];
exportedAssemblyNames = new string[assemblyCount];
exportedLoaders = new Dictionary<Assembly, AssemblyLoader>();
for (int i = 0; i < assemblyCount; i++)
{
exportedAssemblyNames[i] = 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();
List<int> assemblies;
if (!exports.TryGetValue(hash, out assemblies))
{
assemblies = new List<int>();
exports.Add(hash, assemblies);
}
assemblies.Add(i);
}
}
}
if (references == null)
{
references = wildcardExports.ToArray();
}
}
else
{
AssemblyName[] refNames = assemblyLoader.Assembly.GetReferencedAssemblies();
references = new string[refNames.Length];
for (int i = 0; i < references.Length; i++)
{
references[i] = refNames[i].FullName;
}
}
delegates = new AssemblyClassLoader[references.Length];
}
2006-08-14 11:57:03 +04:00
}
}
private void LazyInitExports()
{
if (delegates == null)
{
DoInitializeExports();
}
}
internal Assembly MainAssembly
{
get
2006-08-14 11:57:03 +04:00
{
return assemblyLoader.Assembly;
2006-08-14 11:57:03 +04:00
}
2006-07-10 13:37:06 +04:00
}
internal Assembly GetAssembly(TypeWrapper wrapper)
{
Debug.Assert(wrapper.GetClassLoader() == this);
while (wrapper.IsFakeNestedType)
{
wrapper = wrapper.DeclaringTypeWrapper;
}
return wrapper.TypeAsBaseType.Assembly;
}
internal override Type GetGenericTypeDefinition(string name)
2006-10-09 12:29:42 +04:00
{
try
{
// we only have to look in the main assembly, because only a .NET assembly can contain generic type definitions
// and it cannot be part of a multi assembly sharedclassloader group
Type type = assemblyLoader.Assembly.GetType(name);
if (type != null && type.IsGenericTypeDefinition)
{
return type;
}
2006-10-09 12:29:42 +04:00
}
catch (FileLoadException x)
2006-10-09 12:29:42 +04:00
{
// this can only happen if the assembly was loaded in the ReflectionOnly
// context and the requested type references a type in another assembly
// that cannot be found in the ReflectionOnly context
// TODO figure out what other exceptions Assembly.GetType() can throw
Tracer.Info(Tracer.Runtime, x.Message);
}
return null;
}
private Assembly LoadAssemblyOrClearName(ref string name)
2006-07-10 13:37:06 +04:00
{
if (name == null)
{
// previous load attemp failed
return null;
}
2006-07-10 13:37:06 +04:00
try
{
if (isReflectionOnly)
2006-07-10 13:37:06 +04:00
{
return Assembly.ReflectionOnlyLoad(name);
2006-07-10 13:37:06 +04:00
}
else
2006-07-10 13:37:06 +04:00
{
return Assembly.Load(name);
2006-07-10 13:37:06 +04:00
}
}
catch
2006-07-10 13:37:06 +04:00
{
// cache failure by clearing out the name the caller uses
name = null;
// should we issue a warning error (in ikvmc)?
return null;
2006-07-10 13:37:06 +04:00
}
}
2006-07-21 14:18:13 +04:00
2006-08-14 11:57:03 +04:00
internal TypeWrapper DoLoad(string name)
2006-07-21 14:18:13 +04:00
{
TypeWrapper tw = assemblyLoader.DoLoad(name);
if (tw != null)
{
return RegisterInitiatingLoader(tw);
}
LazyInitExports();
if (exports != null)
2006-07-26 11:57:18 +04:00
{
List<int> assemblies;
if (exports.TryGetValue(JVM.PersistableHash(name), out assemblies))
2006-07-21 14:18:13 +04:00
{
foreach (int index in assemblies)
2006-07-21 14:18:13 +04:00
{
AssemblyLoader loader = exportedAssemblies[index];
if (loader == null)
2006-10-09 12:29:42 +04:00
{
Assembly asm = LoadAssemblyOrClearName(ref exportedAssemblyNames[index]);
if (asm == null)
{
continue;
}
loader = exportedAssemblies[index] = GetLoaderForExportedAssembly(asm);
2006-10-09 12:29:42 +04:00
}
tw = loader.DoLoad(name);
if (tw != null)
2006-10-09 12:29:42 +04:00
{
return RegisterInitiatingLoader(tw);
2006-10-09 12:29:42 +04:00
}
2006-07-26 14:33:52 +04:00
}
}
}
return null;
}
private AssemblyLoader GetLoader(Assembly assembly)
{
if (assemblyLoader.Assembly == assembly)
{
return assemblyLoader;
}
return GetLoaderForExportedAssembly(assembly);
}
private AssemblyLoader GetLoaderForExportedAssembly(Assembly assembly)
{
LazyInitExports();
AssemblyLoader loader;
lock (exportedLoaders)
{
exportedLoaders.TryGetValue(assembly, out loader);
}
if (loader == null)
{
loader = new AssemblyLoader(assembly);
lock (exportedLoaders)
{
AssemblyLoader existing;
if (exportedLoaders.TryGetValue(assembly, out existing))
{
// another thread beat us to it
loader = existing;
}
else
{
exportedLoaders.Add(assembly, loader);
}
}
}
return loader;
2006-07-26 14:33:52 +04:00
}
internal virtual TypeWrapper GetWrapperFromAssemblyType(Type type)
2006-07-26 14:33:52 +04:00
{
2006-08-14 11:57:03 +04:00
//Tracer.Info(Tracer.Runtime, "GetWrapperFromAssemblyType: {0}", type.FullName);
2007-01-16 13:14:47 +03:00
Debug.Assert(!type.Name.EndsWith("[]"), "!type.IsArray", type.FullName);
Debug.Assert(ClassLoaderWrapper.GetAssemblyClassLoader(type.Assembly) == this);
#if !COMPACT_FRAMEWORK && !IKVM_REF_EMIT
2006-08-14 11:57:03 +04:00
Debug.Assert(!(type.Assembly is AssemblyBuilder), "!(type.Assembly is AssemblyBuilder)", type.FullName);
#endif
TypeWrapper wrapper = GetLoader(type.Assembly).CreateWrapperForAssemblyType(type);
2006-08-14 11:57:03 +04:00
if(wrapper != null)
{
wrapper = RegisterInitiatingLoader(wrapper);
2006-08-14 11:57:03 +04:00
if(wrapper.TypeAsTBD != type && (!wrapper.IsRemapped || wrapper.TypeAsBaseType != type))
2006-07-26 14:33:52 +04:00
{
2006-08-14 11:57:03 +04:00
// this really shouldn't happen, it means that we have two different types in our assembly that both
// have the same Java name
string msg = String.Format("\nType \"{0}\" and \"{1}\" both map to the same name \"{2}\".\n", type.FullName, wrapper.TypeAsTBD.FullName, wrapper.Name);
2006-08-14 11:57:03 +04:00
JVM.CriticalFailure(msg, null);
}
return wrapper;
}
return null;
2006-07-26 11:57:18 +04:00
}
2006-07-10 13:37:06 +04:00
protected override TypeWrapper LoadClassImpl(string name, bool throwClassNotFoundException)
{
TypeWrapper tw = DoLoad(name);
if(tw != null)
{
return tw;
}
if(hasCustomClassLoader)
{
return base.LoadClassImpl(name, throwClassNotFoundException);
}
else
{
tw = LoadGenericClass(name);
if(tw != null)
{
return tw;
}
return LoadReferenced(name);
}
}
internal TypeWrapper LoadReferenced(string name)
2006-07-10 13:37:06 +04:00
{
LazyInitExports();
2006-08-14 11:57:03 +04:00
for(int i = 0; i < delegates.Length; i++)
{
if(delegates[i] == null)
2006-07-21 14:18:13 +04:00
{
Assembly asm = LoadAssemblyOrClearName(ref references[i]);
2006-08-14 11:57:03 +04:00
if(asm != null)
{
delegates[i] = ClassLoaderWrapper.GetAssemblyClassLoader(asm);
}
}
2006-10-06 10:53:34 +04:00
if(delegates[i] != null)
2006-08-14 11:57:03 +04:00
{
TypeWrapper tw = delegates[i].DoLoad(name);
2006-10-06 10:53:34 +04:00
if(tw != null)
{
return tw;
}
2006-07-21 14:18:13 +04:00
}
}
if(!assemblyLoader.HasJavaModule)
2006-07-26 11:57:18 +04:00
{
2006-08-14 11:57:03 +04:00
return GetBootstrapClassLoader().LoadClassByDottedNameFast(name);
2006-07-26 11:57:18 +04:00
}
2006-08-14 11:57:03 +04:00
return null;
2006-07-10 13:37:06 +04:00
}
2006-11-30 17:29:43 +03:00
#if !STATIC_COMPILER
internal Assembly FindResourceAssembliesImpl(string unmangledName, string name, bool firstOnly, ref List<Assembly> list)
2006-11-30 17:29:43 +03:00
{
if(ReflectUtil.IsDynamicAssembly(assemblyLoader.Assembly))
{
return null;
}
if(assemblyLoader.Assembly.GetManifestResourceInfo(name) != null)
2006-11-30 17:29:43 +03:00
{
if(firstOnly)
{
return assemblyLoader.Assembly;
2006-11-30 17:29:43 +03:00
}
2008-08-15 16:01:06 +04:00
list = new List<Assembly>();
list.Add(assemblyLoader.Assembly);
2006-11-30 17:29:43 +03:00
}
LazyInitExports();
if(exports != null)
2006-11-30 17:29:43 +03:00
{
List<int> assemblies;
if(exports.TryGetValue(JVM.PersistableHash(unmangledName), out assemblies))
2006-11-30 17:29:43 +03:00
{
foreach(int index in assemblies)
2006-11-30 17:29:43 +03:00
{
AssemblyLoader loader = exportedAssemblies[index];
if(loader == null)
2006-11-30 17:29:43 +03:00
{
Assembly asm = LoadAssemblyOrClearName(ref exportedAssemblyNames[index]);
if(asm == null)
{
continue;
}
loader = exportedAssemblies[index] = GetLoaderForExportedAssembly(asm);
}
if(loader.Assembly.GetManifestResourceInfo(name) != null)
{
if(firstOnly)
{
return loader.Assembly;
}
if(list == null)
{
list = new List<Assembly>();
}
list.Add(loader.Assembly);
2006-11-30 17:29:43 +03:00
}
}
}
}
return null;
}
internal Assembly[] FindResourceAssemblies(string unmangledName, bool firstOnly)
{
List<Assembly> list = null;
string name = JVM.MangleResourceName(unmangledName);
Assembly first = FindResourceAssembliesImpl(unmangledName, name, firstOnly, ref list);
if(first != null)
{
return new Assembly[] { first };
}
LazyInitExports();
for(int i = 0; i < delegates.Length; i++)
{
if(delegates[i] == null)
{
Assembly asm = LoadAssemblyOrClearName(ref references[i]);
2006-11-30 17:29:43 +03:00
if(asm != null)
{
delegates[i] = ClassLoaderWrapper.GetAssemblyClassLoader(asm);
}
}
if(delegates[i] != null)
{
first = delegates[i].FindResourceAssembliesImpl(unmangledName, name, firstOnly, ref list);
if(first != null)
2006-11-30 17:29:43 +03:00
{
return new Assembly[] { first };
2006-11-30 17:29:43 +03:00
}
}
}
if(!assemblyLoader.HasJavaModule)
2006-11-30 17:29:43 +03:00
{
if(firstOnly)
2006-11-30 17:29:43 +03:00
{
return GetBootstrapClassLoader().FindResourceAssemblies(unmangledName, firstOnly);
2006-11-30 17:29:43 +03:00
}
else
2006-11-30 17:29:43 +03:00
{
Assembly[] assemblies = GetBootstrapClassLoader().FindResourceAssemblies(unmangledName, firstOnly);
if(assemblies != null)
{
foreach(Assembly asm in assemblies)
{
if(list == null)
{
list = new List<Assembly>();
}
if(!list.Contains(asm))
{
list.Add(asm);
}
}
}
2006-11-30 17:29:43 +03:00
}
}
if(list == null)
{
return null;
}
2008-08-15 16:01:06 +04:00
return list.ToArray();
2006-11-30 17:29:43 +03:00
}
internal void SetInitInProgress()
{
initializerThread = Thread.CurrentThread;
}
internal void SetInitDone()
{
lock(this)
{
initializerThread = null;
Monitor.PulseAll(this);
}
}
internal void WaitInitDone()
{
lock(this)
{
if(initializerThread != Thread.CurrentThread)
{
while(initializerThread != null)
{
Monitor.Wait(this);
}
}
}
}
2006-11-30 17:29:43 +03:00
#endif // !STATIC_COMPILER
internal virtual object GetProtectionDomain()
{
#if STATIC_COMPILER || FIRST_PASS
return null;
#else
if(protectionDomain == null)
{
java.net.URL codebase;
try
{
codebase = new java.net.URL(assemblyLoader.Assembly.CodeBase);
}
catch(NotSupportedException)
{
// dynamic assemblies don't have a codebase
codebase = null;
}
catch(java.net.MalformedURLException)
{
codebase = null;
}
java.security.Permissions permissions = new java.security.Permissions();
permissions.add(new java.security.AllPermission());
object pd = new java.security.ProtectionDomain(new java.security.CodeSource(codebase, (java.security.cert.Certificate[])null), permissions, (java.lang.ClassLoader)GetJavaClassLoader(), null);
lock(this)
{
if(protectionDomain == null)
{
protectionDomain = pd;
}
}
}
return protectionDomain;
#endif
}
protected override void CheckDefineClassAllowed(string className)
{
if(DoLoad(className) != null)
{
throw new LinkageError("duplicate class definition: " + className);
}
}
internal override TypeWrapper GetLoadedClass(string name)
{
TypeWrapper tw = base.GetLoadedClass(name);
return tw != null ? tw : DoLoad(name);
}
internal override bool InternalsVisibleToImpl(TypeWrapper wrapper, TypeWrapper friend)
{
ClassLoaderWrapper other = friend.GetClassLoader();
if(this == other)
{
return true;
}
AssemblyName otherName;
#if STATIC_COMPILER
CompilerClassLoader ccl = other as CompilerClassLoader;
if(ccl == null)
{
return false;
}
otherName = ccl.GetAssemblyName();
#else
AssemblyClassLoader acl = other as AssemblyClassLoader;
if(acl == null)
{
return false;
}
otherName = acl.GetAssembly(friend).GetName();
#endif
return GetLoaderForExportedAssembly(GetAssembly(wrapper)).InternalsVisibleTo(otherName);
}
2006-05-15 13:08:01 +04:00
}
class BootstrapClassLoader : AssemblyClassLoader
{
internal BootstrapClassLoader()
: base(JVM.CoreAssembly, new string[] {
typeof(object).Assembly.FullName, // mscorlib
typeof(System.Uri).Assembly.FullName // System
}, null, false)
{
}
internal override TypeWrapper GetWrapperFromAssemblyType(Type type)
{
// we have to special case the fake types here
if(type.IsGenericType)
{
TypeWrapper outer = ClassLoaderWrapper.GetWrapperFromType(type.GetGenericArguments()[0]);
foreach(TypeWrapper inner in outer.InnerClasses)
{
if(inner.TypeAsTBD == type)
{
return inner;
}
foreach(TypeWrapper inner2 in inner.InnerClasses)
{
if(inner2.TypeAsTBD == type)
{
return inner2;
}
}
}
return null;
}
return base.GetWrapperFromAssemblyType(type);
}
internal override object GetProtectionDomain()
{
return null;
}
}
2002-12-18 19:00:25 +03:00
}