2002-12-18 19:00:25 +03:00
/ *
2006-01-02 11:15:43 +03:00
Copyright ( C ) 2002 , 2003 , 2004 , 2005 , 2006 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 ;
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
using System.Reflection.Emit ;
#endif
2002-12-18 19:00:25 +03:00
using System.IO ;
using System.Collections ;
using System.Xml ;
using System.Diagnostics ;
2004-09-09 15:17:55 +04:00
using IKVM.Attributes ;
using IKVM.Runtime ;
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
{
2005-06-01 13:49:30 +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 ( ) ;
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
private static bool arrayConstructionHack ;
2005-07-25 18:34:22 +04:00
private static readonly object arrayConstructionLock = new object ( ) ;
private static readonly Hashtable dynamicTypes = Hashtable . Synchronized ( new Hashtable ( ) ) ;
2005-12-07 12:06:32 +03:00
// FXBUG moduleBuilder is static, because multiple dynamic assemblies is broken (TypeResolve doesn't fire)
// so for the time being, we share one dynamic assembly among all classloaders
private static ModuleBuilder moduleBuilder ;
private static bool saveDebugImage ;
private static Hashtable nameClashHash = new Hashtable ( ) ;
private static ArrayList saveDebugAssemblies ;
#endif
2005-09-06 12:06:04 +04:00
private static readonly Hashtable typeToTypeWrapper = Hashtable . Synchronized ( new Hashtable ( ) ) ;
2005-06-01 13:49:30 +04:00
private static ClassLoaderWrapper bootstrapClassLoader ;
private static ClassLoaderWrapper systemClassLoader ;
private object javaClassLoader ;
private Hashtable types = new Hashtable ( ) ;
private ArrayList nativeLibraries ;
private static Hashtable remappedTypes = new Hashtable ( ) ;
private static int instanceCounter = 0 ;
private int instanceId = System . Threading . Interlocked . Increment ( ref instanceCounter ) ;
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// HACK this is used by the ahead-of-time compiler to overrule the bootstrap classloader
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 ;
}
2004-03-08 18:18:47 +03:00
2005-06-01 13:49:30 +04:00
static ClassLoaderWrapper ( )
{
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
// TODO AppDomain.TypeResolve requires ControlAppDomain permission, but if we don't have that,
// we should handle that by disabling dynamic class loading
AppDomain . CurrentDomain . TypeResolve + = new ResolveEventHandler ( OnTypeResolve ) ;
2005-12-07 12:06:32 +03:00
#endif
2005-06-01 13:49:30 +04:00
typeToTypeWrapper [ PrimitiveTypeWrapper . BOOLEAN . TypeAsTBD ] = PrimitiveTypeWrapper . BOOLEAN ;
typeToTypeWrapper [ PrimitiveTypeWrapper . BYTE . TypeAsTBD ] = PrimitiveTypeWrapper . BYTE ;
typeToTypeWrapper [ PrimitiveTypeWrapper . CHAR . TypeAsTBD ] = PrimitiveTypeWrapper . CHAR ;
typeToTypeWrapper [ PrimitiveTypeWrapper . DOUBLE . TypeAsTBD ] = PrimitiveTypeWrapper . DOUBLE ;
typeToTypeWrapper [ PrimitiveTypeWrapper . FLOAT . TypeAsTBD ] = PrimitiveTypeWrapper . FLOAT ;
typeToTypeWrapper [ PrimitiveTypeWrapper . INT . TypeAsTBD ] = PrimitiveTypeWrapper . INT ;
typeToTypeWrapper [ PrimitiveTypeWrapper . LONG . TypeAsTBD ] = PrimitiveTypeWrapper . LONG ;
typeToTypeWrapper [ PrimitiveTypeWrapper . SHORT . TypeAsTBD ] = PrimitiveTypeWrapper . SHORT ;
typeToTypeWrapper [ PrimitiveTypeWrapper . VOID . TypeAsTBD ] = PrimitiveTypeWrapper . VOID ;
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
{
2005-12-19 18:12:49 +03:00
Tracer . Info ( Tracer . Runtime , "Core assembly: {0}" , coreAssembly . Location ) ;
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
2005-06-01 13:49:30 +04:00
internal static bool IsCoreAssemblyType ( Type type )
{
2005-12-07 12:06:32 +03:00
return type . Assembly = = JVM . CoreAssembly ;
2005-06-01 13:49:30 +04:00
}
2004-10-04 23:30:53 +04:00
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
private static Assembly OnTypeResolve ( object sender , ResolveEventArgs args )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
lock ( arrayConstructionLock )
{
Tracer . Info ( Tracer . ClassLoading , "OnTypeResolve: {0} (arrayConstructionHack = {1})" , args . Name , arrayConstructionHack ) ;
if ( arrayConstructionHack )
{
return null ;
}
}
TypeWrapper type = ( TypeWrapper ) dynamicTypes [ args . Name ] ;
if ( type = = null )
2004-08-17 13:05:21 +04:00
{
return null ;
}
2005-08-03 16:59:16 +04:00
// During static compilation, a TypeResolve event should never trigger a finish.
if ( JVM . IsStaticCompilerPhase1 )
{
JVM . CriticalFailure ( "Finish triggered during phase 1 of compilation." , null ) ;
return null ;
}
2005-06-01 13:49:30 +04:00
try
{
type . Finish ( ) ;
}
catch ( RetargetableJavaException x )
{
throw x . ToJava ( ) ;
}
// NOTE We used to remove the type from the hashtable here, but that creates a race condition if
// another thread also fires the OnTypeResolve event while we're baking the type.
// I really would like to remove the type from the hashtable, but at the moment I don't see
// any way of doing that that wouldn't cause this race condition.
//dynamicTypes.Remove(args.Name);
return type . TypeAsTBD . Assembly ;
2004-03-08 18:18:47 +03:00
}
2005-12-07 12:06:32 +03:00
#endif
2005-06-01 13:49:30 +04:00
internal ClassLoaderWrapper ( object javaClassLoader )
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
SetJavaClassLoader ( javaClassLoader ) ;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal void SetJavaClassLoader ( object javaClassLoader )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
this . javaClassLoader = javaClassLoader ;
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 )
{
Debug . Assert ( ! types . ContainsKey ( tw . Name ) ) ;
types . Add ( tw . Name , tw ) ;
Debug . Assert ( ! typeToTypeWrapper . ContainsKey ( type ) ) ;
typeToTypeWrapper . Add ( type , tw ) ;
remappedTypes . Add ( type , type ) ;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// HACK return the TypeWrapper if it is already loaded
2005-07-25 18:34:22 +04:00
// (this exists solely for DynamicTypeWrapper.SetupGhosts and VMClassLoader.findLoadedClass)
2005-06-01 13:49:30 +04:00
internal TypeWrapper GetLoadedClass ( string name )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
lock ( types . SyncRoot )
{
return ( TypeWrapper ) types [ name ] ;
}
2004-08-17 13:05:21 +04:00
}
2003-12-20 01:19:18 +03:00
2005-07-27 19:57:55 +04:00
internal TypeWrapper RegisterInitiatingLoader ( TypeWrapper tw )
{
2005-08-25 17:15:42 +04:00
if ( tw = = null | | tw . IsUnloadable | | tw . IsPrimitive )
2005-07-27 19:57:55 +04:00
return tw ;
lock ( types . SyncRoot )
{
object existing = types [ tw . Name ] ;
if ( existing ! = tw )
{
if ( existing ! = null )
{
throw new LinkageError ( "duplicate class definition: " + tw . Name ) ;
}
if ( tw . IsArray )
{
TypeWrapper elem = tw ;
// TODO there should be a way to get the ultimate element type
// without creating all the intermediate types
while ( elem . IsArray )
{
elem = elem . ElementTypeWrapper ;
}
RegisterInitiatingLoader ( elem ) ;
}
// 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 ;
}
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
// FXBUG This mangles type names, to enable different class loaders loading classes with the same names.
// We used to support this by using an assembly per class loader instance, but because
// of the CLR TypeResolve bug, we put all types in a single assembly for now.
internal string MangleTypeName ( string name )
2003-06-10 17:28:47 +04:00
{
2005-06-01 13:49:30 +04:00
lock ( nameClashHash . SyncRoot )
2003-06-10 17:28:47 +04:00
{
2005-06-01 13:49:30 +04:00
// FXBUG the 1.1 CLR doesn't like type names that end with a period.
if ( nameClashHash . ContainsKey ( name ) | | name . EndsWith ( "." ) )
2003-06-10 17:28:47 +04:00
{
2005-06-01 13:49:30 +04:00
if ( JVM . IsStaticCompiler )
{
Tracer . Warning ( Tracer . Compiler , "Class name clash: {0}" , name ) ;
}
return name + "/" + instanceId ;
}
else
{
nameClashHash . Add ( name , name ) ;
return name ;
2003-06-10 17:28:47 +04:00
}
}
}
2005-12-07 12:06:32 +03:00
#endif
2003-06-10 17:28:47 +04:00
2005-06-01 13:49:30 +04:00
internal TypeWrapper LoadClassByDottedName ( string name )
2003-03-17 17:02:46 +03:00
{
2005-08-25 11:46:57 +04:00
TypeWrapper type = LoadClassByDottedNameFast ( name , true ) ;
2005-06-01 13:49:30 +04:00
if ( type ! = null )
{
return type ;
}
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
{
return LoadClassByDottedNameFast ( name , false ) ;
}
private TypeWrapper LoadClassByDottedNameFast ( 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
if ( name . Length > = 1024 )
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 ;
lock ( types . SyncRoot )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
type = ( TypeWrapper ) types [ name ] ;
if ( type = = null & & types . ContainsKey ( name ) )
2004-12-03 10:57:15 +03:00
{
2005-06-01 13:49:30 +04:00
// NOTE this can also happen if we (incorrectly) trigger a load of this class during
// the loading of the base class, so we print a trace message here.
Tracer . Error ( Tracer . ClassLoading , "**** ClassCircularityError: {0} ****" , name ) ;
throw new ClassCircularityError ( name ) ;
2004-12-03 10:57:15 +03:00
}
}
2005-06-01 13:49:30 +04:00
if ( type ! = null )
2004-12-03 10:57:15 +03:00
{
2005-06-01 13:49:30 +04:00
return type ;
2004-12-03 10:57:15 +03:00
}
2005-06-01 13:49:30 +04:00
if ( name . Length > 1 & & name [ 0 ] = = '[' )
2004-12-03 10:57:15 +03:00
{
2005-06-01 13:49:30 +04:00
int dims = 1 ;
while ( name [ dims ] = = '[' )
2003-08-26 15:24:17 +04:00
{
2005-06-01 13:49:30 +04:00
dims + + ;
2003-08-26 15:24:17 +04:00
}
2005-06-01 13:49:30 +04:00
if ( name [ dims ] = = 'L' )
2002-12-29 19:27:00 +03:00
{
2005-06-01 13:49:30 +04:00
if ( ! name . EndsWith ( ";" ) | | name . Length < = dims + 2 | | name [ dims + 1 ] = = '[' )
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
// malformed class name
return null ;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
string elemClass = name . Substring ( dims + 1 , name . Length - dims - 2 ) ;
type = LoadClassByDottedNameFast ( elemClass ) ;
if ( type ! = null )
2003-08-21 14:06:34 +04:00
{
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-11-01 17:01:42 +03:00
// HACK make sure we don't go through a user class loader when creating
// an array for a precompiled or .NET type
if ( type is DynamicTypeWrapper )
{
type = type . GetClassLoader ( ) . CreateArrayType ( name , type , dims ) ;
}
else
2005-12-07 12:06:32 +03:00
#endif
2005-11-01 17:01:42 +03:00
{
type = GetBootstrapClassLoader ( ) . CreateArrayType ( name , type , dims ) ;
}
2003-08-21 14:06:34 +04:00
}
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( type ) ;
2002-12-29 19:27:00 +03:00
}
2005-06-01 13:49:30 +04:00
if ( name . Length ! = dims + 1 )
{
// malformed class name
return null ;
}
switch ( name [ dims ] )
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
case 'B' :
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetBootstrapClassLoader ( ) . CreateArrayType ( name , PrimitiveTypeWrapper . BYTE , dims ) ) ;
2005-06-01 13:49:30 +04:00
case 'C' :
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetBootstrapClassLoader ( ) . CreateArrayType ( name , PrimitiveTypeWrapper . CHAR , dims ) ) ;
2005-06-01 13:49:30 +04:00
case 'D' :
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetBootstrapClassLoader ( ) . CreateArrayType ( name , PrimitiveTypeWrapper . DOUBLE , dims ) ) ;
2005-06-01 13:49:30 +04:00
case 'F' :
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetBootstrapClassLoader ( ) . CreateArrayType ( name , PrimitiveTypeWrapper . FLOAT , dims ) ) ;
2005-06-01 13:49:30 +04:00
case 'I' :
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetBootstrapClassLoader ( ) . CreateArrayType ( name , PrimitiveTypeWrapper . INT , dims ) ) ;
2005-06-01 13:49:30 +04:00
case 'J' :
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetBootstrapClassLoader ( ) . CreateArrayType ( name , PrimitiveTypeWrapper . LONG , dims ) ) ;
2005-06-01 13:49:30 +04:00
case 'S' :
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetBootstrapClassLoader ( ) . CreateArrayType ( name , PrimitiveTypeWrapper . SHORT , dims ) ) ;
2005-06-01 13:49:30 +04:00
case 'Z' :
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetBootstrapClassLoader ( ) . CreateArrayType ( name , PrimitiveTypeWrapper . BOOLEAN , dims ) ) ;
2005-06-01 13:49:30 +04:00
default :
return null ;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
}
if ( this = = GetBootstrapClassLoader ( ) )
{
// HACK if the name contains a comma, we assume it is an assembly qualified name
if ( name . IndexOf ( ',' ) ! = - 1 )
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
// NOTE even though we search all loaded assemblies below, we still need to do this,
// because this call might actually trigger the load of an assembly.
Type t = Type . GetType ( name ) ;
if ( t = = null )
2004-08-17 13:05:21 +04:00
{
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
// HACK we explicitly try all loaded assemblies, to support assemblies
// that aren't loaded in the "Load" context.
string typeName = name . Substring ( 0 , name . IndexOf ( ',' ) ) ;
foreach ( Assembly asm in AppDomain . CurrentDomain . GetAssemblies ( ) )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
t = asm . GetType ( typeName ) ;
if ( t ! = null & & t . AssemblyQualifiedName = = name )
{
break ;
}
t = null ;
}
2005-12-07 12:06:32 +03:00
#endif
2005-06-01 13:49:30 +04:00
}
if ( t ! = null )
{
2005-12-07 12:06:32 +03:00
if ( AttributeHelper . IsJavaModule ( t . Module ) )
2005-06-01 13:49:30 +04:00
{
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetWrapperFromType ( t ) ) ;
2004-08-17 13:05:21 +04:00
}
else
{
2005-06-01 13:49:30 +04:00
// HACK weird way to load the .NET type wrapper that always works
// (for remapped types as well, because netexp uses this way of
// loading types, we need the remapped types to appear in their
// .NET "warped" form).
2005-08-25 11:46:57 +04:00
return LoadClassByDottedNameFast ( DotNetTypeWrapper . GetName ( t ) , throwClassNotFoundException ) ;
2004-08-17 13:05:21 +04:00
}
}
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
// TODO why is this check here and not at the top of the method?
if ( name ! = "" )
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
Type t = GetBootstrapTypeRaw ( name ) ;
if ( t ! = null )
{
2005-07-27 19:57:55 +04:00
return RegisterInitiatingLoader ( GetWrapperFromBootstrapType ( t ) ) ;
2005-06-01 13:49:30 +04:00
}
type = DotNetTypeWrapper . CreateDotNetTypeWrapper ( name ) ;
if ( type ! = null )
{
Debug . Assert ( type . Name = = name , type . Name + " != " + name ) ;
lock ( types . SyncRoot )
{
// another thread may have beaten us to it and in that
// case we don't want to overwrite the previous one
TypeWrapper race = ( TypeWrapper ) types [ name ] ;
if ( race = = null )
{
types [ name ] = type ;
}
else
{
type = race ;
}
}
return type ;
}
// NOTE it is important that this is done last, because otherwise we will
// load the netexp generated fake types (e.g. delegate inner interface) instead
// of having DotNetTypeWrapper generating it.
type = GetTypeWrapperCompilerHook ( name ) ;
if ( type ! = null )
{
return type ;
}
}
if ( javaClassLoader = = null )
{
return null ;
2003-08-21 14:06:34 +04:00
}
2002-12-29 19:27:00 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE just like Java does (I think), we take the classloader lock before calling the loadClass method
lock ( javaClassLoader )
2002-12-29 19:27:00 +03:00
{
2005-06-01 13:49:30 +04:00
Profiler . Enter ( "ClassLoader.loadClass" ) ;
try
{
type = ( TypeWrapper ) JVM . Library . loadClass ( javaClassLoader , name ) ;
}
2005-08-24 15:35:00 +04:00
catch ( Exception x )
{
2005-08-25 11:46:57 +04:00
if ( ! throwClassNotFoundException
& & LoadClassCritical ( "java.lang.ClassNotFoundException" ) . TypeAsBaseType . IsInstanceOfType ( x ) )
{
return null ;
}
2005-08-24 15:35:00 +04:00
throw new ClassLoadingException ( IKVM . Runtime . Util . MapException ( x ) ) ;
}
2005-06-01 13:49:30 +04:00
finally
{
Profiler . Leave ( "ClassLoader.loadClass" ) ;
}
2005-08-01 14:27:06 +04:00
// NOTE to be safe, we register the initiating loader,
// while we're holding the lock on the class loader object
return RegisterInitiatingLoader ( type ) ;
2002-12-29 19:27:00 +03:00
}
2005-06-01 13:49:30 +04:00
}
finally
{
Profiler . Leave ( "LoadClassByDottedName" ) ;
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
private TypeWrapper GetWrapperFromBootstrapType ( Type type )
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
//Tracer.Info(Tracer.Runtime, "GetWrapperFromBootstrapType: {0}", type.FullName);
Debug . Assert ( GetWrapperFromTypeFast ( type ) = = null , "GetWrapperFromTypeFast(type) == null" , type . FullName ) ;
Debug . Assert ( ! type . IsArray , "!type.IsArray" , type . FullName ) ;
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
Debug . Assert ( ! ( type . Assembly is AssemblyBuilder ) , "!(type.Assembly is AssemblyBuilder)" , type . FullName ) ;
2005-12-07 12:06:32 +03:00
#endif
2005-06-01 13:49:30 +04:00
// only the bootstrap classloader can own compiled types
Debug . Assert ( this = = GetBootstrapClassLoader ( ) , "this == GetBootstrapClassLoader()" , type . FullName ) ;
2005-12-07 12:06:32 +03:00
bool javaType = AttributeHelper . IsJavaModule ( type . Module ) ;
2005-06-01 13:49:30 +04:00
string name ;
2005-01-03 11:26:21 +03:00
if ( javaType )
{
2005-06-01 13:49:30 +04:00
name = CompiledTypeWrapper . GetName ( type ) ;
2005-01-03 11:26:21 +03:00
}
else
{
2005-06-01 13:49:30 +04:00
name = DotNetTypeWrapper . GetName ( type ) ;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
TypeWrapper wrapper ;
2004-08-17 13:05:21 +04:00
lock ( types . SyncRoot )
2003-08-13 19:00:41 +04:00
{
2005-06-01 13:49:30 +04:00
wrapper = ( TypeWrapper ) types [ name ] ;
}
2005-08-02 12:44:55 +04:00
if ( wrapper ! = null )
{
if ( wrapper . TypeAsTBD ! = type )
{
string msg = String . Format ( "\nTypename \"{0}\" is imported from multiple assemblies:\n{1}\n{2}\n" , type . FullName , wrapper . Assembly . FullName , type . Assembly . FullName ) ;
JVM . CriticalFailure ( msg , null ) ;
}
}
else
2005-06-01 13:49:30 +04:00
{
if ( javaType )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// since this type was compiled from Java source, we have to look for our
// attributes
wrapper = CompiledTypeWrapper . newInstance ( name , type ) ;
2004-08-17 13:05:21 +04:00
}
2005-01-03 11:26:21 +03:00
else
{
2005-06-01 13:49:30 +04:00
// 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)
wrapper = new DotNetTypeWrapper ( type ) ;
}
Debug . Assert ( wrapper . Name = = name , "wrapper.Name == name" , type . FullName ) ;
lock ( types . SyncRoot )
{
// another thread may have beaten us to it and in that
// case we don't want to overwrite the previous one
TypeWrapper race = ( TypeWrapper ) types [ name ] ;
if ( race = = null )
{
types . Add ( name , wrapper ) ;
typeToTypeWrapper . Add ( type , wrapper ) ;
}
else
{
wrapper = race ;
}
2005-01-03 11:26:21 +03:00
}
2003-08-13 19:00:41 +04:00
}
2005-06-01 13:49:30 +04:00
return wrapper ;
2003-08-13 19:00:41 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// NOTE this method only sees pre-compiled Java classes
internal Type GetBootstrapTypeRaw ( string name )
2002-12-18 19:00:25 +03:00
{
2005-12-07 12:06:32 +03:00
#if COMPACT_FRAMEWORK
// TODO figure this out
return GetJavaTypeFromAssembly ( JVM . CoreAssembly , name ) ;
#else
Assembly [ ] assemblies ;
#if WHIDBEY
2005-12-19 18:12:49 +03:00
if ( JVM . IsStaticCompiler | | JVM . IsIkvmStub )
2005-12-07 12:06:32 +03:00
{
assemblies = AppDomain . CurrentDomain . ReflectionOnlyGetAssemblies ( ) ;
}
else
{
assemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
}
#else
assemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
#endif
foreach ( Assembly a in assemblies )
2003-02-20 17:18:38 +03:00
{
2005-06-01 13:49:30 +04:00
if ( ! ( a is AssemblyBuilder ) )
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
Type t = GetJavaTypeFromAssembly ( a , name ) ;
if ( t ! = null )
{
return t ;
}
2004-01-11 16:14:42 +03:00
}
2003-02-20 17:18:38 +03:00
}
2005-06-01 13:49:30 +04:00
return null ;
2005-12-07 12:06:32 +03:00
#endif
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
private static Type GetJavaTypeFromAssembly ( Assembly a , string name )
2004-11-16 14:11:53 +03:00
{
2005-06-27 13:06:57 +04:00
try
2005-06-01 13:49:30 +04:00
{
2005-06-27 13:06:57 +04:00
Type t = a . GetType ( name ) ;
2005-08-25 13:36:36 +04:00
if ( t ! = null
2005-12-07 12:06:32 +03:00
& & AttributeHelper . IsJavaModule ( t . Module )
2005-08-25 13:36:36 +04:00
& & ! AttributeHelper . IsHideFromJava ( t ) )
2005-06-27 13:06:57 +04:00
{
return t ;
}
// HACK we might be looking for an inner classes
t = a . GetType ( name . Replace ( '$' , '+' ) ) ;
2005-08-25 13:36:36 +04:00
if ( t ! = null
2005-12-07 12:06:32 +03:00
& & AttributeHelper . IsJavaModule ( t . Module )
2005-08-25 13:36:36 +04:00
& & ! AttributeHelper . IsHideFromJava ( t ) )
2005-06-27 13:06:57 +04:00
{
return t ;
}
2005-06-01 13:49:30 +04:00
}
2005-06-27 13:06:57 +04:00
catch ( ArgumentException x )
2005-06-01 13:49:30 +04:00
{
2005-06-27 13:06:57 +04:00
// 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 ) ;
2005-06-01 13:49:30 +04:00
}
return null ;
2004-11-16 14:11:53 +03:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal virtual TypeWrapper GetTypeWrapperCompilerHook ( string name )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return null ;
2005-01-03 11:26:21 +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 ;
TypeWrapper wrapper ;
lock ( types . SyncRoot )
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
wrapper = ( TypeWrapper ) types [ name ] ;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
if ( wrapper = = null )
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
String netname = elementType . FullName + "[]" ;
for ( int i = 1 ; i < dims ; i + + )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
netname + = "[]" ;
}
// .NET 1.1 has a limit of 1024 characters for type names
if ( netname . Length > = 1024 )
{
return null ;
}
Type array ;
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
if ( elementType . Module is ModuleBuilder )
{
// FXBUG ModuleBuilder.GetType() is broken (I think), it fires a TypeResolveEvent when
// you try to construct an array type from an unfinished type. I don't think it should
// do that. We have to work around that by setting a global flag (yuck) to prevent us
// from responding to the TypeResolveEvent.
lock ( arrayConstructionLock )
{
arrayConstructionHack = true ;
try
{
array = ( ( ModuleBuilder ) elementType . Module ) . GetType ( netname ) ;
}
finally
{
arrayConstructionHack = false ;
}
}
}
else
2005-12-07 12:06:32 +03:00
#endif
2005-06-01 13:49:30 +04:00
{
array = elementType . Assembly . GetType ( netname , true ) ;
}
Modifiers modifiers = Modifiers . Final | Modifiers . Abstract ;
Modifiers reflectiveModifiers = modifiers ;
modifiers | = elementTypeWrapper . Modifiers & Modifiers . Public ;
reflectiveModifiers | = elementTypeWrapper . ReflectiveModifiers & Modifiers . AccessMask ;
wrapper = new ArrayTypeWrapper ( array , modifiers , reflectiveModifiers , name , this ) ;
lock ( types . SyncRoot )
{
// another thread may have beaten us to it and in that
// case we don't want to overwrite the previous one
TypeWrapper race = ( TypeWrapper ) types [ name ] ;
if ( race = = null )
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
types . Add ( name , wrapper ) ;
2005-12-07 12:06:32 +03:00
#if COMPACT_FRAMEWORK
if ( ! wrapper . IsGhostArray )
{
Debug . Assert ( ! typeToTypeWrapper . ContainsKey ( array ) , name ) ;
typeToTypeWrapper . Add ( array , wrapper ) ;
}
#else
2005-06-01 13:49:30 +04:00
if ( ! ( elementType is TypeBuilder ) & & ! wrapper . IsGhostArray )
{
Debug . Assert ( ! typeToTypeWrapper . ContainsKey ( array ) , name ) ;
typeToTypeWrapper . Add ( array , wrapper ) ;
}
2005-12-07 12:06:32 +03:00
#endif
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
else
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
wrapper = race ;
2005-01-03 11:26:21 +03:00
}
2002-12-18 19:00:25 +03:00
}
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
return wrapper ;
}
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
internal TypeWrapper DefineClass ( ClassFile f , object protectionDomain )
{
string dotnetAssembly = f . IKVMAssemblyAttribute ;
if ( dotnetAssembly ! = null )
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
// HACK only the bootstrap classloader can define .NET types (but for convenience, we do
// allow other class loaders to call DefineClass for them)
// TODO reconsider this, it might be a better idea to only allow netexp generated jars on the bootclasspath
return GetBootstrapClassLoader ( ) . DefineNetExpType ( f . Name , dotnetAssembly ) ;
2005-01-03 11:26:21 +03:00
}
lock ( types . SyncRoot )
{
2005-06-01 13:49:30 +04:00
if ( types . ContainsKey ( f . Name ) )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
throw new LinkageError ( "duplicate class definition: " + f . Name ) ;
}
// mark the type as "loading in progress", so that we can detect circular dependencies.
types . Add ( f . Name , null ) ;
}
try
{
TypeWrapper type = CreateDynamicTypeWrapper ( f , this , protectionDomain ) ;
lock ( types . SyncRoot )
{
// in very extreme conditions another thread may have beaten us to it
// and loaded a class with the same name, in that case we'll leak
// the defined DynamicTypeWrapper (or rather the Reflection.Emit
// defined type).
TypeWrapper race = ( TypeWrapper ) types [ f . Name ] ;
if ( race = = null )
{
Debug . Assert ( ! dynamicTypes . ContainsKey ( type . TypeAsTBD . FullName ) ) ;
dynamicTypes . Add ( type . TypeAsTBD . FullName , type ) ;
types [ f . Name ] = type ;
}
else
2004-08-17 13:05:21 +04:00
{
2005-07-27 19:57:55 +04:00
throw new LinkageError ( "duplicate class definition: " + f . Name ) ;
2004-08-17 13:05:21 +04:00
}
}
2005-06-01 13:49:30 +04:00
return type ;
}
catch
{
lock ( types . SyncRoot )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if ( types [ f . Name ] = = null )
{
// 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 ) ;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
throw ;
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
protected virtual TypeWrapper CreateDynamicTypeWrapper ( ClassFile f , ClassLoaderWrapper loader , object protectionDomain )
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
return new DynamicTypeWrapper ( f , loader , protectionDomain ) ;
2003-12-20 01:19:18 +03:00
}
2005-06-01 13:49:30 +04:00
private TypeWrapper DefineNetExpType ( string name , string assemblyName )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
Debug . Assert ( this = = GetBootstrapClassLoader ( ) ) ;
TypeWrapper type ;
lock ( types . SyncRoot )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
// we need to check if we've already got it, because other classloaders than the bootstrap classloader may
// "define" NetExp types, there is a potential race condition if multiple classloaders try to define the
// same type simultaneously.
type = ( TypeWrapper ) types [ name ] ;
if ( type ! = null )
{
return type ;
}
}
// The sole purpose of the netexp 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 ;
try
{
asm = Assembly . Load ( assemblyName ) ;
}
catch ( Exception x )
{
throw new NoClassDefFoundError ( name + " (" + x . Message + ")" ) ;
}
// pre-compiled Java types can also live in a netexp referenced assembly,
// so we have to explicitly check for those
// (DotNetTypeWrapper.CreateDotNetTypeWrapper will refuse to return Java types).
Type t = GetJavaTypeFromAssembly ( asm , name ) ;
if ( t ! = null )
{
return GetWrapperFromBootstrapType ( t ) ;
}
type = DotNetTypeWrapper . CreateDotNetTypeWrapper ( name ) ;
if ( type = = null )
{
throw new NoClassDefFoundError ( name + " not found in " + assemblyName ) ;
2003-08-08 16:37:14 +04:00
}
2005-01-03 11:26:21 +03:00
lock ( types . SyncRoot )
2003-08-08 16:37:14 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper race = ( TypeWrapper ) types [ name ] ;
2005-01-03 11:26:21 +03:00
if ( race = = null )
{
2005-06-01 13:49:30 +04:00
types . Add ( name , type ) ;
2005-01-03 11:26:21 +03:00
}
else
{
type = race ;
}
2003-08-08 16:37:14 +04:00
}
2005-01-03 11:26:21 +03:00
return type ;
}
2005-12-07 12:06:32 +03:00
#endif
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
internal object GetJavaClassLoader ( )
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
return ( this = = GetBootstrapClassLoader ( ) ) ? null : javaClassLoader ;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
// When -Xbootclasspath is specified, we use a URLClassLoader as an
// additional bootstrap class loader (this is not visible to the Java code).
// We need to access this to be able to load resources.
internal static object GetJavaBootstrapClassLoader ( )
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
return GetBootstrapClassLoader ( ) . javaClassLoader ;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
2005-12-07 12:06:32 +03:00
#if ! COMPACT_FRAMEWORK
2005-06-01 13:49:30 +04:00
internal static void PrepareForSaveDebugImage ( )
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
Debug . Assert ( moduleBuilder = = null ) ;
saveDebugImage = true ;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
internal static bool IsSaveDebugImage
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
get
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
return saveDebugImage ;
2004-08-17 13:05:21 +04:00
}
2003-12-20 01:19:18 +03:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal static void FinishAll ( )
2002-12-18 19:00:25 +03:00
{
2005-08-05 12:40:54 +04:00
JVM . FinishingForDebugSave = true ;
2005-06-01 13:49:30 +04:00
while ( dynamicTypes . Count > 0 )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
ArrayList l = new ArrayList ( dynamicTypes . Values ) ;
foreach ( TypeWrapper tw in l )
{
2005-06-16 11:38:08 +04:00
string name = tw . TypeAsTBD . FullName ;
Tracer . Info ( Tracer . Runtime , "Finishing {0}" , name ) ;
2005-08-05 12:40:54 +04:00
tw . Finish ( ) ;
2005-06-16 11:38:08 +04:00
dynamicTypes . Remove ( name ) ;
2005-06-01 13:49:30 +04:00
}
2002-12-18 19:00:25 +03:00
}
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal static void SaveDebugImage ( object mainClass )
2004-09-05 13:37:58 +04:00
{
2005-06-01 13:49:30 +04:00
FinishAll ( ) ;
// HACK use reflection to get the type from the class
TypeWrapper mainTypeWrapper = IKVM . NativeCode . java . lang . VMClass . getWrapperFromClass ( mainClass ) ;
mainTypeWrapper . Finish ( ) ;
Type mainType = mainTypeWrapper . TypeAsTBD ;
MethodInfo main = mainType . GetMethod ( "main" , BindingFlags . Static | BindingFlags . Public | BindingFlags . NonPublic , null , new Type [ ] { typeof ( string [ ] ) } , null ) ;
AssemblyBuilder asm = ( ( AssemblyBuilder ) moduleBuilder . Assembly ) ;
asm . SetEntryPoint ( main , PEFileKinds . ConsoleApplication ) ;
asm . Save ( "ikvmdump.exe" ) ;
if ( saveDebugAssemblies ! = null )
2004-09-05 13:37:58 +04:00
{
2005-06-01 13:49:30 +04:00
foreach ( AssemblyBuilder ab in saveDebugAssemblies )
{
ab . Save ( ab . GetName ( ) . Name + ".dll" ) ;
}
2004-09-05 13:37:58 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal static void RegisterForSaveDebug ( AssemblyBuilder ab )
2004-09-05 13:37:58 +04:00
{
2005-06-01 13:49:30 +04:00
if ( saveDebugAssemblies = = null )
{
saveDebugAssemblies = new ArrayList ( ) ;
}
saveDebugAssemblies . Add ( ab ) ;
2004-09-05 13:37:58 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal ModuleBuilder ModuleBuilder
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
lock ( this )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if ( moduleBuilder = = null )
{
moduleBuilder = CreateModuleBuilder ( ) ;
}
return moduleBuilder ;
2002-12-18 19:00:25 +03:00
}
}
}
2005-06-01 13:49:30 +04:00
protected virtual ModuleBuilder CreateModuleBuilder ( )
2004-09-05 13:37:58 +04:00
{
2005-06-01 13:49:30 +04:00
AssemblyName name = new AssemblyName ( ) ;
if ( saveDebugImage )
{
name . Name = "ikvmdump" ;
}
else
{
name . Name = "ikvm_dynamic_assembly__" + instanceId + "__" + ( uint ) Environment . TickCount ;
}
DateTime now = DateTime . Now ;
name . Version = new Version ( now . Year , ( now . Month * 100 ) + now . Day , ( now . Hour * 100 ) + now . Minute , ( now . Second * 1000 ) + now . Millisecond ) ;
2005-12-19 18:12:49 +03:00
AssemblyBuilder assemblyBuilder ;
#if WHIDBEY
if ( JVM . IsIkvmStub )
{
assemblyBuilder = AppDomain . CurrentDomain . DefineDynamicAssembly ( name , AssemblyBuilderAccess . ReflectionOnly , null , null , null , null , null , true ) ;
}
else
#endif
assemblyBuilder = AppDomain . CurrentDomain . DefineDynamicAssembly ( name , saveDebugImage ? AssemblyBuilderAccess . RunAndSave : AssemblyBuilderAccess . Run , null , null , null , null , null , true ) ;
2005-06-01 13:49:30 +04:00
CustomAttributeBuilder debugAttr = new CustomAttributeBuilder ( typeof ( DebuggableAttribute ) . GetConstructor ( new Type [ ] { typeof ( bool ) , typeof ( bool ) } ) , new object [ ] { true , JVM . Debug } ) ;
assemblyBuilder . SetCustomAttribute ( debugAttr ) ;
2006-01-02 11:15:43 +03:00
ModuleBuilder moduleBuilder = saveDebugImage ? assemblyBuilder . DefineDynamicModule ( "ikvmdump.exe" , "ikvmdump.exe" , JVM . Debug ) : assemblyBuilder . DefineDynamicModule ( name . Name , JVM . Debug ) ;
if ( ! JVM . NoStackTraceInfo )
{
AttributeHelper . SetSourceFile ( moduleBuilder , null ) ;
}
return moduleBuilder ;
2004-09-05 13:37:58 +04:00
}
2005-12-07 12:06:32 +03:00
#endif
2002-12-18 19:00:25 +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 ;
}
ArrayList list = new ArrayList ( ) ;
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
}
2005-06-01 13:49:30 +04:00
TypeWrapper [ ] types = new TypeWrapper [ list . Count ] ;
list . CopyTo ( types ) ;
return types ;
2002-12-18 19:00:25 +03:00
}
2004-09-09 15:17:55 +04:00
2005-06-01 13:49:30 +04:00
internal static ClassLoaderWrapper GetBootstrapClassLoader ( )
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
lock ( typeof ( ClassLoaderWrapper ) )
{
if ( bootstrapClassLoader = = null )
{
bootstrapClassLoader = new ClassLoaderWrapper ( null ) ;
}
return bootstrapClassLoader ;
}
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
internal static ClassLoaderWrapper GetSystemClassLoader ( )
2004-09-09 15:17:55 +04:00
{
2005-06-01 13:49:30 +04:00
// during static compilation, we don't have a system class loader
if ( JVM . IsStaticCompiler )
{
return GetBootstrapClassLoader ( ) ;
}
if ( systemClassLoader = = null )
{
systemClassLoader = GetClassLoaderWrapper ( JVM . Library . getSystemClassLoader ( ) ) ;
}
return systemClassLoader ;
2004-09-09 15:17:55 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal static ClassLoaderWrapper GetClassLoaderWrapper ( object javaClassLoader )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if ( javaClassLoader = = null | | GetBootstrapClassLoader ( ) . javaClassLoader = = javaClassLoader )
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
{
2005-09-06 12:06:04 +04:00
ClassLoaderWrapper wrapper = ( ClassLoaderWrapper ) JVM . Library . getWrapperFromClassLoader ( javaClassLoader ) ;
2005-06-01 13:49:30 +04:00
if ( wrapper = = null )
{
wrapper = new ClassLoaderWrapper ( javaClassLoader ) ;
2005-09-06 12:06:04 +04:00
JVM . Library . 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
}
2005-06-01 13:49:30 +04:00
// This only returns the wrapper for a Type if that wrapper has already been created, otherwise
// it returns null
// If the wrapper doesn't exist, that means that the type is either a .NET type or a pre-compiled Java class
internal static TypeWrapper GetWrapperFromTypeFast ( Type type )
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper . AssertFinished ( type ) ;
TypeWrapper wrapper = ( TypeWrapper ) typeToTypeWrapper [ type ] ;
if ( wrapper = = null )
2003-02-15 21:52:32 +03:00
{
2005-06-01 13:49:30 +04:00
string name = ( string ) remappedTypes [ type ] ;
if ( name ! = null )
{
return LoadClassCritical ( name ) ;
}
2003-02-15 21:52:32 +03:00
}
2005-06-01 13:49:30 +04:00
return wrapper ;
2003-02-15 21:52:32 +03:00
}
2005-06-01 13:49:30 +04:00
internal static TypeWrapper GetWrapperFromType ( Type type )
2003-02-15 21:52:32 +03:00
{
2005-06-01 13:49:30 +04:00
//Tracer.Info(Tracer.Runtime, "GetWrapperFromType: {0}", type.AssemblyQualifiedName);
TypeWrapper . AssertFinished ( type ) ;
TypeWrapper wrapper = GetWrapperFromTypeFast ( type ) ;
if ( wrapper = = null )
2003-02-17 13:13:16 +03:00
{
2005-06-01 13:49:30 +04:00
Debug . Assert ( type ! = typeof ( object ) & & type ! = typeof ( string ) ) ;
if ( type . IsArray )
2003-02-17 13:13:16 +03:00
{
2005-06-01 13:49:30 +04:00
// it might be an array of a dynamically compiled Java type
int rank = 1 ;
Type elem = type . GetElementType ( ) ;
while ( elem . IsArray )
{
rank + + ;
elem = elem . GetElementType ( ) ;
}
wrapper = GetWrapperFromType ( elem ) ;
return wrapper . MakeArrayType ( rank ) ;
2003-02-17 13:13:16 +03:00
}
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
// was "loaded" by the bootstrap classloader
// TODO think up a scheme to deal with .NET types that have the same name. Since all .NET types
// appear in the boostrap classloader, we need to devise a scheme to mangle the class name
return GetBootstrapClassLoader ( ) . GetWrapperFromBootstrapType ( type ) ;
2003-02-17 13:13:16 +03:00
}
2005-06-01 13:49:30 +04:00
return wrapper ;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal static void SetWrapperForType ( Type type , TypeWrapper wrapper )
{
TypeWrapper . AssertFinished ( type ) ;
Debug . Assert ( ! typeToTypeWrapper . ContainsKey ( type ) ) ;
typeToTypeWrapper . Add ( type , wrapper ) ;
}
2004-11-23 20:46:39 +03:00
2005-06-01 13:49:30 +04:00
internal static void PublishLibraryImplementationHelperType ( Type type )
2003-12-24 14:51:41 +03:00
{
2005-06-01 13:49:30 +04:00
CompiledTypeWrapper typeWrapper = CompiledTypeWrapper . newInstance ( type . FullName , type ) ;
SetWrapperForType ( type , typeWrapper ) ;
GetBootstrapClassLoader ( ) . types [ type . FullName ] = typeWrapper ;
2003-12-24 14:51:41 +03: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 )
{
nativeLibraries = new ArrayList ( ) ;
}
nativeLibraries . Add ( p ) ;
2004-08-30 19:56:23 +04:00
}
}
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 ] ;
}
return ( IntPtr [ ] ) nativeLibraries . ToArray ( typeof ( IntPtr ) ) ;
2004-08-30 19:56:23 +04:00
}
}
2005-02-23 15:56:15 +03:00
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
}
}
2002-12-18 19:00:25 +03:00
}