IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ExportImpl.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.IO.Compression;
5using System.Linq;
6using System.Reflection.Metadata;
7using System.Reflection.PortableExecutable;
8
10using IKVM.Reflection;
11using IKVM.Runtime;
13
14using Type = IKVM.Reflection.Type;
15
16namespace IKVM.Tools.Exporter
17{
18
23 {
24
25 readonly ExportOptions options;
26 readonly IDiagnosticHandler diagnostics;
27
28 readonly Dictionary<string, string> done = new Dictionary<string, string>();
29 readonly Dictionary<string, RuntimeJavaType> todo = new Dictionary<string, RuntimeJavaType>();
30 ZipArchive zipFile;
31 FileInfo file;
32
37 public ExportImpl(ExportOptions options, IDiagnosticHandler diagnostics)
38 {
39 this.options = options ?? throw new ArgumentNullException(nameof(options));
40 this.diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
41 }
42
46 public int Execute()
47 {
48 var references = new List<string>();
49 if (options.References != null)
50 foreach (var reference in options.References)
51 references.Add(reference);
52
53 var libpaths = new List<string>();
54 if (options.Libraries != null)
55 foreach (var library in options.Libraries)
56 libpaths.Add(library);
57
58 var namespaces = new List<string>();
59 if (options.Namespaces != null)
60 foreach (var ns in options.Namespaces)
61 namespaces.Add(ns);
62
63 if (File.Exists(options.Assembly) && options.NoStdLib)
64 {
65 // Add the target assembly to the references list, to allow it to be considered as "mscorlib".
66 // This allows "ikvmstub -nostdlib \...\mscorlib.dll" to work.
67 references.Add(options.Assembly);
68 }
69
70 // discover the core lib from the references
71 var coreLibName = FindCoreLibName(references, libpaths);
72 if (coreLibName == null)
73 {
74 diagnostics.CoreClassesMissing();
75 return 1;
76 }
77
78 // build universe and resolver against universe and references
79 var universe = new Universe(coreLibName);
80 var assemblyResolver = new AssemblyResolver();
81 assemblyResolver.Warning += new AssemblyResolver.WarningEvent(Resolver_Warning);
82 assemblyResolver.Init(universe, options.NoStdLib, references, libpaths);
83
84 var cache = new Dictionary<string, Assembly>();
85 foreach (var reference in references)
86 {
87 Assembly[] dummy = null;
88 if (assemblyResolver.ResolveReference(cache, ref dummy, reference) == false)
89 {
90 diagnostics.ReferenceNotFound(reference);
91 return 1;
92 }
93 }
94
95 Assembly assembly = null;
96 try
97 {
98 file = new FileInfo(options.Assembly);
99 }
100 catch (FileNotFoundException)
101 {
102 diagnostics.InputFileNotFound(options.Assembly);
103 return 1;
104 }
105 catch (Exception x)
106 {
107 diagnostics.ErrorReadingFile(options.Assembly, x.ToString());
108 return 1;
109 }
110
111 if (file != null && file.Exists)
112 {
113 assembly = assemblyResolver.LoadFile(options.Assembly);
114 }
115 else
116 {
117 assembly = assemblyResolver.LoadWithPartialName(options.Assembly);
118 }
119
120 StaticCompiler compiler;
121 RuntimeContext context;
122
123 int rc = 0;
124 if (assembly == null)
125 {
126 rc = 1;
127 diagnostics.ReferenceNotFound(options.Assembly);
128 }
129 else
130 {
131 Assembly runtimeAssembly = null;
132 Assembly baseAssembly = null;
133
134 if (options.Bootstrap)
135 {
136 var runtimeAssemblyPath = references.FirstOrDefault(i => Path.GetFileNameWithoutExtension(i) == "IKVM.Runtime");
137 if (runtimeAssemblyPath != null)
138 runtimeAssembly = assemblyResolver.LoadFile(runtimeAssemblyPath);
139
140 if (runtimeAssembly == null || runtimeAssembly.__IsMissing)
141 {
142 diagnostics.RuntimeNotFound();
143 return 1;
144 }
145
146 compiler = new StaticCompiler(universe, assemblyResolver, runtimeAssembly);
147 context = new RuntimeContext(new RuntimeContextOptions(), diagnostics, new ManagedTypeResolver(compiler, null), true, compiler);
148 context.ClassLoaderFactory.SetBootstrapClassLoader(new RuntimeBootstrapClassLoader(context));
149 }
150 else
151 {
152
153 var runtimeAssemblyPath = references.FirstOrDefault(i => Path.GetFileNameWithoutExtension(i) == "IKVM.Runtime");
154 if (runtimeAssemblyPath != null)
155 runtimeAssembly = assemblyResolver.LoadFile(runtimeAssemblyPath);
156
157 var baseAssemblyPath = references.FirstOrDefault(i => Path.GetFileNameWithoutExtension(i) == "IKVM.Java");
158 if (baseAssemblyPath != null)
159 baseAssembly = assemblyResolver.LoadFile(baseAssemblyPath);
160
161 if (runtimeAssembly == null || runtimeAssembly.__IsMissing)
162 {
163 diagnostics.RuntimeNotFound();
164 return 1;
165 }
166
167 if (baseAssembly == null || runtimeAssembly.__IsMissing)
168 {
169 diagnostics.CoreClassesMissing();
170 return 1;
171 }
172
173 compiler = new StaticCompiler(universe, assemblyResolver, runtimeAssembly);
174 context = new RuntimeContext(new RuntimeContextOptions(), diagnostics, new ManagedTypeResolver(compiler, baseAssembly), false, compiler);
175 }
176
177 if (context.AttributeHelper.IsJavaModule(assembly.ManifestModule))
178 {
179 diagnostics.ExportingImportsNotSupported();
180 return 1;
181 }
182
183 if (options.Output == null)
184 options.Output = assembly.GetName().Name + ".jar";
185
186 try
187 {
188 using (zipFile = new ZipArchive(new FileStream(options.Output, FileMode.Create), ZipArchiveMode.Create))
189 {
190 try
191 {
192 var assemblies = new List<Assembly>();
193 assemblies.Add(assembly);
194
195 if (options.Shared)
196 LoadSharedClassLoaderAssemblies(compiler, assembly, assemblies);
197
198 foreach (var asm in assemblies)
199 {
200 if (ProcessTypes(context, asm.GetTypes()) != 0)
201 {
202 rc = 1;
203 if (options.ContinueOnError == false)
204 break;
205 }
206
207 if (options.Forwarders && ProcessTypes(context, asm.ManifestModule.__GetExportedTypes()) != 0)
208 {
209 rc = 1;
210 if (options.ContinueOnError == false)
211 break;
212 }
213 }
214 }
215 catch (Exception x)
216 {
217 if (options.ContinueOnError == false)
218 diagnostics.UnknownWarning($"Assembly reflection encountered an error. Resultant JAR may be incomplete. ({x.Message})");
219
220 rc = 1;
221 }
222 }
223 }
224 catch (InvalidDataException e)
225 {
226 rc = 1;
227 diagnostics.InvalidZip(options.Output);
228 }
229 }
230
231 return rc;
232 }
233
240 static string FindCoreLibName(List<string> references, List<string> libpaths)
241 {
242 foreach (var reference in references)
243 if (GetAssemblyNameIfCoreLib(reference) is string coreLibName)
244 return coreLibName;
245
246 return null;
247 }
248
254 static string GetAssemblyNameIfCoreLib(string path)
255 {
256 if (File.Exists(path) == false)
257 return null;
258
259 try
260 {
261 using var st = File.OpenRead(path);
262 using var pe = new PEReader(st);
263 var mr = pe.GetMetadataReader();
264
265 foreach (var handle in mr.TypeDefinitions)
266 if (IsSystemObject(mr, handle))
267 return mr.GetString(mr.GetAssemblyDefinition().Name);
268
269 return null;
270 }
271 catch (System.BadImageFormatException)
272 {
273 return null;
274 }
275 catch (InvalidOperationException)
276 {
277 return null;
278 }
279 catch (IOException)
280 {
281 return null;
282 }
283 }
284
291 static bool IsSystemObject(MetadataReader reader, TypeDefinitionHandle th)
292 {
293 var td = reader.GetTypeDefinition(th);
294 var ns = reader.GetString(td.Namespace);
295 var nm = reader.GetString(td.Name);
296
297 return ns == "System" && nm == "Object";
298 }
299
300 static void Resolver_Warning(AssemblyResolver.WarningId warning, string message, string[] parameters)
301 {
302 if (warning != AssemblyResolver.WarningId.HigherVersion)
303 Console.Error.WriteLine("Warning: " + message, parameters);
304 }
305
306 static void LoadSharedClassLoaderAssemblies(StaticCompiler compiler, Assembly assembly, List<Assembly> assemblies)
307 {
308 if (assembly.GetManifestResourceInfo("ikvm.exports") != null)
309 {
310 using (var stream = assembly.GetManifestResourceStream("ikvm.exports"))
311 {
312 var rdr = new BinaryReader(stream);
313 var assemblyCount = rdr.ReadInt32();
314 for (int i = 0; i < assemblyCount; i++)
315 {
316 var name = rdr.ReadString();
317 var typeCount = rdr.ReadInt32();
318 if (typeCount > 0)
319 {
320 for (int j = 0; j < typeCount; j++)
321 {
322 rdr.ReadInt32();
323 }
324 try
325 {
326 assemblies.Add(compiler.Load(name));
327 }
328 catch
329 {
330 Console.WriteLine("Warning: Unable to load shared class loader assembly: {0}", name);
331 }
332 }
333 }
334 }
335 }
336 }
337
338 void WriteClass(RuntimeJavaType javaType)
339 {
340 var entry = zipFile.CreateEntry(javaType.Name.Replace('.', '/') + ".class");
341 entry.LastWriteTime = new DateTime(1980, 01, 01, 0, 0, 0, DateTimeKind.Utc);
342 using Stream stream = entry.Open();
343
344 javaType.Context.StubGenerator.Write(stream, javaType, options.IncludeNonPublicTypes, options.IncludeNonPublicInterfaces, options.IncludeNonPublicMembers, options.IncludeParameterNames, options.SerialVersionUID);
345 }
346
347 bool ExportNamespace(IList<string> namespaces, Type type)
348 {
349 if (namespaces.Count == 0)
350 return true;
351
352 var name = type.FullName;
353 foreach (string ns in namespaces)
354 if (name.StartsWith(ns, StringComparison.Ordinal))
355 return true;
356
357 return false;
358 }
359
360 int ProcessTypes(RuntimeContext context, Type[] types)
361 {
362 int rc = 0;
363 foreach (var t in types)
364 {
365 if ((t.IsPublic || options.IncludeNonPublicTypes) && ExportNamespace(options.Namespaces, t) && !t.IsGenericTypeDefinition && !context.AttributeHelper.IsHideFromJava(t) && (!t.IsGenericType || !context.AttributeHelper.IsJavaModule(t.Module)))
366 {
367 RuntimeJavaType c;
368 if (context.ClassLoaderFactory.IsRemappedType(t) || t.IsPrimitive || t == context.Types.Void)
370 else
371 c = context.ClassLoaderFactory.GetJavaTypeFromType(t);
372
373 if (c != null)
374 AddToExportList(c);
375 }
376 }
377
378 bool keepGoing;
379 do
380 {
381 keepGoing = false;
382 foreach (var c in new List<RuntimeJavaType>(todo.Values).OrderBy(i => i.Name))
383 {
384 if (!done.ContainsKey(c.Name))
385 {
386 keepGoing = true;
387 done.Add(c.Name, null);
388
389 try
390 {
391 rc = ProcessClass(c);
392 if (rc != 0)
393 return rc;
394
395 WriteClass(c);
396 }
397 catch (Exception x)
398 {
399 if (options.ContinueOnError)
400 {
401 rc = 1;
402 Console.WriteLine(x);
403 }
404 else
405 {
406 throw;
407 }
408 }
409 }
410 }
411 }
412 while (keepGoing);
413
414 return rc;
415 }
416
417 void AddToExportList(RuntimeJavaType c)
418 {
419 todo[c.Name] = c;
420 }
421
422 bool IsNonVectorArray(RuntimeJavaType tw)
423 {
424 return !tw.IsArray && tw.TypeAsBaseType.IsArray;
425 }
426
427 int AddToExportListIfNeeded(RuntimeJavaType javaType)
428 {
429 while (javaType.IsArray)
430 javaType = javaType.ElementTypeWrapper;
431
432 if (javaType.IsUnloadable && javaType is RuntimeUnloadableJavaType unloadableJavaType)
433 {
434 javaType.Diagnostics.MissingType(unloadableJavaType.MissingType.Name, unloadableJavaType.MissingType.Assembly.FullName);
435 return 1;
436 }
437
438 if (javaType is RuntimeStubJavaType)
439 {
440 // skip
441 }
442 else if ((javaType.TypeAsTBD != null && javaType.TypeAsTBD.IsGenericType) || IsNonVectorArray(javaType) || !javaType.IsPublic)
443 {
444 AddToExportList(javaType);
445 }
446
447 return 0;
448 }
449
450 int AddToExportListIfNeeded(RuntimeJavaType[] types)
451 {
452 foreach (var tw in types)
453 {
454 var rc = AddToExportListIfNeeded(tw);
455 if (rc != 0)
456 return rc;
457 }
458
459 return 0;
460 }
461
462 int ProcessClass(RuntimeJavaType tw)
463 {
464 int rc = 0;
465
466 var superclass = tw.BaseTypeWrapper;
467 if (superclass != null)
468 {
469 rc = AddToExportListIfNeeded(superclass);
470 if (rc != 0)
471 return rc;
472 }
473
474 rc = AddToExportListIfNeeded(tw.Interfaces);
475 if (rc != 0)
476 return rc;
477
478 var outerClass = tw.DeclaringTypeWrapper;
479 if (outerClass != null)
480 AddToExportList(outerClass);
481
482 foreach (var innerClass in tw.InnerClasses)
483 if (innerClass.IsPublic)
484 AddToExportList(innerClass);
485
486 foreach (var mw in tw.GetMethods())
487 {
488 if (mw.IsPublic || mw.IsProtected)
489 {
490 mw.Link();
491
492 rc = AddToExportListIfNeeded(mw.ReturnType);
493 if (rc != 0)
494 return rc;
495
496 rc = AddToExportListIfNeeded(mw.GetParameters());
497 if (rc != 0)
498 return rc;
499 }
500 }
501
502 foreach (var fw in tw.GetFields())
503 {
504 if (fw.IsPublic || fw.IsProtected)
505 {
506 fw.Link();
507 rc = AddToExportListIfNeeded(fw.FieldTypeWrapper);
508 if (rc != 0)
509 return rc;
510 }
511 }
512
513 return 0;
514 }
515
516 }
517
518}
Maintains services relevant to an instane of the IKVM runtime.
AttributeHelper AttributeHelper
Gets the AttributeHelper associated with this instance of the runtime.
StubGenerator StubGenerator
Gets the StubGenerator associated with this instance of the runtime.
Types Types
Gets the Types associated with this instance of the runtime.
RuntimeManagedJavaTypeFactory ManagedJavaTypeFactory
Gets the RuntimeManagedJavaTypeFactory associated with this instance of the runtime.
RuntimeClassLoaderFactory ClassLoaderFactory
Gets the RuntimeClassLoaderFactory associated with this instance of the runtime.
RuntimeJavaType GetJavaTypeFromManagedType(Type type)
Gets the RuntimeJavaType associated with the specified managed type, or creates one on demand.
Defines a runtime java type with no implementation.
Main entry point for the application.
Definition ExportImpl.cs:23
ExportImpl(ExportOptions options, IDiagnosticHandler diagnostics)
Initializes a new instance.
Definition ExportImpl.cs:37
int Execute()
Executes the exporter.
Definition ExportImpl.cs:46
Options passed to the exporter.
Holds the static compiler information.
Exposes methods to accept diagnostic invocations.
void MissingType(string arg0, string arg1)
The 'MissingType' diagnostic.