2
Copyright (C) 2002-2011 Jeroen Frijters
4
This software is provided 'as-is', without any express or implied
5
warranty. In no event will the authors be held liable for any damages
6
arising from the use of this software.
8
Permission is granted to anyone to use this software for any purpose,
9
including commercial applications, and to alter it and redistribute it
10
freely, subject to the following restrictions:
12
1. The origin of this software must not be misrepresented; you must not
13
claim that you wrote the original software. If you use this software
14
in a product, an acknowledgment in the product documentation would be
15
appreciated but is not required.
16
2. Altered source versions must be plainly marked as such, and must not be
17
misrepresented as being the original software.
18
3. This notice may not be removed or altered from any source distribution.
25
using System.Collections.Generic;
26
using System.Diagnostics;
28
using IKVM.Reflection;
29
using IKVM.Reflection.Emit;
30
using Type = IKVM.Reflection.Type;
32
using System.Reflection;
33
using System.Reflection.Emit;
36
namespace IKVM.Internal
38
sealed class DynamicClassLoader : TypeWrapperFactory
41
private static List<AssemblyBuilder> saveDebugAssemblies;
42
private static List<DynamicClassLoader> saveClassLoaders;
43
#endif // !STATIC_COMPILER
44
private readonly Dictionary<string, TypeWrapper> dynamicTypes = new Dictionary<string, TypeWrapper>();
45
private ModuleBuilder moduleBuilder;
47
private TypeBuilder proxyHelperContainer;
48
private List<TypeBuilder> proxyHelpers;
49
private TypeBuilder proxiesContainer;
50
private List<TypeBuilder> proxies;
51
#endif // STATIC_COMPILER
52
private Dictionary<string, TypeBuilder> unloadables;
53
private TypeBuilder unloadableContainer;
54
#if !STATIC_COMPILER && !CLASSGC
55
private static DynamicClassLoader instance = new DynamicClassLoader(CreateModuleBuilder());
58
private List<string> friends = new List<string>();
61
[System.Security.SecuritySafeCritical]
62
static DynamicClassLoader()
65
if(JVM.IsSaveDebugImage)
68
saveClassLoaders.Add(instance);
71
// TODO AppDomain.TypeResolve requires ControlAppDomain permission, but if we don't have that,
72
// we should handle that by disabling dynamic class loading
73
AppDomain.CurrentDomain.TypeResolve += new ResolveEventHandler(OnTypeResolve);
74
#endif // !STATIC_COMPILER
77
internal DynamicClassLoader(ModuleBuilder moduleBuilder)
79
this.moduleBuilder = moduleBuilder;
81
// Ref.Emit doesn't like the "<Module>" name for types
82
// (since it already defines a pseudo-type named <Module> for global methods and fields)
83
dynamicTypes.Add("<Module>", null);
87
internal override void AddInternalsVisibleTo(Assembly friend)
89
string name = friend.GetName().Name;
92
if (!friends.Contains(name))
95
((AssemblyBuilder)moduleBuilder.Assembly).SetCustomAttribute(new CustomAttributeBuilder(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { name }));
102
private static Assembly OnTypeResolve(object sender, ResolveEventArgs args)
106
DynamicClassLoader instance;
107
ClassLoaderWrapper loader = ClassLoaderWrapper.GetClassLoaderForDynamicJavaAssembly(args.RequestingAssembly);
112
instance = (DynamicClassLoader)loader.GetTypeWrapperFactory();
114
instance.dynamicTypes.TryGetValue(args.Name, out type);
123
catch(RetargetableJavaException x)
127
// NOTE We used to remove the type from the hashtable here, but that creates a race condition if
128
// another thread also fires the OnTypeResolve event while we're baking the type.
129
// I really would like to remove the type from the hashtable, but at the moment I don't see
130
// any way of doing that that wouldn't cause this race condition.
131
// UPDATE since we now also use the dynamicTypes hashtable to keep track of type names that
132
// have been used already, we cannot remove the keys.
133
return type.TypeAsTBD.Assembly;
135
#endif // !STATIC_COMPILER
137
internal override bool ReserveName(string name)
141
if(dynamicTypes.ContainsKey(name))
145
dynamicTypes.Add(name, null);
150
internal override string AllocMangledName(DynamicTypeWrapper tw)
154
return TypeNameMangleImpl(dynamicTypes, tw.Name, tw);
158
internal static string TypeNameMangleImpl(Dictionary<string, TypeWrapper> dict, string name, TypeWrapper tw)
160
// the CLR maximum type name length is 1023 characters,
161
// but we need to leave some room for the suffix that we
162
// may need to append to make the name unique
163
const int MaxLength = 1000;
164
if (name.Length > MaxLength)
166
name = name.Substring(0, MaxLength) + "/truncated";
168
string mangledTypeName = TypeNameUtil.ReplaceIllegalCharacters(name);
169
// FXBUG the CLR (both 1.1 and 2.0) doesn't like type names that end with a single period,
170
// it loses the trailing period in the name that gets passed in the TypeResolve event.
171
if (dict.ContainsKey(mangledTypeName) || mangledTypeName.EndsWith("."))
174
Tracer.Warning(Tracer.Compiler, "Class name clash: {0}", mangledTypeName);
176
// Java class names cannot contain slashes (since they are converted into periods),
177
// so we take advantage of that fact to create a unique name.
178
string baseName = mangledTypeName;
182
mangledTypeName = baseName + "/" + (++instanceId);
183
} while (dict.ContainsKey(mangledTypeName));
185
dict.Add(mangledTypeName, tw);
186
return mangledTypeName;
189
internal sealed override TypeWrapper DefineClassImpl(Dictionary<string, TypeWrapper> types, ClassFile f, ClassLoaderWrapper classLoader, object protectionDomain)
192
AotTypeWrapper type = new AotTypeWrapper(f, (CompilerClassLoader)classLoader);
194
types[f.Name] = type;
197
// this step can throw a retargettable exception, if the class is incorrect
198
DynamicTypeWrapper type = new DynamicTypeWrapper(f, classLoader);
199
// This step actually creates the TypeBuilder. It is not allowed to throw any exceptions,
200
// if an exception does occur, it is due to a programming error in the IKVM or CLR runtime
201
// and will cause a CriticalFailure and exit the process.
206
// in very extreme conditions another thread may have beaten us to it
207
// and loaded (not defined) a class with the same name, in that case
208
// we'll leak the the Reflection.Emit defined type. Also see the comment
209
// in ClassLoaderWrapper.RegisterInitiatingLoader().
211
types.TryGetValue(f.Name, out race);
214
types[f.Name] = type;
216
java.lang.Class clazz = new java.lang.Class(null);
218
TypeWrapper.SetTypeWrapperHack(clazz, type);
220
clazz.typeWrapper = type;
222
clazz.pd = (java.security.ProtectionDomain)protectionDomain;
223
type.SetClassObject(clazz);
228
throw new LinkageError("duplicate class definition: " + f.Name);
232
#endif // STATIC_COMPILER
236
internal void DefineProxyHelper(Type type)
238
if(proxyHelperContainer == null)
240
proxyHelperContainer = moduleBuilder.DefineType("__<Proxy>", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
241
AttributeHelper.HideFromJava(proxyHelperContainer);
242
AttributeHelper.SetEditorBrowsableNever(proxyHelperContainer);
243
proxyHelpers = new List<TypeBuilder>();
245
proxyHelpers.Add(proxyHelperContainer.DefineNestedType(TypeNameUtil.MangleNestedTypeName(type.FullName), TypeAttributes.NestedPublic | TypeAttributes.Interface | TypeAttributes.Abstract, null, new Type[] { type }));
248
internal TypeBuilder DefineProxy(TypeWrapper proxyClass, TypeWrapper[] interfaces)
250
if (proxiesContainer == null)
252
proxiesContainer = moduleBuilder.DefineType("__<Proxies>", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract);
253
AttributeHelper.HideFromJava(proxiesContainer);
254
AttributeHelper.SetEditorBrowsableNever(proxiesContainer);
255
proxies = new List<TypeBuilder>();
257
Type[] ifaces = new Type[interfaces.Length];
258
for (int i = 0; i < ifaces.Length; i++)
260
ifaces[i] = interfaces[i].TypeAsBaseType;
262
TypeBuilder tb = proxiesContainer.DefineNestedType(GetProxyNestedName(interfaces), TypeAttributes.NestedPublic | TypeAttributes.Class | TypeAttributes.Sealed, proxyClass.TypeAsBaseType, ifaces);
268
private static string GetProxyNestedName(TypeWrapper[] interfaces)
270
System.Text.StringBuilder sb = new System.Text.StringBuilder();
271
foreach (TypeWrapper tw in interfaces)
273
sb.Append(tw.Name.Length).Append('|').Append(tw.Name);
275
return TypeNameUtil.MangleNestedTypeName(sb.ToString());
278
internal static string GetProxyName(TypeWrapper[] interfaces)
280
return "__<Proxies>+" + GetProxyNestedName(interfaces);
283
internal static string GetProxyHelperName(Type type)
285
return "__<Proxy>+" + TypeNameUtil.MangleNestedTypeName(type.FullName);
288
internal override Type DefineUnloadable(string name)
292
if(unloadables == null)
294
unloadables = new Dictionary<string, TypeBuilder>();
297
if(unloadables.TryGetValue(name, out type))
301
if(unloadableContainer == null)
303
unloadableContainer = moduleBuilder.DefineType("__<Unloadable>", TypeAttributes.Interface | TypeAttributes.Abstract);
304
AttributeHelper.HideFromJava(unloadableContainer);
306
type = unloadableContainer.DefineNestedType(TypeNameUtil.MangleNestedTypeName(name), TypeAttributes.NestedPrivate | TypeAttributes.Interface | TypeAttributes.Abstract);
307
unloadables.Add(name, type);
312
internal void FinishAll()
314
Dictionary<TypeWrapper, TypeWrapper> done = new Dictionary<TypeWrapper, TypeWrapper>();
319
List<TypeWrapper> l = new List<TypeWrapper>(dynamicTypes.Values);
320
foreach(TypeWrapper tw in l)
322
if(tw != null && !done.ContainsKey(tw))
326
Tracer.Info(Tracer.Runtime, "Finishing {0}", tw.TypeAsTBD.FullName);
331
if(unloadableContainer != null)
333
unloadableContainer.CreateType();
334
foreach(TypeBuilder tb in unloadables.Values)
340
if(proxyHelperContainer != null)
342
proxyHelperContainer.CreateType();
343
foreach(TypeBuilder tb in proxyHelpers)
348
if(proxiesContainer != null)
350
proxiesContainer.CreateType();
351
foreach(TypeBuilder tb in proxies)
356
#endif // STATIC_COMPILER
360
internal static void SaveDebugImages()
362
JVM.FinishingForDebugSave = true;
363
if (saveClassLoaders != null)
365
foreach (DynamicClassLoader instance in saveClassLoaders)
367
instance.FinishAll();
368
AssemblyBuilder ab = (AssemblyBuilder)instance.ModuleBuilder.Assembly;
369
ab.Save(ab.GetName().Name + ".dll");
372
if (saveDebugAssemblies != null)
374
foreach (AssemblyBuilder ab in saveDebugAssemblies)
376
ab.Save(ab.GetName().Name + ".dll");
381
internal static void RegisterForSaveDebug(AssemblyBuilder ab)
383
if(saveDebugAssemblies == null)
385
saveDebugAssemblies = new List<AssemblyBuilder>();
387
saveDebugAssemblies.Add(ab);
391
internal sealed override ModuleBuilder ModuleBuilder
395
return moduleBuilder;
399
[System.Security.SecuritySafeCritical]
400
internal static DynamicClassLoader Get(ClassLoaderWrapper loader)
403
DynamicClassLoader instance = new DynamicClassLoader(((CompilerClassLoader)loader).CreateModuleBuilder());
405
DynamicClassLoader instance = new DynamicClassLoader(CreateModuleBuilder());
406
if(saveClassLoaders != null)
408
saveClassLoaders.Add(instance);
415
private static ModuleBuilder CreateModuleBuilder()
417
AssemblyName name = new AssemblyName();
418
if(JVM.IsSaveDebugImage)
420
if(saveClassLoaders == null)
422
System.Threading.Interlocked.CompareExchange(ref saveClassLoaders, new List<DynamicClassLoader>(), null);
424
// we ignore the race condition (we could end up with multiple assemblies with the same name),
425
// because it is pretty harmless (you'll miss one of the ikvmdump-xx.dll files)
426
name.Name = "ikvmdump-" + saveClassLoaders.Count;
430
name.Name = "ikvm_dynamic_assembly__" + (uint)Environment.TickCount;
432
DateTime now = DateTime.Now;
433
name.Version = new Version(now.Year, (now.Month * 100) + now.Day, (now.Hour * 100) + now.Minute, (now.Second * 1000) + now.Millisecond);
434
List<CustomAttributeBuilder> attribs = new List<CustomAttributeBuilder>();
435
AssemblyBuilderAccess access;
436
if(JVM.IsSaveDebugImage)
438
access = AssemblyBuilderAccess.RunAndSave;
441
else if(JVM.classUnloading
442
// DefineDynamicAssembly(..., RunAndCollect, ...) does a demand for PermissionSet(Unrestricted), so we want to avoid that in partial trust scenarios
443
&& AppDomain.CurrentDomain.IsFullyTrusted)
445
access = AssemblyBuilderAccess.RunAndCollect;
450
access = AssemblyBuilderAccess.Run;
453
if(!AppDomain.CurrentDomain.IsFullyTrusted)
455
attribs.Add(new CustomAttributeBuilder(typeof(System.Security.SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
458
AssemblyBuilder assemblyBuilder =
460
AppDomain.CurrentDomain.DefineDynamicAssembly(name, access, null, true, attribs);
462
AppDomain.CurrentDomain.DefineDynamicAssembly(name, access, null, null, null, null, null, true, attribs);
464
AttributeHelper.SetRuntimeCompatibilityAttribute(assemblyBuilder);
465
bool debug = JVM.EmitSymbols;
466
CustomAttributeBuilder debugAttr = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[] { typeof(bool), typeof(bool) }), new object[] { true, debug });
467
assemblyBuilder.SetCustomAttribute(debugAttr);
468
ModuleBuilder moduleBuilder = JVM.IsSaveDebugImage ? assemblyBuilder.DefineDynamicModule(name.Name, name.Name + ".dll", debug) : assemblyBuilder.DefineDynamicModule(name.Name, debug);
469
moduleBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(IKVM.Attributes.JavaModuleAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
470
return moduleBuilder;
472
#endif // !STATIC_COMPILER