~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/runtime/DynamicClassLoader.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2002-2011 Jeroen Frijters
 
3
 
 
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.
 
7
 
 
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:
 
11
 
 
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.
 
19
 
 
20
  Jeroen Frijters
 
21
  jeroen@frijters.net
 
22
  
 
23
*/
 
24
using System;
 
25
using System.Collections.Generic;
 
26
using System.Diagnostics;
 
27
#if STATIC_COMPILER
 
28
using IKVM.Reflection;
 
29
using IKVM.Reflection.Emit;
 
30
using Type = IKVM.Reflection.Type;
 
31
#else
 
32
using System.Reflection;
 
33
using System.Reflection.Emit;
 
34
#endif
 
35
 
 
36
namespace IKVM.Internal
 
37
{
 
38
        sealed class DynamicClassLoader : TypeWrapperFactory
 
39
        {
 
40
#if !STATIC_COMPILER
 
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;
 
46
#if STATIC_COMPILER
 
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());
 
56
#endif
 
57
#if CLASSGC
 
58
                private List<string> friends = new List<string>();
 
59
#endif
 
60
 
 
61
                [System.Security.SecuritySafeCritical]
 
62
                static DynamicClassLoader()
 
63
                {
 
64
#if !STATIC_COMPILER
 
65
                        if(JVM.IsSaveDebugImage)
 
66
                        {
 
67
#if !CLASSGC
 
68
                                saveClassLoaders.Add(instance);
 
69
#endif
 
70
                        }
 
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
 
75
                }
 
76
 
 
77
                internal DynamicClassLoader(ModuleBuilder moduleBuilder)
 
78
                {
 
79
                        this.moduleBuilder = moduleBuilder;
 
80
 
 
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);
 
84
                }
 
85
 
 
86
#if CLASSGC
 
87
                internal override void AddInternalsVisibleTo(Assembly friend)
 
88
                {
 
89
                        string name = friend.GetName().Name;
 
90
                        lock (friends)
 
91
                        {
 
92
                                if (!friends.Contains(name))
 
93
                                {
 
94
                                        friends.Add(name);
 
95
                                        ((AssemblyBuilder)moduleBuilder.Assembly).SetCustomAttribute(new CustomAttributeBuilder(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { name }));
 
96
                                }
 
97
                        }
 
98
                }
 
99
#endif // CLASSGC
 
100
 
 
101
#if !STATIC_COMPILER
 
102
                private static Assembly OnTypeResolve(object sender, ResolveEventArgs args)
 
103
                {
 
104
                        TypeWrapper type;
 
105
#if CLASSGC
 
106
                        DynamicClassLoader instance;
 
107
                        ClassLoaderWrapper loader = ClassLoaderWrapper.GetClassLoaderForDynamicJavaAssembly(args.RequestingAssembly);
 
108
                        if(loader == null)
 
109
                        {
 
110
                                return null;
 
111
                        }
 
112
                        instance = (DynamicClassLoader)loader.GetTypeWrapperFactory();
 
113
#endif
 
114
                        instance.dynamicTypes.TryGetValue(args.Name, out type);
 
115
                        if(type == null)
 
116
                        {
 
117
                                return null;
 
118
                        }
 
119
                        try
 
120
                        {
 
121
                                type.Finish();
 
122
                        }
 
123
                        catch(RetargetableJavaException x)
 
124
                        {
 
125
                                throw x.ToJava();
 
126
                        }
 
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;
 
134
                }
 
135
#endif // !STATIC_COMPILER
 
136
 
 
137
                internal override bool ReserveName(string name)
 
138
                {
 
139
                        lock(dynamicTypes)
 
140
                        {
 
141
                                if(dynamicTypes.ContainsKey(name))
 
142
                                {
 
143
                                        return false;
 
144
                                }
 
145
                                dynamicTypes.Add(name, null);
 
146
                                return true;
 
147
                        }
 
148
                }
 
149
 
 
150
                internal override string AllocMangledName(DynamicTypeWrapper tw)
 
151
                {
 
152
                        lock(dynamicTypes)
 
153
                        {
 
154
                                return TypeNameMangleImpl(dynamicTypes, tw.Name, tw);
 
155
                        }
 
156
                }
 
