IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
DynamicClassLoader.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2014 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*/
24using System;
25using System.Collections.Generic;
26using System.Runtime.Serialization;
27
29
30using static System.Diagnostics.DebuggableAttribute;
31
32#if IMPORTER
33using IKVM.Reflection;
36
37using Type = IKVM.Reflection.Type;
38using ProtectionDomain = System.Object;
39#else
40using System.Reflection;
41using System.Reflection.Emit;
42
43using ProtectionDomain = java.security.ProtectionDomain;
44#endif
45
46namespace IKVM.Runtime
47{
48
52 internal sealed class DynamicClassLoader : RuntimeJavaTypeFactory
53 {
54
55#if !IMPORTER
56 static AssemblyBuilder jniProxyAssemblyBuilder;
57#endif
58
59 readonly RuntimeContext context;
60 readonly IDiagnosticHandler diagnostics;
61 readonly ModuleBuilder moduleBuilder;
62 readonly bool hasInternalAccess;
63
64#if IMPORTER
65 TypeBuilder proxiesContainer;
66 List<TypeBuilder> proxies;
67#endif
68
69 Dictionary<string, TypeBuilder> unloadables;
70 TypeBuilder unloadableContainer;
71 Type[] delegates;
72
80 internal DynamicClassLoader(RuntimeContext context, IDiagnosticHandler diagnostics, ModuleBuilder moduleBuilder, bool hasInternalAccess)
81 {
82 this.context = context ?? throw new ArgumentNullException(nameof(context));
83 this.diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
84 this.moduleBuilder = moduleBuilder;
85 this.hasInternalAccess = hasInternalAccess;
86 }
87
93 internal override bool ReserveName(string name)
94 {
95 return context.DynamicClassLoaderFactory.ReserveName(name);
96 }
97
103 internal override string AllocMangledName(RuntimeByteCodeJavaType javaType)
104 {
105 return DynamicClassLoaderFactory.TypeNameMangleImpl(context.DynamicClassLoaderFactory.dynamicTypes, javaType.Name, javaType);
106 }
107
108 internal sealed override RuntimeJavaType DefineClassImpl(Dictionary<string, RuntimeJavaType> types, RuntimeJavaType host, ClassFile f, RuntimeClassLoader classLoader, ProtectionDomain protectionDomain)
109 {
110#if IMPORTER
111 var type = new RuntimeImportByteCodeJavaType(f, (ImportClassLoader)classLoader);
112 type.CreateStep1();
113 types[f.Name] = type;
114 return type;
115#elif FIRST_PASS
116 return null;
117#else
118 // this step can throw a retargettable exception, if the class is incorrect
119 var type = new RuntimeByteCodeJavaType(host, f, classLoader, protectionDomain);
120 // This step actually creates the TypeBuilder. It is not allowed to throw any exceptions,
121 // if an exception does occur, it is due to a programming error in the IKVM or CLR runtime
122 // and will cause a CriticalFailure and exit the process.
123 type.CreateStep1();
124 type.CreateStep2();
125 if (types == null)
126 {
127 // we're defining an anonymous class, so we don't need any locking
128 TieClassAndWrapper(type, protectionDomain);
129 return type;
130 }
131 lock (types)
132 {
133 // in very extreme conditions another thread may have beaten us to it
134 // and loaded (not defined) a class with the same name, in that case
135 // we'll leak the the Reflection.Emit defined type. Also see the comment
136 // in ClassLoaderWrapper.RegisterInitiatingLoader().
137 RuntimeJavaType race;
138 types.TryGetValue(f.Name, out race);
139 if (race == null)
140 {
141 types[f.Name] = type;
142 TieClassAndWrapper(type, protectionDomain);
143 }
144 else
145 {
146 throw new LinkageError("duplicate class definition: " + f.Name);
147 }
148 }
149
150 return type;
151#endif
152 }
153
154#if !IMPORTER && !FIRST_PASS
155
156 private static java.lang.Class TieClassAndWrapper(RuntimeJavaType type, ProtectionDomain protectionDomain)
157 {
158 java.lang.Class clazz = new java.lang.Class((java.lang.ClassLoader)null);
159 clazz.typeWrapper = type;
160 clazz.pd = protectionDomain;
161 type.SetClassObject(clazz);
162 return clazz;
163 }
164
165#endif
166
167#if IMPORTER
168
169 internal TypeBuilder DefineProxy(string name, TypeAttributes typeAttributes, Type parent, Type[] interfaces)
170 {
171 if (proxiesContainer == null)
172 {
173 proxiesContainer = moduleBuilder.DefineType(TypeNameUtil.ProxiesContainer, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract);
174 context.AttributeHelper.HideFromJava(proxiesContainer);
175 context.AttributeHelper.SetEditorBrowsableNever(proxiesContainer);
176 proxies = new List<TypeBuilder>();
177 }
178 TypeBuilder tb = proxiesContainer.DefineNestedType(name, typeAttributes, parent, interfaces);
179 proxies.Add(tb);
180 return tb;
181 }
182
183#endif
184
185 internal override Type DefineUnloadable(string name)
186 {
187 lock (this)
188 {
189 if (unloadables == null)
190 {
191 unloadables = new Dictionary<string, TypeBuilder>();
192 }
193 TypeBuilder type;
194 if (unloadables.TryGetValue(name, out type))
195 {
196 return type;
197 }
198 if (unloadableContainer == null)
199 {
200 unloadableContainer = moduleBuilder.DefineType(RuntimeUnloadableJavaType.ContainerTypeName, TypeAttributes.Interface | TypeAttributes.Abstract);
201 context.AttributeHelper.HideFromJava(unloadableContainer);
202 }
203 type = unloadableContainer.DefineNestedType(TypeNameUtil.MangleNestedTypeName(name), TypeAttributes.NestedPrivate | TypeAttributes.Interface | TypeAttributes.Abstract);
204 unloadables.Add(name, type);
205 return type;
206 }
207 }
208
209 internal override Type DefineDelegate(int parameterCount, bool returnVoid)
210 {
211 lock (this)
212 {
213 if (delegates == null)
214 {
215 delegates = new Type[512];
216 }
217 int index = parameterCount + (returnVoid ? 256 : 0);
218 Type type = delegates[index];
219 if (type != null)
220 {
221 return type;
222 }
223 TypeBuilder tb = moduleBuilder.DefineType(returnVoid ? "__<>NVIV`" + parameterCount : "__<>NVI`" + (parameterCount + 1), TypeAttributes.NotPublic | TypeAttributes.Sealed, context.Types.MulticastDelegate);
224 string[] names = new string[parameterCount + (returnVoid ? 0 : 1)];
225 for (int i = 0; i < names.Length; i++)
226 {
227 names[i] = "P" + i;
228 }
229 if (!returnVoid)
230 {
231 names[names.Length - 1] = "R";
232 }
233 Type[] genericParameters = tb.DefineGenericParameters(names);
234 Type[] parameterTypes = genericParameters;
235 if (!returnVoid)
236 {
237 parameterTypes = new Type[genericParameters.Length - 1];
238 Array.Copy(genericParameters, parameterTypes, parameterTypes.Length);
239 }
240 tb.DefineMethod(ConstructorInfo.ConstructorName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, context.Types.Void, new Type[] { context.Types.Object, context.Types.IntPtr })
241 .SetImplementationFlags(MethodImplAttributes.Runtime);
242 MethodBuilder mb = tb.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Virtual, returnVoid ? context.Types.Void : genericParameters[genericParameters.Length - 1], parameterTypes);
243 mb.SetImplementationFlags(MethodImplAttributes.Runtime);
244 type = tb.CreateType();
245 delegates[index] = type;
246 return type;
247 }
248 }
249
250 internal override bool HasInternalAccess
251 {
252 get { return hasInternalAccess; }
253 }
254
255 internal void FinishAll()
256 {
257 var done = new Dictionary<RuntimeJavaType, RuntimeJavaType>();
258 var more = true;
259
260 while (more)
261 {
262 more = false;
263 var l = context.DynamicClassLoaderFactory.dynamicTypes.ToArray();
264 foreach (var i in l)
265 {
266 var tw = i.Value;
267 if (tw != null && !done.ContainsKey(tw))
268 {
269 more = true;
270 done.Add(tw, tw);
271 diagnostics.GenericRuntimeTrace($"Finishing: {tw.TypeAsTBD.FullName}");
272 tw.Finish();
273 }
274 }
275 }
276
277 if (unloadableContainer != null)
278 {
279 unloadableContainer.CreateType();
280 foreach (var tb in unloadables.Values)
281 tb.CreateType();
282 }
283
284#if IMPORTER
285 if (proxiesContainer != null)
286 {
287 proxiesContainer.CreateType();
288 foreach (var tb in proxies)
289 tb.CreateType();
290 }
291
292#endif
293
294 }
295
296#if !IMPORTER
297
298 internal static ModuleBuilder CreateJniProxyModuleBuilder()
299 {
300 AssemblyName name = new AssemblyName();
301 name.Name = "jniproxy";
302 jniProxyAssemblyBuilder = DefineDynamicAssembly(name, AssemblyBuilderAccess.Run, null);
303 return jniProxyAssemblyBuilder.DefineDynamicModule("jniproxy.dll");
304 }
305
306#endif
307
308 internal sealed override ModuleBuilder ModuleBuilder => moduleBuilder;
309
310#if !IMPORTER
311
312#if NETFRAMEWORK
313
314 internal sealed class ForgedKeyPair : StrongNameKeyPair
315 {
316
317 internal static readonly StrongNameKeyPair Instance;
318
319 static ForgedKeyPair()
320 {
321 try
322 {
323 // this public key byte array must be the same as the public key in DynamicAssemblySuffixAndPublicKey
324 Instance = new ForgedKeyPair(new byte[] {
325 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00,
326 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53,
327 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x9D,
328 0x67, 0x4F, 0x3D, 0x63, 0xB8, 0xD7, 0xA4, 0xC4, 0x28, 0xBD, 0x73,
329 0x88, 0x34, 0x1B, 0x02, 0x5C, 0x71, 0xAA, 0x61, 0xC6, 0x22, 0x4C,
330 0xD5, 0x3A, 0x12, 0xC2, 0x13, 0x30, 0xA3, 0x15, 0x9D, 0x30, 0x00,
331 0x51, 0xFE, 0x2E, 0xED, 0x15, 0x4F, 0xE3, 0x0D, 0x70, 0x67, 0x3A,
332 0x07, 0x9E, 0x45, 0x29, 0xD0, 0xFD, 0x78, 0x11, 0x3D, 0xCA, 0x77,
333 0x1D, 0xA8, 0xB0, 0xC1, 0xEF, 0x2F, 0x77, 0xB7, 0x36, 0x51, 0xD5,
334 0x56, 0x45, 0xB0, 0xA4, 0x29, 0x4F, 0x0A, 0xF9, 0xBF, 0x70, 0x78,
335 0x43, 0x2E, 0x13, 0xD0, 0xF4, 0x6F, 0x95, 0x1D, 0x71, 0x2C, 0x2F,
336 0xCF, 0x02, 0xEB, 0x15, 0x55, 0x2C, 0x0F, 0xE7, 0x81, 0x7F, 0xC0,
337 0xAE, 0xD5, 0x8E, 0x09, 0x84, 0xF8, 0x66, 0x61, 0xBF, 0x64, 0xD8,
338 0x82, 0xF2, 0x9B, 0x61, 0x98, 0x99, 0xDD, 0x26, 0x40, 0x41, 0xE7,
339 0xD4, 0x99, 0x25, 0x48, 0xEB, 0x9E
340 });
341 }
342 catch
343 {
344
345 }
346 }
347
352 private ForgedKeyPair(byte[] publicKey) :
353 base(ToInfo(publicKey), new StreamingContext())
354 {
355
356 }
357
358 private static SerializationInfo ToInfo(byte[] publicKey)
359 {
360 byte[] privateKey = publicKey;
361 SerializationInfo info = new SerializationInfo(typeof(StrongNameKeyPair), new FormatterConverter());
362 info.AddValue("_keyPairExported", true);
363 info.AddValue("_keyPairArray", privateKey);
364 info.AddValue("_keyPairContainer", null);
365 info.AddValue("_publicKey", publicKey);
366 return info;
367 }
368 }
369
370#endif
371
372 public static ModuleBuilder CreateModuleBuilder(RuntimeContext context)
373 {
374 AssemblyName name = new AssemblyName();
375 name.Name = "ikvm_dynamic_assembly__" + (uint)Environment.TickCount;
376 return CreateModuleBuilder(context, name);
377 }
378
379 public static ModuleBuilder CreateModuleBuilder(RuntimeContext context, AssemblyName name)
380 {
381 var now = DateTime.Now;
382 name.Version = new Version(now.Year, (now.Month * 100) + now.Day, (now.Hour * 100) + now.Minute, (now.Second * 1000) + now.Millisecond);
383 var attribs = new List<CustomAttributeBuilder>();
384 AssemblyBuilderAccess access = AssemblyBuilderAccess.Run;
385
386#if NETFRAMEWORK
387 if (!AppDomain.CurrentDomain.IsFullyTrusted)
388 attribs.Add(new CustomAttributeBuilder(typeof(System.Security.SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
389#endif
390
391 var assemblyBuilder = DefineDynamicAssembly(name, access, attribs);
392 context.AttributeHelper.SetRuntimeCompatibilityAttribute(assemblyBuilder);
393
394 // determine debugging mode
395 var debugMode = DebuggingModes.Default | DebuggingModes.IgnoreSymbolStoreSequencePoints;
396 if (JVM.EmitSymbols)
397 debugMode |= DebuggingModes.DisableOptimizations;
398
399 context.AttributeHelper.SetDebuggingModes(assemblyBuilder, debugMode);
400
401#if NETFRAMEWORK
402 var moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name, JVM.EmitSymbols);
403#else
404 var moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name);
405#endif
406
407 moduleBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(IKVM.Attributes.JavaModuleAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
408 return moduleBuilder;
409 }
410
411 static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, IEnumerable<CustomAttributeBuilder> assemblyAttributes)
412 {
413#if NETFRAMEWORK
414 return AppDomain.CurrentDomain.DefineDynamicAssembly(name, access, null, true, assemblyAttributes);
415#else
416 return AssemblyBuilder.DefineDynamicAssembly(name, access, assemblyAttributes);
417#endif
418 }
419
420#endif
421
422 }
423
424}
java.security.ProtectionDomain ProtectionDomain
IKVM.Reflection.Type Type
IKVM.Reflection.AssemblyName AssemblyName
IKVM.Reflection.ConstructorInfo ConstructorInfo
Implementation of RuntimeClassLoader that emits loaded Java types to an AssemblyBuilder.
Implementation of RuntimeByteCodeJavaType that customizes output for the importer.
Exposes methods to accept diagnostic invocations.