2006-02-22 17:44:07 +03:00
|
|
|
/*
|
|
|
|
Copyright (C) 2002, 2003, 2004, 2005, 2006 Jeroen Frijters
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
*/
|
|
|
|
#if !COMPACT_FRAMEWORK
|
|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.Reflection.Emit;
|
|
|
|
|
|
|
|
namespace IKVM.Internal
|
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
class DynamicClassLoader : TypeWrapperFactory
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-07-05 12:46:56 +04:00
|
|
|
#if !WHIDBEY
|
|
|
|
internal static bool arrayConstructionHack;
|
|
|
|
internal static readonly object arrayConstructionLock = new object();
|
|
|
|
#endif // !WHIDBEY
|
2006-02-22 17:44:07 +03:00
|
|
|
private static readonly Hashtable dynamicTypes = Hashtable.Synchronized(new Hashtable());
|
2006-07-24 12:21:11 +04:00
|
|
|
private static readonly char[] specialCharacters = { '\\', '+', ',', '[', ']' };
|
|
|
|
private static readonly string specialCharactersString = new String(specialCharacters);
|
2006-02-22 17:44:07 +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 ArrayList saveDebugAssemblies;
|
|
|
|
private static int instanceCounter = 0;
|
|
|
|
private int instanceId = System.Threading.Interlocked.Increment(ref instanceCounter);
|
2006-07-06 17:53:51 +04:00
|
|
|
private ClassLoaderWrapper classLoader;
|
2006-02-22 17:44:07 +03:00
|
|
|
|
|
|
|
static DynamicClassLoader()
|
|
|
|
{
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2006-07-06 17:53:51 +04:00
|
|
|
internal DynamicClassLoader(ClassLoaderWrapper classLoader)
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
this.classLoader = classLoader;
|
2006-02-22 17:44:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private static Assembly OnTypeResolve(object sender, ResolveEventArgs args)
|
|
|
|
{
|
2006-07-05 12:46:56 +04:00
|
|
|
#if !WHIDBEY
|
2006-02-22 17:44:07 +03:00
|
|
|
lock(arrayConstructionLock)
|
|
|
|
{
|
|
|
|
Tracer.Info(Tracer.ClassLoading, "OnTypeResolve: {0} (arrayConstructionHack = {1})", args.Name, arrayConstructionHack);
|
|
|
|
if(arrayConstructionHack)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2006-07-05 12:46:56 +04:00
|
|
|
#endif // !WHIDBEY
|
2006-02-22 17:44:07 +03:00
|
|
|
TypeWrapper type = (TypeWrapper)dynamicTypes[args.Name];
|
|
|
|
if(type == null)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
type.Finish();
|
|
|
|
}
|
2006-04-10 13:09:09 +04:00
|
|
|
#if !STATIC_COMPILER
|
2006-02-22 17:44:07 +03:00
|
|
|
catch(RetargetableJavaException x)
|
|
|
|
{
|
|
|
|
throw x.ToJava();
|
|
|
|
}
|
2006-04-10 13:09:09 +04:00
|
|
|
#endif // !STATIC_COMPILER
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
}
|
2006-02-22 17:44:07 +03:00
|
|
|
// 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.
|
2006-05-05 15:21:15 +04:00
|
|
|
// UPDATE since we now also use the dynamicTypes hashtable to keep track of type names that
|
|
|
|
// have been used already, we cannot remove the keys.
|
2006-02-22 17:44:07 +03:00
|
|
|
return type.TypeAsTBD.Assembly;
|
|
|
|
}
|
|
|
|
|
2006-07-06 17:53:51 +04:00
|
|
|
internal override TypeWrapper DefineClassImpl(Hashtable types, ClassFile f, object protectionDomain)
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
DynamicTypeWrapper type = CreateDynamicTypeWrapper(f);
|
|
|
|
// this step can throw a retargettable exception, if the class is incorrect
|
|
|
|
bool hasclinit;
|
|
|
|
type.CreateStep1(out hasclinit);
|
|
|
|
// now we can allocate the mangledTypeName, because the next step cannot fail
|
|
|
|
string mangledTypeName = f.Name;
|
|
|
|
lock(dynamicTypes.SyncRoot)
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-07-24 12:21:11 +04:00
|
|
|
// Ref.Emit doesn't like the "<Module>" name for types
|
|
|
|
// (since it already defines a pseudo-type named <Module> for global methods and fields)
|
|
|
|
if(mangledTypeName == "<Module>")
|
|
|
|
{
|
|
|
|
mangledTypeName = "_Module_";
|
|
|
|
}
|
|
|
|
if(mangledTypeName.IndexOfAny(specialCharacters) >= 0)
|
|
|
|
{
|
|
|
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
|
|
|
foreach(char c in mangledTypeName)
|
|
|
|
{
|
|
|
|
if(specialCharactersString.IndexOf(c) >= 0)
|
|
|
|
{
|
|
|
|
sb.Append('\\');
|
|
|
|
}
|
|
|
|
sb.Append(c);
|
|
|
|
}
|
|
|
|
mangledTypeName = sb.ToString();
|
|
|
|
}
|
2006-07-06 17:53:51 +04:00
|
|
|
// FXBUG the 1.1 CLR doesn't like type names that end with a period.
|
|
|
|
if(dynamicTypes.ContainsKey(mangledTypeName) || mangledTypeName.EndsWith("."))
|
2006-07-04 14:13:32 +04:00
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
#if STATIC_COMPILER
|
|
|
|
Tracer.Warning(Tracer.Compiler, "Class name clash: {0}", mangledTypeName);
|
2006-07-04 14:13:32 +04:00
|
|
|
#endif
|
2006-07-06 17:53:51 +04:00
|
|
|
mangledTypeName += "/" + instanceId;
|
2006-07-04 14:13:32 +04:00
|
|
|
}
|
2006-07-06 17:53:51 +04:00
|
|
|
dynamicTypes.Add(mangledTypeName, null);
|
2006-02-22 17:44:07 +03:00
|
|
|
}
|
2006-07-06 17:53:51 +04:00
|
|
|
// This step actually creates the TypeBuilder. It is not allowed to throw any exceptions,
|
|
|
|
// if an exception does occur, it is due to a programming error in the IKVM or CLR runtime
|
|
|
|
// and will cause a CriticalFailure and exit the process.
|
|
|
|
type.CreateStep2NoFail(hasclinit, mangledTypeName);
|
2006-02-22 17:44:07 +03:00
|
|
|
lock(types.SyncRoot)
|
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
// in very extreme conditions another thread may have beaten us to it
|
|
|
|
// and loaded (not defined) a class with the same name, in that case
|
|
|
|
// we'll leak the the Reflection.Emit defined type. Also see the comment
|
|
|
|
// in ClassLoaderWrapper.RegisterInitiatingLoader().
|
|
|
|
TypeWrapper race = (TypeWrapper)types[f.Name];
|
|
|
|
if(race == null)
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
Debug.Assert(dynamicTypes.ContainsKey(mangledTypeName) && dynamicTypes[mangledTypeName] == null);
|
|
|
|
dynamicTypes[mangledTypeName] = type;
|
|
|
|
types[f.Name] = type;
|
2006-04-10 13:09:09 +04:00
|
|
|
#if !STATIC_COMPILER
|
2006-07-06 17:53:51 +04:00
|
|
|
type.SetClassObject(JVM.Library.newClass(type, protectionDomain));
|
2006-04-10 13:09:09 +04:00
|
|
|
#endif
|
2006-02-22 17:44:07 +03:00
|
|
|
}
|
2006-07-06 17:53:51 +04:00
|
|
|
else
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
throw new LinkageError("duplicate class definition: " + f.Name);
|
2006-02-22 17:44:07 +03:00
|
|
|
}
|
|
|
|
}
|
2006-07-06 17:53:51 +04:00
|
|
|
return type;
|
2006-02-22 17:44:07 +03:00
|
|
|
}
|
|
|
|
|
2006-05-05 15:21:15 +04:00
|
|
|
protected virtual DynamicTypeWrapper CreateDynamicTypeWrapper(ClassFile f)
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
return new DynamicTypeWrapper(f, classLoader);
|
2006-02-22 17:44:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal static void PrepareForSaveDebugImage()
|
|
|
|
{
|
|
|
|
Debug.Assert(moduleBuilder == null);
|
|
|
|
saveDebugImage = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static bool IsSaveDebugImage
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return saveDebugImage;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-10 13:09:09 +04:00
|
|
|
internal static void FinishAll(bool forDebug)
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-04-10 13:09:09 +04:00
|
|
|
JVM.FinishingForDebugSave = forDebug;
|
2006-05-05 15:21:15 +04:00
|
|
|
Hashtable done = new Hashtable();
|
|
|
|
bool more = true;
|
|
|
|
while(more)
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
2006-05-05 15:21:15 +04:00
|
|
|
more = false;
|
2006-02-22 17:44:07 +03:00
|
|
|
ArrayList l = new ArrayList(dynamicTypes.Values);
|
|
|
|
foreach(TypeWrapper tw in l)
|
|
|
|
{
|
2006-05-05 15:21:15 +04:00
|
|
|
if(!done.ContainsKey(tw))
|
|
|
|
{
|
|
|
|
more = true;
|
|
|
|
done.Add(tw, tw);
|
|
|
|
Tracer.Info(Tracer.Runtime, "Finishing {0}", tw.TypeAsTBD.FullName);
|
|
|
|
tw.Finish();
|
|
|
|
}
|
2006-02-22 17:44:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-10 13:09:09 +04:00
|
|
|
#if !STATIC_COMPILER
|
2006-02-22 17:44:07 +03:00
|
|
|
internal static void SaveDebugImage(object mainClass)
|
|
|
|
{
|
2006-04-10 13:09:09 +04:00
|
|
|
FinishAll(true);
|
2006-03-27 17:59:59 +04:00
|
|
|
TypeWrapper mainTypeWrapper = TypeWrapper.FromClass(mainClass);
|
2006-02-22 17:44:07 +03:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
foreach(AssemblyBuilder ab in saveDebugAssemblies)
|
|
|
|
{
|
|
|
|
ab.Save(ab.GetName().Name + ".dll");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-04-10 13:09:09 +04:00
|
|
|
#endif
|
2006-02-22 17:44:07 +03:00
|
|
|
|
|
|
|
internal static void RegisterForSaveDebug(AssemblyBuilder ab)
|
|
|
|
{
|
|
|
|
if(saveDebugAssemblies == null)
|
|
|
|
{
|
|
|
|
saveDebugAssemblies = new ArrayList();
|
|
|
|
}
|
|
|
|
saveDebugAssemblies.Add(ab);
|
|
|
|
}
|
|
|
|
|
2006-07-06 17:53:51 +04:00
|
|
|
internal override ModuleBuilder ModuleBuilder
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2006-07-06 17:53:51 +04:00
|
|
|
lock(typeof(DynamicClassLoader))
|
2006-02-22 17:44:07 +03:00
|
|
|
{
|
|
|
|
if(moduleBuilder == null)
|
|
|
|
{
|
|
|
|
moduleBuilder = CreateModuleBuilder();
|
|
|
|
}
|
|
|
|
return moduleBuilder;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected virtual ModuleBuilder CreateModuleBuilder()
|
|
|
|
{
|
2006-07-04 14:13:32 +04:00
|
|
|
#if STATIC_COMPILER
|
|
|
|
// HACK this is required because DelegateInnerClassTypeWrapper currently uses the ModuleBuilder
|
|
|
|
// property to get a ModuleBuilder on the class loader that defined the delegate,
|
|
|
|
// instead of the class loader that is using the delegate (as it probably should)
|
2006-07-06 17:53:51 +04:00
|
|
|
return ClassLoaderWrapper.GetBootstrapClassLoader().ModuleBuilder;
|
2006-07-04 14:13:32 +04:00
|
|
|
#else // STATIC_COMPILER
|
2006-02-22 17:44:07 +03: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);
|
2006-05-15 13:08:01 +04:00
|
|
|
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, saveDebugImage ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run, null, null, null, null, null, true);
|
2006-02-22 17:44:07 +03:00
|
|
|
CustomAttributeBuilder debugAttr = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[] { typeof(bool), typeof(bool) }), new object[] { true, JVM.Debug });
|
|
|
|
assemblyBuilder.SetCustomAttribute(debugAttr);
|
2006-07-04 14:13:32 +04:00
|
|
|
return saveDebugImage ? assemblyBuilder.DefineDynamicModule("ikvmdump.exe", "ikvmdump.exe", JVM.Debug) : assemblyBuilder.DefineDynamicModule(name.Name, JVM.Debug);
|
2006-05-04 12:09:56 +04:00
|
|
|
#endif // STATIC_COMPILER
|
2006-02-22 17:44:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif //COMPACT_FRAMEWORK
|