157
 
 
158
                internal static string TypeNameMangleImpl(Dictionary<string, TypeWrapper> dict, string name, TypeWrapper tw)
 
159
                {
 
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)
 
165
                        {
 
166
                                name = name.Substring(0, MaxLength) + "/truncated";
 
167
                        }
 
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("."))
 
172
                        {
 
173
#if STATIC_COMPILER
 
174
                                        Tracer.Warning(Tracer.Compiler, "Class name clash: {0}", mangledTypeName);
 
175
#endif
 
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;
 
179
                                int instanceId = 0;
 
180
                                do
 
181
                                {
 
182
                                        mangledTypeName = baseName + "/" + (++instanceId);
 
183
                                } while (dict.ContainsKey(mangledTypeName));
 
184
                        }
 
185
                        dict.Add(mangledTypeName, tw);
 
186
                        return mangledTypeName;
 
187
                }
 
188
 
 
189
                internal sealed override TypeWrapper DefineClassImpl(Dictionary<string, TypeWrapper> types, ClassFile f, ClassLoaderWrapper classLoader, object protectionDomain)
 
190
                {
 
191
#if STATIC_COMPILER
 
192
                        AotTypeWrapper type = new AotTypeWrapper(f, (CompilerClassLoader)classLoader);
 
193
                        type.CreateStep1();
 
194
                        types[f.Name] = type;
 
195
                        return type;
 
196
#else
 
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.
 
202
                        type.CreateStep1();
 
203
                        type.CreateStep2();
 
204
                        lock(types)
 
205
                        {
 
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().
 
210
                                TypeWrapper race;
 
211
                                types.TryGetValue(f.Name, out race);
 
212
                                if(race == null)
 
213
                                {
 
214
                                        types[f.Name] = type;
 
215
#if !FIRST_PASS
 
216
                                        java.lang.Class clazz = new java.lang.Class(null);
 
217
#if __MonoCS__
 
218
                                        TypeWrapper.SetTypeWrapperHack(clazz, type);
 
219
#else
 
220
                                        clazz.typeWrapper = type;
 
221
#endif
 
222
                                        clazz.pd = (java.security.ProtectionDomain)protectionDomain;
 
223
                                        type.SetClassObject(clazz);
 
224
#endif
 
225
                                }
 
226
                                else
 
227
                                {
 
228
                                        throw new LinkageError("duplicate class definition: " + f.Name);
 
229
                                }
 
230
                        }
 
231
                        return type;
 
232
#endif // STATIC_COMPILER
 
233
                }
 
234
 
 
235
#if STATIC_COMPILER
 
236
                internal void DefineProxyHelper(Type type)
 
237
                {
 
238
                        if(proxyHelperContainer == null)
 
239
                        {
 
240
                                proxyHelperContainer = moduleBuilder.DefineType("__<Proxy>", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
 
241
                                AttributeHelper.HideFromJava(proxyHelperContainer);
 
242
                                AttributeHelper.SetEditorBrowsableNever(proxyHelperContainer);
 
243
                                proxyHelpers = new List<TypeBuilder>();
 
244
                        }
 
245
                        proxyHelpers.Add(proxyHelperContainer.DefineNestedType(TypeNameUtil.MangleNestedTypeName(type.FullName), TypeAttributes.NestedPublic | TypeAttributes.Interface | TypeAttributes.Abstract, null, new Type[] { type }));
 
246
                }
 
247
 
 
248
                internal TypeBuilder DefineProxy(TypeWrapper proxyClass, TypeWrapper[] interfaces)
 
249
                {
 
250
                        if (proxiesContainer == null)
 
251
                        {
 
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>();
 
256
                        }
 
257
                        Type[] ifaces = new Type[interfaces.Length];
 
258
                        for (int i = 0; i < ifaces.Length; i++)
 
259
                        {
 
260
                                ifaces[i] = interfaces[i].TypeAsBaseType;
 
261
                        }
 
262
                        TypeBuilder tb = proxiesContainer.DefineNestedType(GetProxyNestedName(interfaces), TypeAttributes.NestedPublic | TypeAttributes.Class | TypeAttributes.Sealed, proxyClass.TypeAsBaseType, ifaces);
 
263
                        proxies.Add(tb);
 
264
                        return tb;
 
265
                }
 
266
#endif
 
267
 
 
268
                private static string GetProxyNestedName(TypeWrapper[] interfaces)
 
269
                {
 
270
                        System.Text.StringBuilder sb = new System.Text.StringBuilder();
 
271
                        foreach (TypeWrapper tw in interfaces)
 
272
                        {
 
273
                                sb.Append(tw.Name.Length).Append('|').Append(tw.Name);
 
274
                        }
 
275
                        return TypeNameUtil.MangleNestedTypeName(sb.ToString());
 
276
                }
 
277
 
 
278
                internal static string GetProxyName(TypeWrapper[] interfaces)
 
279
                {
 
280
                        return "__<Proxies>+" + GetProxyNestedName(interfaces);
 
281
                }
 
282
 
 
283
                internal static string GetProxyHelperName(Type type)
 
284
                {
 
285
                        return "__<Proxy>+" + TypeNameUtil.MangleNestedTypeName(type.FullName);
 
286
                }
 
287
 
 
288
                internal override Type DefineUnloadable(string name)
 
289
                {
 
290
                        lock(this)
 
291
                        {
 
292
                                if(unloadables == null)
 
293
                                {
 
294
                                        unloadables = new Dictionary<string, TypeBuilder>();
 
295
                                }
 
296
                                TypeBuilder type;
 
297
                                if(unloadables.TryGetValue(name, out type))
 
298
                                {
 
299
                                        return type;
 
300
                                }
 
301
                                if(unloadableContainer == null)
 
302
                                {
 
303
                                        unloadableContainer = moduleBuilder.DefineType("__<Unloadable>", TypeAttributes.Interface | TypeAttributes.Abstract);
 
304
                                        AttributeHelper.HideFromJava(unloadableContainer);
 
305
                                }
 
306
                                type = unloadableContainer.DefineNestedType(TypeNameUtil.MangleNestedTypeName(name), TypeAttributes.NestedPrivate | TypeAttributes.Interface | TypeAttributes.Abstract);
 
307
                                unloadables.Add(name, type);
 
308
                                return type;
 
309
                        }
 
310
                }
 
311
 
 
312
                internal void FinishAll()
 
313
                {
 
314
                        Dictionary<TypeWrapper, TypeWrapper> done = new Dictionary<TypeWrapper, TypeWrapper>();
 
315
                        bool more = true;
 
316
                        while(more)
 
317
                        {
 
318
                                more = false;
 
319
                                List<TypeWrapper> l = new List<TypeWrapper>(dynamicTypes.Values);
 
320
                                foreach(TypeWrapper tw in l)
 
321
                                {
 
322
                                        if(tw != null && !done.ContainsKey(tw))
 
323
                                        {
 
324
                                                more = true;
 
325
                                                done.Add(tw, tw);
 
326
                                                Tracer.Info(Tracer.Runtime, "Finishing {0}", tw.TypeAsTBD.FullName);
 
327
                                                tw.Finish();
 
328
                                        }
 
329
                                }
 
330
                        }
 
331
                        if(unloadableContainer != null)
 
332
                        {
 
333
                                unloadableContainer.CreateType();
 
334
                                foreach(TypeBuilder tb in unloadables.Values)
 
335
                                {
 
336
                                        tb.CreateType();
 
337
                                }
 
338
                        }
 
339
#if STATIC_COMPILER
 
340
                        if(proxyHelperContainer != null)
 
341
                        {
 
342
                                proxyHelperContainer.CreateType();
 
343
                                foreach(TypeBuilder tb in proxyHelpers)
 
344
                                {
 
345
                                        tb.CreateType();
 
346
                                }
 
347
                        }
 
348
                        if(proxiesContainer != null)
 
349
                        {
 
350
                                proxiesContainer.CreateType();
 
351
                                foreach(TypeBuilder tb in proxies)
 
352
                                {
 
353
                                        tb.CreateType();
 
354
                                }
 
355
                        }
 
356
#endif // STATIC_COMPILER
 
357
                }
 
358
 
 
359
#if !STATIC_COMPILER
 
360
                internal static void SaveDebugImages()
 
361
                {
 
362
                        JVM.FinishingForDebugSave = true;
 
363
                        if (saveClassLoaders != null)
 
364
                        {
 
365
                                foreach (DynamicClassLoader instance in saveClassLoaders)
 
366
                                {
 
367
                                        instance.FinishAll();
 
368
                                        AssemblyBuilder ab = (AssemblyBuilder)instance.ModuleBuilder.Assembly;
 
369
                                        ab.Save(ab.GetName().Name + ".dll");
 
370
                                }
 
371
                        }
 
372
                        if (saveDebugAssemblies != null)
 
373
                        {
 
374
                                foreach (AssemblyBuilder ab in saveDebugAssemblies)
 
375
                                {
 
376
                                        ab.Save(ab.GetName().Name + ".dll");
 
377
                                }
 
378
                        }
 
379
                }
 
380
 
 
381
                internal static void RegisterForSaveDebug(AssemblyBuilder ab)
 
382
                {
 
383
                        if(saveDebugAssemblies == null)
 
384
                        {
 
385
                                saveDebugAssemblies = new List<AssemblyBuilder>();
 
386
                        }
 
387
                        saveDebugAssemblies.Add(ab);
 
388
                }
 
389
#endif
 
390
 
 
391
                internal sealed override ModuleBuilder ModuleBuilder
 
392
                {
 
393
                        get
 
394
                        {
 
395
                                return moduleBuilder;
 
396
                        }
 
397
                }
 
398
 
 
399
                [System.Security.SecuritySafeCritical]
 
400
                internal static DynamicClassLoader Get(ClassLoaderWrapper loader)
 
401
                {
 
402
#if STATIC_COMPILER
 
403
                        DynamicClassLoader instance = new DynamicClassLoader(((CompilerClassLoader)loader).CreateModuleBuilder());
 
404
#elif CLASSGC
 
405
                        DynamicClassLoader instance = new DynamicClassLoader(CreateModuleBuilder());
 
406
                        if(saveClassLoaders != null)
 
407
                        {
 
408
                                saveClassLoaders.Add(instance);
 
409
                        }
 
410
#endif
 
411
                        return instance;
 
412
                }
 
413
 
 
414
#if !STATIC_COMPILER
 
415
                private static ModuleBuilder CreateModuleBuilder()
 
416
                {
 
417
                        AssemblyName name = new AssemblyName();
 
418
                        if(JVM.IsSaveDebugImage)
 
419
                        {
 
420
                                if(saveClassLoaders == null)
 
421
                                {
 
422
                                        System.Threading.Interlocked.CompareExchange(ref saveClassLoaders, new List<DynamicClassLoader>(), null);
 
423
                                }
 
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;
 
427
                        }
 
428
                        else
 
429
                        {
 
430
                                name.Name = "ikvm_dynamic_assembly__" + (uint)Environment.TickCount;
 
431
                        }
 
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)
 
437
                        {
 
438
                                access = AssemblyBuilderAccess.RunAndSave;
 
439
                        }
 
440
#if CLASSGC
 
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)
 
444
                        {
 
445
                                access = AssemblyBuilderAccess.RunAndCollect;
 
446
                        }
 
447
#endif
 
448
                        else
 
449
                        {
 
450
                                access = AssemblyBuilderAccess.Run;
 
451
                        }
 
452
#if NET_4_0
 
453
                        if(!AppDomain.CurrentDomain.IsFullyTrusted)
 
454
                        {
 
455
                                attribs.Add(new CustomAttributeBuilder(typeof(System.Security.SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
 
456
                        }
 
457
#endif
 
458
                        AssemblyBuilder assemblyBuilder =
 
459
#if NET_4_0
 
460
                                AppDomain.CurrentDomain.DefineDynamicAssembly(name, access, null, true, attribs);
 
461
#else
 
462
                                AppDomain.CurrentDomain.DefineDynamicAssembly(name, access, null, null, null, null, null, true, attribs);
 
463
#endif
 
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;
 
471
                }
 
472
#endif // !STATIC_COMPILER
 
473
        }
 
474
}