IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
RuntimeByteCodeJavaType.JavaTypeImpl.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2015 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.Diagnostics;
27using System.Collections.Concurrent;
28
29using IKVM.Attributes;
30
31#if IMPORTER
32using IKVM.Reflection;
35
36using Type = IKVM.Reflection.Type;
38#else
39using System.Reflection;
40using System.Reflection.Emit;
41
43#endif
44
45namespace IKVM.Runtime
46{
47
48 partial class RuntimeByteCodeJavaType
49 {
50
51 private sealed partial class JavaTypeImpl : DynamicImpl
52 {
53
54 readonly RuntimeJavaType host;
55 readonly ClassFile classFile;
56 readonly RuntimeDynamicOrImportJavaType wrapper;
57 TypeBuilder typeBuilder;
58 RuntimeJavaMethod[] methods;
59 RuntimeJavaMethod[][] baseMethods;
60 RuntimeJavaField[] fields;
61 FinishedTypeImpl finishedType;
62 bool finishInProgress;
63 MethodBuilder clinitMethod;
64 MethodBuilder finalizeMethod;
65 int recursionCount;
66#if IMPORTER
67 RuntimeByteCodeJavaType enclosingClassWrapper;
68 AnnotationBuilder annotationBuilder;
69 TypeBuilder enumBuilder;
70 TypeBuilder privateInterfaceMethods;
71 ConcurrentDictionary<string, RuntimeJavaType> nestedTypeNames; // only keys are used, values are always null
72#endif
73
74 internal JavaTypeImpl(RuntimeJavaType host, ClassFile f, RuntimeByteCodeJavaType wrapper)
75 {
76 wrapper.ClassLoader.Diagnostics.GenericCompilerInfo("constructing JavaTypeImpl for " + f.Name);
77 this.host = host;
78 this.classFile = f;
79 this.wrapper = (RuntimeDynamicOrImportJavaType)wrapper;
80 }
81
82 internal void CreateStep1()
83 {
84 // process all methods (needs to be done first, because property fields depend on being able to lookup the accessor methods)
85 var hasclinit = wrapper.BaseTypeWrapper == null ? false : wrapper.BaseTypeWrapper.HasStaticInitializer;
86 methods = new RuntimeJavaMethod[classFile.Methods.Length];
87 baseMethods = new RuntimeJavaMethod[classFile.Methods.Length][];
88 for (int i = 0; i < methods.Length; i++)
89 {
90 var flags = MemberFlags.None;
91 var m = classFile.Methods[i];
92 if (m.IsClassInitializer)
93 {
94#if IMPORTER
95 if (IsSideEffectFreeStaticInitializerOrNoop(m, out var noop))
96 {
97 if (noop)
98 flags |= MemberFlags.NoOp;
99 }
100 else
101 {
102 hasclinit = true;
103 }
104#else
105 hasclinit = true;
106#endif
107 }
108
109 if (m.IsInternal)
110 flags |= MemberFlags.InternalAccess;
111
112#if IMPORTER
113 if (m.IsCallerSensitive && SupportsCallerID(m))
114 flags |= MemberFlags.CallerID;
115
116 // set as module initializer
117 if (m.IsModuleInitializer)
118 flags |= MemberFlags.ModuleInitializer;
119#endif
120
121 if (wrapper.IsGhost && m.IsVirtual)
122 {
123 // note that a GhostMethodWrapper can also represent a default interface method
124 methods[i] = new RuntimeGhostJavaMethod(wrapper, m.Name, m.Signature, null, null, null, null, m.Modifiers, flags);
125 }
126 else if (m.IsConstructor && wrapper.IsDelegate)
127 {
128 methods[i] = new DelegateConstructorMethodWrapper(wrapper, m);
129 }
130 else if (classFile.IsInterface && !m.IsStatic && !m.IsPublic)
131 {
132 // we can't use callvirt to call interface private instance methods (because we have to compile them as static methods,
133 // since the CLR doesn't support interface instance methods), so need a special MethodWrapper
134 methods[i] = new RuntimePrivateInterfaceJavaMethod(wrapper, m.Name, m.Signature, null, null, null, m.Modifiers, flags);
135 }
136 else if (classFile.IsInterface && m.IsVirtual && !m.IsAbstract)
137 {
138 // note that a GhostMethodWrapper can also represent a default interface method
139 methods[i] = new RuntimeDefaultInterfaceJavaMethod(wrapper, m.Name, m.Signature, null, null, null, null, m.Modifiers, flags);
140 }
141 else
142 {
143 if (!classFile.IsInterface && m.IsVirtual)
144 {
145 baseMethods[i] = FindBaseMethods(m, out var explicitOverride);
146 if (explicitOverride)
147 flags |= MemberFlags.ExplicitOverride;
148 }
149
150 methods[i] = new RuntimeTypicalJavaMethod(wrapper, m.Name, m.Signature, null, null, null, m.Modifiers, flags);
151 }
152 }
153
154 if (hasclinit)
155 wrapper.SetHasStaticInitializer();
156
157 if (!wrapper.IsInterface || wrapper.IsPublic)
158 {
159 var methodsArray = new List<RuntimeJavaMethod>(methods);
160 var baseMethodsArray = new List<RuntimeJavaMethod[]>(baseMethods);
161 AddMirandaMethods(methodsArray, baseMethodsArray, wrapper);
162 methods = methodsArray.ToArray();
163 baseMethods = baseMethodsArray.ToArray();
164 }
165
166 if (!wrapper.IsInterface)
167 AddDelegateInvokeStubs(wrapper, ref methods);
168
169 wrapper.SetMethods(methods);
170
171 fields = new RuntimeJavaField[classFile.Fields.Length];
172 for (int i = 0; i < fields.Length; i++)
173 {
174 var fld = classFile.Fields[i];
175 if (fld.IsStaticFinalConstant)
176 {
177 RuntimeJavaType fieldType = null;
178#if !IMPORTER
179 fieldType = wrapper.Context.ClassLoaderFactory.GetBootstrapClassLoader().FieldTypeWrapperFromSig(fld.Signature, LoadMode.LoadOrThrow);
180#endif
181 fields[i] = new RuntimeConstantJavaField(wrapper, fieldType, fld.Name, fld.Signature, fld.Modifiers, null, fld.ConstantValue, MemberFlags.None);
182 }
183 else if (fld.IsProperty)
184 {
185 fields[i] = new RuntimeByteCodePropertyJavaField(wrapper, fld);
186 }
187 else
188 {
189 fields[i] = RuntimeJavaField.Create(wrapper, null, null, fld.Name, fld.Signature, new ExModifiers(fld.Modifiers, fld.IsInternal));
190 }
191 }
192#if IMPORTER
193 wrapper.AddMapXmlFields(ref fields);
194#endif
195 wrapper.SetFields(fields);
196 }
197
198#if IMPORTER
199
200 bool SupportsCallerID(ClassFile.Method method)
201 {
202 if ((classFile.Name == "sun.reflect.Reflection" && method.Name == "getCallerClass") || (classFile.Name == "java.lang.SecurityManager" && method.Name == "checkMemberAccess"))
203 {
204 // ignore CallerSensitive on methods that don't need CallerID parameter
205 return false;
206 }
207 else if (method.IsStatic)
208 {
209 return true;
210 }
211 else if ((classFile.IsFinal || classFile.Name == "java.lang.Runtime" || classFile.Name == "java.io.ObjectStreamClass") && wrapper.BaseTypeWrapper.GetMethod(method.Name, method.Signature, true) == null && !HasInterfaceMethod(wrapper, method.Name, method.Signature))
212 {
213 // We only support CallerID instance methods on final or effectively final types,
214 // because we don't support interface stubs with CallerID.
215 // We also don't support a CallerID method overriding a method or implementing an interface.
216 return true;
217 }
218 else if (RequiresDynamicReflectionCallerClass(classFile.Name, method.Name, method.Signature))
219 {
220 // We don't support CallerID for virtual methods that can be overridden or implement an interface,
221 // so these methods will do a dynamic stack walk if when Reflection.getCallerClass() is used.
222 return false;
223 }
224 else
225 {
226 // If we end up here, we either have to add support or add them to the white-list in the above clause
227 // to allow them to fall back to dynamic stack walking.
228 wrapper.ClassLoader.Diagnostics.CallerSensitiveOnUnsupportedMethod(classFile.Name, method.Name, method.Signature);
229 return false;
230 }
231 }
232
233 static bool HasInterfaceMethod(RuntimeJavaType tw, string name, string signature)
234 {
235 for (; tw != null; tw = tw.BaseTypeWrapper)
236 {
237 foreach (var iface in tw.Interfaces)
238 {
239 if (iface.GetMethod(name, signature, false) != null)
240 {
241 return true;
242 }
243 if (HasInterfaceMethod(iface, name, signature))
244 {
245 return true;
246 }
247 }
248 }
249
250 return false;
251 }
252#endif
253
254 internal void CreateStep2()
255 {
256#if IMPORTER
257 if (typeBuilder != null)
258 {
259 // in the static compiler we need to create the TypeBuilder from outer to inner
260 // and to avoid having to sort the classes this way, we instead call CreateStep2
261 // on demand for outer wrappers and this necessitates us to keep track of
262 // whether we've already been called
263 return;
264 }
265#endif
266
267 // this method is not allowed to throw exceptions (if it does, the runtime will abort)
268 var hasclinit = wrapper.HasStaticInitializer;
269 var mangledTypeName = wrapper.classLoader.GetTypeWrapperFactory().AllocMangledName(wrapper);
270 var f = classFile;
271
272 try
273 {
274 TypeAttributes typeAttribs = 0;
275 if (f.IsAbstract)
276 typeAttribs |= TypeAttributes.Abstract;
277 if (f.IsFinal)
278 typeAttribs |= TypeAttributes.Sealed;
279 if (!hasclinit)
280 typeAttribs |= TypeAttributes.BeforeFieldInit;
281#if IMPORTER
282
283 bool cantNest = false;
284 bool setModifiers = false;
285 TypeBuilder enclosing = null;
286 string enclosingClassName = null;
287 // we only compile inner classes as nested types in the static compiler, because it has a higher cost
288 // and doesn't buy us anything in dynamic mode (and if fact, due to an FXBUG it would make handling
289 // the TypeResolve event very hard)
290 var outerClass = getOuterClass();
291 if (outerClass.outerClass.IsNotNil)
292 {
293 enclosingClassName = classFile.GetConstantPoolClass(outerClass.outerClass);
294 }
295 else if (f.EnclosingMethod != null)
296 {
297 enclosingClassName = f.EnclosingMethod[0];
298 }
299
300 if (enclosingClassName != null)
301 {
302 if (!CheckInnerOuterNames(f.Name, enclosingClassName))
303 {
304 wrapper.ClassLoader.Diagnostics.GenericCompilerWarning($"Incorrect {(outerClass.outerClass.IsNotNil ? "InnerClasses" : "EnclosingMethod")} attribute on {f.Name}");
305 }
306 else
307 {
308 try
309 {
310 enclosingClassWrapper = wrapper.classLoader.TryLoadClassByName(enclosingClassName) as RuntimeByteCodeJavaType;
311 }
312 catch (RetargetableJavaException x)
313 {
314 wrapper.ClassLoader.Diagnostics.GenericCompilerWarning($"Unable to load outer class {enclosingClassName} for inner class {f.Name} ({x.GetType().Name}: {x.Message})");
315 }
316
317 if (enclosingClassWrapper != null)
318 {
319 // make sure the relationship is reciprocal (otherwise we run the risk of
320 // baking the outer type before the inner type) and that the inner and outer
321 // class live in the same class loader (when doing a multi target compilation,
322 // it is possible to split the two classes across assemblies)
323 var oimpl = enclosingClassWrapper.impl as JavaTypeImpl;
324 if (oimpl != null && enclosingClassWrapper.ClassLoader == wrapper.ClassLoader)
325 {
326 var outerClassFile = oimpl.classFile;
327 var outerInnerClasses = outerClassFile.InnerClasses;
328 if (outerInnerClasses == null)
329 {
330 enclosingClassWrapper = null;
331 }
332 else
333 {
334 var ok = false;
335 for (int i = 0; i < outerInnerClasses.Length; i++)
336 {
337 if (((outerInnerClasses[i].outerClass.IsNotNil && outerClassFile.GetConstantPoolClass(outerInnerClasses[i].outerClass) == outerClassFile.Name) || (outerInnerClasses[i].outerClass.IsNil && outerClass.outerClass.IsNil)) && outerInnerClasses[i].innerClass.IsNotNil && outerClassFile.GetConstantPoolClass(outerInnerClasses[i].innerClass) == f.Name)
338 {
339 ok = true;
340 break;
341 }
342 }
343
344 if (!ok)
345 {
346 enclosingClassWrapper = null;
347 }
348 }
349 }
350 else
351 {
352 enclosingClassWrapper = null;
353 }
354
355 if (enclosingClassWrapper != null)
356 {
357 enclosingClassWrapper.CreateStep2();
358 enclosing = oimpl.typeBuilder;
359 if (outerClass.outerClass.IsNil)
360 {
361 // we need to record that we're not an inner classes, but an enclosed class
362 typeAttribs |= TypeAttributes.SpecialName;
363 }
364 }
365 else
366 {
367 wrapper.ClassLoader.Diagnostics.GenericCompilerWarning($"Non-reciprocal inner class {f.Name}");
368 }
369 }
370 }
371 }
372
373 if (f.IsPublic)
374 {
375 if (enclosing != null)
376 {
377 if (enclosingClassWrapper.IsPublic)
378 {
379 typeAttribs |= TypeAttributes.NestedPublic;
380 }
381 else
382 {
383 // We're a public type nested inside a non-public type, this means that we can't compile this type as a nested type,
384 // because that would mean it wouldn't be visible outside the assembly.
385 cantNest = true;
386 typeAttribs |= TypeAttributes.Public;
387 }
388 }
389 else
390 {
391 typeAttribs |= TypeAttributes.Public;
392 }
393 }
394 else if (enclosing != null)
395 {
396 typeAttribs |= TypeAttributes.NestedAssembly;
397 }
398#else // IMPORTER
399 if (f.IsPublic)
400 {
401 typeAttribs |= TypeAttributes.Public;
402 }
403#endif // IMPORTER
404 if (f.IsInterface)
405 {
406 typeAttribs |= TypeAttributes.Interface | TypeAttributes.Abstract;
407#if IMPORTER
408 // if any "meaningless" bits are set, preserve them
409 setModifiers |= (f.Modifiers & (Modifiers)0x99CE) != 0;
410 // by default we assume interfaces are abstract, so in the exceptional case we need a ModifiersAttribute
411 setModifiers |= (f.Modifiers & Modifiers.Abstract) == 0;
412 if (enclosing != null && !cantNest)
413 {
414 if (wrapper.IsGhost)
415 {
416 // TODO this is low priority, since the current Java class library doesn't define any ghost interfaces
417 // as inner classes
418 throw new NotImplementedException();
419 }
420
421 // LAMESPEC the CLI spec says interfaces cannot contain nested types (Part.II, 9.6), but that rule isn't enforced
422 // (and broken by J# as well), so we'll just ignore it too.
423 typeBuilder = enclosing.DefineNestedType(AllocNestedTypeName(enclosingClassWrapper.Name, f.Name), typeAttribs);
424 }
425 else
426 {
427 if (wrapper.IsGhost)
428 {
429 typeBuilder = wrapper.DefineGhostType(mangledTypeName, typeAttribs);
430 }
431 else
432 {
433 typeBuilder = wrapper.classLoader.GetTypeWrapperFactory().ModuleBuilder.DefineType(mangledTypeName, typeAttribs);
434 }
435 }
436#else // IMPORTER
437 typeBuilder = wrapper.classLoader.GetTypeWrapperFactory().ModuleBuilder.DefineType(mangledTypeName, typeAttribs);
438#endif // IMPORTER
439 }
440 else
441 {
442 typeAttribs |= TypeAttributes.Class;
443#if IMPORTER
444 // if any "meaningless" bits are set, preserve them
445 setModifiers |= (f.Modifiers & (Modifiers)0x99CE) != 0;
446 // by default we assume ACC_SUPER for classes, so in the exceptional case we need a ModifiersAttribute
447 setModifiers |= !f.IsSuper;
448 if (enclosing != null && !cantNest)
449 {
450 // LAMESPEC the CLI spec says interfaces cannot contain nested types (Part.II, 9.6), but that rule isn't enforced
451 // (and broken by J# as well), so we'll just ignore it too.
452 typeBuilder = enclosing.DefineNestedType(AllocNestedTypeName(enclosingClassWrapper.Name, f.Name), typeAttribs);
453 }
454 else
455#endif // IMPORTER
456 {
457 typeBuilder = wrapper.classLoader.GetTypeWrapperFactory().ModuleBuilder.DefineType(mangledTypeName, typeAttribs);
458 }
459 }
460
461#if IMPORTER
462 // When we're statically compiling, we associate the typeBuilder with the wrapper. This enables types in referenced assemblies to refer back to
463 // types that we're currently compiling (i.e. a cyclic dependency between the currently assembly we're compiling and a referenced assembly).
464 wrapper.Context.ClassLoaderFactory.SetWrapperForType(typeBuilder, wrapper);
465
466 if (outerClass.outerClass.IsNotNil)
467 {
468 if (enclosing != null && cantNest)
469 {
470 wrapper.Context.AttributeHelper.SetNonNestedInnerClass(enclosing, f.Name);
471 }
472 if (enclosing == null || cantNest)
473 {
474 wrapper.Context.AttributeHelper.SetNonNestedOuterClass(typeBuilder, enclosingClassName);
475 }
476 }
477
478 if (classFile.InnerClasses != null)
479 {
480 foreach (var inner in classFile.InnerClasses)
481 {
482 var name = classFile.GetConstantPoolClass(inner.innerClass);
483 var exists = false;
484
485 try
486 {
487 exists = wrapper.ClassLoader.TryLoadClassByName(name) != null;
488 }
489 catch (RetargetableJavaException)
490 {
491
492 }
493
494 if (!exists)
495 {
496 wrapper.Context.AttributeHelper.SetNonNestedInnerClass(typeBuilder, name);
497 }
498 }
499 }
500
501 if (typeBuilder.FullName != wrapper.Name && wrapper.Name.Replace('$', '+') != typeBuilder.FullName)
502 {
503 wrapper.classLoader.AddNameMapping(wrapper.Name, typeBuilder.FullName);
504 }
505
506 if (f.IsAnnotation && Annotation.HasRetentionPolicyRuntime(f.Annotations))
507 {
508 annotationBuilder = new AnnotationBuilder(wrapper.Context, this, enclosing);
509 wrapper.SetAnnotation(annotationBuilder);
510 }
511
512 // For Java 5 Enum types, we generate a nested .NET enum.
513 // This is primarily to support annotations that take enum parameters.
514 if (f.IsEnum && f.IsPublic)
515 {
516 AddCliEnum();
517 }
518
519 AddInnerClassAttribute(enclosing != null, outerClass.innerClass.IsNotNil, mangledTypeName, outerClass.accessFlags);
520 if (classFile.DeprecatedAttribute && !Annotation.HasObsoleteAttribute(classFile.Annotations))
521 {
522 wrapper.Context.AttributeHelper.SetDeprecatedAttribute(typeBuilder);
523 }
524
525 if (classFile.GenericSignature != null)
526 {
527 wrapper.Context.AttributeHelper.SetSignatureAttribute(typeBuilder, classFile.GenericSignature);
528 }
529 if (classFile.EnclosingMethod != null)
530 {
531 if (outerClass.outerClass.IsNil && enclosing != null && !cantNest)
532 {
533 // we don't need to record the enclosing type, if we're compiling the current type as a nested type because of the EnclosingMethod attribute
534 wrapper.Context.AttributeHelper.SetEnclosingMethodAttribute(typeBuilder, null, classFile.EnclosingMethod[1], classFile.EnclosingMethod[2]);
535 }
536 else
537 {
538 wrapper.Context.AttributeHelper.SetEnclosingMethodAttribute(typeBuilder, classFile.EnclosingMethod[0], classFile.EnclosingMethod[1], classFile.EnclosingMethod[2]);
539 }
540 }
541
542 if (classFile.RuntimeVisibleTypeAnnotations.Count > 0)
543 wrapper.Context.AttributeHelper.SetRuntimeVisibleTypeAnnotationsAttribute(typeBuilder, in classFile.RuntimeVisibleTypeAnnotations);
544
545 if (wrapper.classLoader.EmitStackTraceInfo)
546 {
547 if (f.SourceFileAttribute != null)
548 {
549 if ((enclosingClassWrapper == null && f.SourceFileAttribute == typeBuilder.Name + ".java")
550 || (enclosingClassWrapper != null && f.SourceFileAttribute == enclosingClassWrapper.sourceFileName))
551 {
552 // we don't need to record the name because it matches our heuristic
553 }
554 else
555 {
556 wrapper.Context.AttributeHelper.SetSourceFile(typeBuilder, f.SourceFileAttribute);
557 }
558 }
559 else
560 {
561 wrapper.Context.AttributeHelper.SetSourceFile(typeBuilder, null);
562 }
563 }
564 // NOTE in Whidbey we can (and should) use CompilerGeneratedAttribute to mark Synthetic types
565 if (setModifiers || classFile.IsInternal || (classFile.Modifiers & (Modifiers.Synthetic | Modifiers.Annotation | Modifiers.Enum)) != 0)
566 {
567 wrapper.Context.AttributeHelper.SetModifiers(typeBuilder, classFile.Modifiers, classFile.IsInternal);
568 }
569#endif // IMPORTER
570 if (hasclinit)
571 {
572 AddClinitTrigger();
573 }
574 if (HasStructLayoutAttributeAnnotation(classFile))
575 {
576 // when we have a StructLayoutAttribute, field order is significant,
577 // so we link all fields here to make sure they are created in class file order.
578 foreach (RuntimeJavaField fw in fields)
579 {
580 fw.Link();
581 }
582 }
583 }
584#if IMPORTER
585 finally { }
586#else
587 catch (Exception x)
588 {
589 throw new InternalException("Exception during JavaTypeImpl.CreateStep2", x);
590 }
591#endif
592 }
593
594#if IMPORTER
595
596 private void AddInnerClassAttribute(bool isNestedType, bool isInnerClass, string mangledTypeName, Modifiers innerClassFlags)
597 {
598 string name = classFile.Name;
599
600 if (isNestedType)
601 {
602 if (name == enclosingClassWrapper.Name + "$" + typeBuilder.Name)
603 {
604 name = null;
605 }
606 }
607 else if (name == mangledTypeName)
608 {
609 name = null;
610 }
611
612 if ((isInnerClass && RuntimeManagedByteCodeJavaType.PredictReflectiveModifiers(wrapper) != innerClassFlags) || name != null)
613 {
614 // HACK we abuse the InnerClassAttribute to record to real name for non-inner classes as well
615 wrapper.Context.AttributeHelper.SetInnerClass(typeBuilder, name, isInnerClass ? innerClassFlags : wrapper.Modifiers);
616 }
617 }
618
619 private void AddCliEnum()
620 {
621 ImportClassLoader ccl = wrapper.classLoader;
622 string name = "__Enum";
623 while (!ccl.ReserveName(classFile.Name + "$" + name))
624 {
625 name += "_";
626 }
627 enumBuilder = typeBuilder.DefineNestedType(name, TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.NestedPublic | TypeAttributes.Serializable, wrapper.Context.Types.Enum);
628 wrapper.Context.AttributeHelper.HideFromJava(enumBuilder);
629 enumBuilder.DefineField("value__", wrapper.Context.Types.Int32, FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
630 for (int i = 0; i < classFile.Fields.Length; i++)
631 {
632 if (classFile.Fields[i].IsEnum)
633 {
634 FieldBuilder fieldBuilder = enumBuilder.DefineField(classFile.Fields[i].Name, enumBuilder, FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal);
635 fieldBuilder.SetConstant(i);
636 }
637 }
638 wrapper.SetEnumType(enumBuilder);
639 }
640#endif
641
642 void AddClinitTrigger()
643 {
644 // We create a empty method that we can use to trigger our .cctor
645 // (previously we used RuntimeHelpers.RunClassConstructor, but that is slow and requires additional privileges)
646 var attribs = MethodAttributes.Static | MethodAttributes.SpecialName;
647 if (classFile.IsAbstract)
648 {
649 var hasfields = false;
650
651 // If we have any public static fields, the cctor trigger must (and may) be public as well
652 foreach (ClassFile.Field fld in classFile.Fields)
653 {
654 if (fld.IsPublic && fld.IsStatic)
655 {
656 hasfields = true;
657 break;
658 }
659 }
660
661 attribs |= hasfields ? MethodAttributes.Public : MethodAttributes.FamORAssem;
662 }
663 else
664 {
665 attribs |= MethodAttributes.Public;
666 }
667
668 clinitMethod = typeBuilder.DefineMethod("__<clinit>", attribs, null, null);
669 clinitMethod.GetILGenerator().Emit(OpCodes.Ret);
670 clinitMethod.SetImplementationFlags(clinitMethod.GetMethodImplementationFlags());
671 }
672
673 private static bool HasStructLayoutAttributeAnnotation(ClassFile c)
674 {
675 if (c.Annotations != null)
676 {
677 foreach (object[] annot in c.Annotations)
678 {
679 if ("Lcli/System/Runtime/InteropServices/StructLayoutAttribute$Annotation;".Equals(annot[1]))
680 {
681 return true;
682 }
683 }
684 }
685 return false;
686 }
687
688#if IMPORTER
689 private ClassFile.InnerClass getOuterClass()
690 {
691 ClassFile.InnerClass[] innerClasses = classFile.InnerClasses;
692 if (innerClasses != null)
693 {
694 for (int j = 0; j < innerClasses.Length; j++)
695 {
696 if (innerClasses[j].innerClass.IsNotNil && classFile.GetConstantPoolClass(innerClasses[j].innerClass) == classFile.Name)
697 {
698 return innerClasses[j];
699 }
700 }
701 }
702 return new ClassFile.InnerClass();
703 }
704
705 private bool IsSideEffectFreeStaticInitializerOrNoop(ClassFile.Method m, out bool noop)
706 {
707 if (m.ExceptionTable.Length != 0)
708 {
709 noop = false;
710 return false;
711 }
712 noop = true;
713 for (int i = 0; i < m.Instructions.Length; i++)
714 {
716 while ((bc = m.Instructions[i].NormalizedOpCode) == NormalizedByteCode.__goto)
717 {
718 int target = m.Instructions[i].TargetIndex;
719 if (target <= i)
720 {
721 // backward branch means we can't do anything
722 noop = false;
723 return false;
724 }
725 // we must skip the unused instructions because the "remove assertions" optimization
726 // uses a goto to remove the (now unused) code
727 i = target;
728 }
729 if (bc == NormalizedByteCode.__getstatic || bc == NormalizedByteCode.__putstatic)
730 {
731 ClassFile.ConstantPoolItemFieldref fld = classFile.SafeGetFieldref(m.Instructions[i].Arg1);
732 if (fld == null || fld.Class != classFile.Name)
733 {
734 noop = false;
735 return false;
736 }
737 // don't allow getstatic to load non-primitive fields, because that would
738 // cause the verifier to try to load the type
739 if (bc == NormalizedByteCode.__getstatic && "L[".IndexOf(fld.Signature[0]) != -1)
740 {
741 noop = false;
742 return false;
743 }
744 ClassFile.Field field = classFile.GetField(fld.Name, fld.Signature);
745 if (field == null)
746 {
747 noop = false;
748 return false;
749 }
750 if (bc == NormalizedByteCode.__putstatic)
751 {
752 if (field.IsProperty && field.PropertySetter != null)
753 {
754 noop = false;
755 return false;
756 }
757 }
758 else if (field.IsProperty && field.PropertyGetter != null)
759 {
760 noop = false;
761 return false;
762 }
763 }
764 else if (ByteCodeMetaData.CanThrowException(bc))
765 {
766 noop = false;
767 return false;
768 }
769 else if (bc == NormalizedByteCode.__aconst_null
770 || (bc == NormalizedByteCode.__iconst && m.Instructions[i].Arg1 == 0)
771 || bc == NormalizedByteCode.__return
772 || bc == NormalizedByteCode.__nop)
773 {
774 // valid instructions in a potential noop <clinit>
775 }
776 else
777 {
778 noop = false;
779 }
780 }
781 // the method needs to be verifiable to be side effect free, since we already analysed it,
782 // we know that the verifier won't try to load any types (which isn't allowed at this time)
783 try
784 {
785 wrapper.Context.MethodAnalyzerFactory.Create(null, wrapper, null, classFile, m, wrapper.classLoader);
786 return true;
787 }
788 catch (VerifyError)
789 {
790 return false;
791 }
792 }
793#endif // IMPORTER
794
795 private RuntimeJavaMethod GetMethodWrapperDuringCtor(RuntimeJavaType lookup, IList<RuntimeJavaMethod> methods, string name, string sig)
796 {
797 if (lookup == wrapper)
798 {
799 foreach (RuntimeJavaMethod mw in methods)
800 {
801 if (mw.Name == name && mw.Signature == sig)
802 {
803 return mw;
804 }
805 }
806 if (lookup.BaseTypeWrapper == null)
807 {
808 return null;
809 }
810 else
811 {
812 return lookup.BaseTypeWrapper.GetMethod(name, sig, true);
813 }
814 }
815 else
816 {
817 return lookup.GetMethod(name, sig, true);
818 }
819 }
820
821 void AddMirandaMethods(List<RuntimeJavaMethod> methods, List<RuntimeJavaMethod[]> baseMethods, RuntimeJavaType tw)
822 {
823 foreach (var iface in tw.Interfaces)
824 {
825 // for interfaces, we only need miranda methods for non-public interfaces that we extend
826 if (iface.IsPublic && wrapper.IsInterface)
827 continue;
828
829 AddMirandaMethods(methods, baseMethods, iface);
830
831 foreach (var ifmethod in iface.GetMethods())
832 {
833 // skip <clinit> and non-virtual interface methods introduced in Java 8
834 if (ifmethod.IsVirtual)
835 {
836 RuntimeJavaType lookup = wrapper;
837
838 while (lookup != null)
839 {
840 var mw = GetMethodWrapperDuringCtor(lookup, methods, ifmethod.Name, ifmethod.Signature);
841 if (mw == null || (mw.IsMirandaMethod && mw.DeclaringType != wrapper))
842 {
843 mw = RuntimeMirandaJavaMethod.Create(wrapper, ifmethod);
844 methods.Add(mw);
845 baseMethods.Add([ifmethod]);
846 break;
847 }
848
849 if (mw.IsMirandaMethod && mw.DeclaringType == wrapper)
850 {
851 methods[methods.IndexOf(mw)] = ((RuntimeMirandaJavaMethod)mw).Update(ifmethod);
852 break;
853 }
854
855 if (mw.IsStatic == false || mw.DeclaringType == wrapper)
856 break;
857
858 lookup = mw.DeclaringType.BaseTypeWrapper;
859 }
860 }
861 }
862 }
863 }
864
865 void AddDelegateInvokeStubs(RuntimeJavaType tw, ref RuntimeJavaMethod[] methods)
866 {
867 foreach (var iface in tw.Interfaces)
868 {
869 if (iface.IsFakeNestedType &&
870 iface.GetMethods().Length == 1 &&
871 iface.GetMethods()[0].IsDelegateInvokeWithByRefParameter)
872 {
873 var mw = new DelegateInvokeStubMethodWrapper(wrapper, iface.DeclaringTypeWrapper.TypeAsBaseType, iface.GetMethods()[0].Signature);
874 if (GetMethodWrapperDuringCtor(wrapper, methods, mw.Name, mw.Signature) == null)
875 methods = ArrayUtil.Concat(methods, mw);
876 }
877
878 AddDelegateInvokeStubs(iface, ref methods);
879 }
880 }
881
882#if IMPORTER
883
884 static bool CheckInnerOuterNames(string inner, string outer)
885 {
886 // do some sanity checks on the inner/outer class names
887 return inner.Length > outer.Length + 1 && inner[outer.Length] == '$' && inner.StartsWith(outer, StringComparison.Ordinal);
888 }
889
890 string AllocNestedTypeName(string outer, string inner)
891 {
892 Debug.Assert(CheckInnerOuterNames(inner, outer));
893 nestedTypeNames ??= new ConcurrentDictionary<string, RuntimeJavaType>();
894 return DynamicClassLoaderFactory.TypeNameMangleImpl(nestedTypeNames, inner.Substring(outer.Length + 1), null);
895 }
896
897#endif
898
899 int GetMethodIndex(RuntimeJavaMethod mw)
900 {
901 for (int i = 0; i < methods.Length; i++)
902 if (methods[i] == mw)
903 return i;
904
905 throw new InvalidOperationException();
906 }
907
908 static void CheckLoaderConstraints(RuntimeJavaMethod mw, RuntimeJavaMethod baseMethod)
909 {
910 if (mw.ReturnType != baseMethod.ReturnType)
911 {
912 if (mw.ReturnType.IsUnloadable || baseMethod.ReturnType.IsUnloadable)
913 {
914 // unloadable types can never cause a loader constraint violation
915 if (mw.ReturnType.IsUnloadable && baseMethod.ReturnType.IsUnloadable)
916 ((RuntimeUnloadableJavaType)mw.ReturnType).SetCustomModifier(((RuntimeUnloadableJavaType)baseMethod.ReturnType).CustomModifier);
917 }
918 else
919 {
920#if IMPORTER
921 StaticCompiler.LinkageError("Method \"{2}.{3}{4}\" has a return type \"{0}\" and tries to override method \"{5}.{3}{4}\" that has a return type \"{1}\"", mw.ReturnType, baseMethod.ReturnType, mw.DeclaringType.Name, mw.Name, mw.Signature, baseMethod.DeclaringType.Name);
922#else
923 throw new LinkageError("Loader constraints violated");
924#endif
925 }
926 }
927
928 var here = mw.GetParameters();
929 var there = baseMethod.GetParameters();
930 for (int i = 0; i < here.Length; i++)
931 {
932 if (here[i] != there[i])
933 {
934 if (here[i].IsUnloadable || there[i].IsUnloadable)
935 {
936 // unloadable types can never cause a loader constraint violation
937 if (here[i].IsUnloadable && there[i].IsUnloadable)
938 {
939 ((RuntimeUnloadableJavaType)here[i]).SetCustomModifier(((RuntimeUnloadableJavaType)there[i]).CustomModifier);
940 }
941 }
942 else
943 {
944#if IMPORTER
945 StaticCompiler.LinkageError("Method \"{2}.{3}{4}\" has an argument type \"{0}\" and tries to override method \"{5}.{3}{4}\" that has an argument type \"{1}\"", here[i], there[i], mw.DeclaringType.Name, mw.Name, mw.Signature, baseMethod.DeclaringType.Name);
946#else
947 throw new LinkageError("Loader constraints violated");
948#endif
949 }
950 }
951 }
952 }
953
954 int GetFieldIndex(RuntimeJavaField fw)
955 {
956 for (int i = 0; i < fields.Length; i++)
957 if (fields[i] == fw)
958 return i;
959
960 throw new InvalidOperationException();
961 }
962
963 internal override FieldInfo LinkField(RuntimeJavaField fw)
964 {
965 if (fw is RuntimeByteCodePropertyJavaField propertyField)
966 {
967 propertyField.DoLink(typeBuilder);
968 return null;
969 }
970
971 int fieldIndex = GetFieldIndex(fw);
972#if IMPORTER
973 if (wrapper.ClassLoader.RemoveUnusedFields &&
974 fw.IsPrivate &&
975 fw.IsStatic &&
976 fw.IsFinal &&
977 fw.IsSerialVersionUID == false &&
978 classFile.Fields[fieldIndex].Annotations == null &&
979 classFile.IsReferenced(classFile.Fields[fieldIndex]) == false)
980 {
981 // unused, so we skip it
982 wrapper.ClassLoader.Diagnostics.GenericCompilerInfo($"Unused field {wrapper.Name}::{fw.Name}");
983 return null;
984 }
985
986 // for compatibility with broken Java code that assumes that reflection returns the fields in class declaration
987 // order, we emit the fields in class declaration order in the .NET metadata (and then when we retrieve them
988 // using .NET reflection, we sort on metadata token.)
989 if (fieldIndex > 0)
990 if (!fields[fieldIndex - 1].IsLinked)
991 for (int i = 0; i < fieldIndex; i++)
992 fields[i].Link();
993
994 if (fieldIndex >= classFile.Fields.Length)
995 {
996 // this must be a field defined in map.xml
997 FieldAttributes fieldAttribs = 0;
998 if (fw.IsPublic)
999 fieldAttribs |= FieldAttributes.Public;
1000 else if (fw.IsProtected)
1001 fieldAttribs |= FieldAttributes.FamORAssem;
1002 else if (fw.IsPrivate)
1003 fieldAttribs |= FieldAttributes.Private;
1004 else
1005 fieldAttribs |= FieldAttributes.Assembly;
1006
1007 if (fw.IsStatic)
1008 fieldAttribs |= FieldAttributes.Static;
1009
1010 if (fw.IsFinal)
1011 fieldAttribs |= FieldAttributes.InitOnly;
1012
1013 return DefineField(fw.Name, fw.FieldTypeWrapper, fieldAttribs, fw.IsVolatile);
1014 }
1015#endif // IMPORTER
1016 FieldBuilder field;
1017
1018 var fld = classFile.Fields[fieldIndex];
1019 FieldAttributes attribs = 0;
1020 var realFieldName = UnicodeUtil.EscapeInvalidSurrogates(fld.Name);
1021 if (ReferenceEquals(realFieldName, fld.Name) == false)
1022 attribs |= FieldAttributes.SpecialName;
1023
1024 var methodAttribs = MethodAttributes.HideBySig;
1025#if IMPORTER
1026 var setModifiers = fld.IsInternal || (fld.Modifiers & (Modifiers.Synthetic | Modifiers.Enum)) != 0;
1027 // The CLR has no equivalent of the Java 11 nestmate access rule. A
1028 // private field may legally be accessed by the enclosing type or a
1029 // sibling nested type in Java, but emitting it as CLR private causes
1030 // those otherwise valid accesses to fail with FieldAccessException.
1031 // Keep the Java access flags in the Modifiers attribute and expose
1032 // the backing CLR field to the generated assembly instead.
1033 var needsNestmateFieldAccess = fld.IsPrivate && HasNestmates();
1034#endif
1035 if (fld.IsPrivate)
1036 {
1037#if IMPORTER
1038 if (needsNestmateFieldAccess)
1039 {
1040 attribs |= FieldAttributes.Assembly;
1041 setModifiers = true;
1042 }
1043 else
1044#endif
1045 {
1046 attribs |= FieldAttributes.Private;
1047 }
1048 }
1049 else if (fld.IsProtected)
1050 {
1051 attribs |= FieldAttributes.FamORAssem;
1052 methodAttribs |= MethodAttributes.FamORAssem;
1053 }
1054 else if (fld.IsPublic)
1055 {
1056 attribs |= FieldAttributes.Public;
1057 methodAttribs |= MethodAttributes.Public;
1058 }
1059 else
1060 {
1061 attribs |= FieldAttributes.Assembly;
1062 methodAttribs |= MethodAttributes.Assembly;
1063 }
1064
1065 if (fld.IsStatic)
1066 {
1067 attribs |= FieldAttributes.Static;
1068 methodAttribs |= MethodAttributes.Static;
1069 }
1070
1071 // NOTE "constant" static finals are converted into literals
1072 // TODO it would be possible for Java code to change the value of a non-blank static final, but I don't
1073 // know if we want to support this (since the Java JITs don't really support it either)
1074 if (fld.IsStaticFinalConstant)
1075 {
1076 attribs |= FieldAttributes.Literal;
1077 field = DefineField(realFieldName, fw.FieldTypeWrapper, attribs, false);
1078 field.SetConstant(fld.ConstantValue);
1079 }
1080 else
1081 {
1082#if IMPORTER
1083 if (wrapper.IsPublic && wrapper.NeedsType2AccessStub(fw))
1084 {
1085 // this field is going to get a type 2 access stub, so we hide the actual field
1086 attribs &= ~FieldAttributes.FieldAccessMask;
1087 attribs |= FieldAttributes.Assembly;
1088 // instead of adding HideFromJava we rename the field to avoid confusing broken compilers
1089 // see https://sourceforge.net/tracker/?func=detail&atid=525264&aid=3056721&group_id=69637
1090 // additional note: now that we maintain the ordering of the fields, we need to recognize
1091 // these fields so that we know where to insert the corresponding accessor property FieldWrapper.
1092 realFieldName = NamePrefix.Type2AccessStubBackingField + realFieldName;
1093 }
1094 else if (fld.IsFinal)
1095 {
1096 if (wrapper.IsInterface || wrapper.classLoader.StrictFinalFieldSemantics)
1097 attribs |= FieldAttributes.InitOnly;
1098 else
1099 setModifiers = true;
1100 }
1101#else
1102 if (fld.IsFinal && wrapper.IsInterface)
1103 attribs |= FieldAttributes.InitOnly;
1104#endif
1105
1106 field = DefineField(realFieldName, fw.FieldTypeWrapper, attribs, fld.IsVolatile);
1107 }
1108 if (fld.IsTransient)
1109 {
1110 var transientAttrib = new CustomAttributeBuilder(wrapper.Context.Resolver.ResolveCoreType(typeof(NonSerializedAttribute).FullName).GetConstructor([]).AsReflection(), Array.Empty<object>());
1111 field.SetCustomAttribute(transientAttrib);
1112 }
1113#if IMPORTER
1114 {
1115 // if the Java modifiers cannot be expressed in .NET, we emit the Modifiers attribute to store
1116 // the Java modifiers
1117 if (setModifiers)
1118 wrapper.Context.AttributeHelper.SetModifiers(field, fld.Modifiers, fld.IsInternal);
1119
1120 if (fld.DeprecatedAttribute && !Annotation.HasObsoleteAttribute(fld.Annotations))
1121 wrapper.Context.AttributeHelper.SetDeprecatedAttribute(field);
1122
1123 if (fld.GenericSignature != null)
1124 wrapper.Context.AttributeHelper.SetSignatureAttribute(field, fld.GenericSignature);
1125
1126 if (fld.RuntimeVisibleTypeAnnotations.Count > 0)
1127 wrapper.Context.AttributeHelper.SetRuntimeVisibleTypeAnnotationsAttribute(field, in fld.RuntimeVisibleTypeAnnotations);
1128 }
1129#endif
1130
1131 return field;
1132 }
1133
1134 bool HasNestmates()
1135 {
1136 // A '$' is retained as a fallback because older class files can omit
1137 // InnerClasses metadata. It also matches the nestmate test used by
1138 // RuntimeJavaMember.
1139 if (classFile.Name.IndexOf('$') >= 0)
1140 return true;
1141
1142 var innerClasses = classFile.InnerClasses;
1143 if (innerClasses == null)
1144 return false;
1145
1146 foreach (var innerClass in innerClasses)
1147 if (innerClass.outerClass.IsNotNil &&
1148 classFile.GetConstantPoolClass(innerClass.outerClass) == classFile.Name)
1149 return true;
1150
1151 return false;
1152 }
1153
1154 FieldBuilder DefineField(string name, RuntimeJavaType tw, FieldAttributes attribs, bool isVolatile)
1155 {
1156 var modreq = isVolatile ? [wrapper.Context.Types.IsVolatile] : Type.EmptyTypes;
1157 return typeBuilder.DefineField(name, tw.TypeAsSignatureType, modreq, wrapper.GetModOpt(tw, false), attribs);
1158 }
1159
1160 internal override void EmitRunClassConstructor(CodeEmitter ilgen)
1161 {
1162 if (clinitMethod != null)
1163 ilgen.Emit(OpCodes.Call, clinitMethod);
1164 }
1165
1166 internal override DynamicImpl Finish()
1167 {
1168 var baseTypeWrapper = wrapper.BaseTypeWrapper;
1169 if (baseTypeWrapper != null)
1170 {
1171 baseTypeWrapper.Finish();
1172 baseTypeWrapper.LinkAll();
1173 }
1174
1175 // NOTE there is a bug in the CLR (.NET 1.0 & 1.1 [1.2 is not yet available]) that
1176 // causes the AppDomain.TypeResolve event to receive the incorrect type name for nested types.
1177 // The Name in the ResolveEventArgs contains only the nested type name, not the full type name,
1178 // for example, if the type being resolved is "MyOuterType+MyInnerType", then the event only
1179 // receives "MyInnerType" as the name. Since we only compile inner classes as nested types
1180 // when we're statically compiling, we can only run into this bug when we're statically compiling.
1181 // NOTE To work around this bug, we have to make sure that all types that are going to be
1182 // required in finished form, are finished explicitly here. It isn't clear what other types are
1183 // required to be finished. I instrumented a static compilation of classpath.dll and this
1184 // turned up no other cases of the TypeResolve event firing.
1185 foreach (var iface in wrapper.interfaces)
1186 {
1187 iface.Finish();
1188 iface.LinkAll();
1189 }
1190
1191 // make sure all classes are loaded, before we start finishing the type. During finishing, we
1192 // may not run any Java code, because that might result in a request to finish the type that we
1193 // are in the process of finishing, and this would be a problem.
1194 // Prevent infinity recursion for broken class loaders by keeping a recursion count and falling
1195 // back to late binding if we recurse more than twice.
1196 var mode = System.Threading.Interlocked.Increment(ref recursionCount) > 2 || (JVM.DisableEagerClassLoading && wrapper.Name != "sun.reflect.misc.Trampoline")
1197 ? LoadMode.ReturnUnloadable
1198 : LoadMode.Link;
1199 try
1200 {
1201 classFile.Link(wrapper, mode);
1202
1203 for (int i = 0; i < fields.Length; i++)
1204 fields[i].Link(mode);
1205
1206 for (int i = 0; i < methods.Length; i++)
1207 methods[i].Link(mode);
1208 }
1209 finally
1210 {
1211 System.Threading.Interlocked.Decrement(ref recursionCount);
1212 }
1213
1214 // this is the correct lock, FinishCore doesn't call any user code and mutates global state,
1215 // so it needs to be protected by a lock.
1216 lock (this)
1217 {
1218 FinishedTypeImpl impl;
1219
1220 try
1221 {
1222 // call FinishCore in the finally to avoid Thread.Abort interrupting the thread
1223 }
1224 finally
1225 {
1226 impl = FinishCore();
1227 }
1228
1229 return impl;
1230 }
1231 }
1232
1233 FinishedTypeImpl FinishCore()
1234 {
1235 // it is possible that the loading of the referenced classes triggered a finish of us,
1236 // if that happens, we just return
1237 if (finishedType != null)
1238 return finishedType;
1239
1240 if (finishInProgress)
1241 throw new InvalidOperationException("Recursive finish attempt for " + wrapper.Name);
1242
1243 finishInProgress = true;
1244 wrapper.ClassLoader.Diagnostics.GenericCompilerTrace($"Finishing: {wrapper.Name}");
1245
1246 try
1247 {
1248 RuntimeJavaType declaringTypeWrapper = null;
1249 var innerClassesTypeWrappers = Array.Empty<RuntimeJavaType>();
1250
1251 // if we're an inner class, we need to attach an InnerClass attribute
1252 var innerclasses = classFile.InnerClasses;
1253 if (innerclasses != null)
1254 {
1255 // TODO consider not pre-computing innerClassesTypeWrappers and declaringTypeWrapper here
1256 var wrappers = new List<RuntimeJavaType>();
1257 for (int i = 0; i < innerclasses.Length; i++)
1258 {
1259 if (innerclasses[i].innerClass.IsNotNil && innerclasses[i].outerClass.IsNotNil)
1260 {
1261 if (classFile.GetConstantPoolClassType(innerclasses[i].outerClass) == wrapper)
1262 wrappers.Add(classFile.GetConstantPoolClassType(innerclasses[i].innerClass));
1263 if (classFile.GetConstantPoolClassType(innerclasses[i].innerClass) == wrapper)
1264 declaringTypeWrapper = classFile.GetConstantPoolClassType(innerclasses[i].outerClass);
1265 }
1266 }
1267 innerClassesTypeWrappers = wrappers.ToArray();
1268
1269#if IMPORTER
1270 // before we bake our type, we need to link any inner annotations to allow them to create their attribute type (as a nested type)
1271 foreach (var tw in innerClassesTypeWrappers)
1272 {
1273 if (tw is RuntimeByteCodeJavaType dtw)
1274 {
1275 var impl = dtw.impl as JavaTypeImpl;
1276 if (impl != null)
1277 if (impl.annotationBuilder != null)
1278 impl.annotationBuilder.Link();
1279 }
1280 }
1281#endif
1282
1283 }
1284#if IMPORTER
1285
1286 if (annotationBuilder != null)
1287 {
1288 var cab = new CustomAttributeBuilder(wrapper.Context.Resolver.ResolveRuntimeType(typeof(AnnotationAttributeAttribute).FullName).AsReflection().GetConstructor(new Type[] { wrapper.Context.Types.String }), new object[] { UnicodeUtil.EscapeInvalidSurrogates(annotationBuilder.AttributeTypeName) });
1289 typeBuilder.SetCustomAttribute(cab);
1290 }
1291
1292 if (!wrapper.IsInterface && wrapper.IsMapUnsafeException)
1293 {
1294 // mark all exceptions that are unsafe for mapping with a custom attribute,
1295 // so that at runtime we can quickly assertain if an exception type can be
1296 // caught without filtering
1297 wrapper.Context.AttributeHelper.SetExceptionIsUnsafeForMapping(typeBuilder);
1298 }
1299#endif
1300
1301 var context = new FinishContext(wrapper.Context, host, classFile, wrapper, typeBuilder);
1302 var type = context.FinishImpl();
1303
1304#if IMPORTER
1305 if (annotationBuilder != null)
1306 annotationBuilder.Finish(this);
1307
1308 if (enumBuilder != null)
1309 enumBuilder.CreateType();
1310
1311 if (privateInterfaceMethods != null)
1312 privateInterfaceMethods.CreateType();
1313#endif
1314
1315 var finishedClinitMethod = (MethodInfo)clinitMethod;
1316#if !IMPORTER
1317 if (finishedClinitMethod != null)
1318 {
1319 // In dynamic mode, we may need to emit a call to this method from a DynamicMethod which doesn't support calling unfinished methods,
1320 // so we must resolve to the real method here.
1321 finishedClinitMethod = type.GetMethod("__<clinit>", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
1322 }
1323#endif
1324
1325 finishedType = new FinishedTypeImpl(type, innerClassesTypeWrappers, declaringTypeWrapper, wrapper.ReflectiveModifiers, Metadata.Create(classFile), finishedClinitMethod, finalizeMethod, host);
1326 return finishedType;
1327 }
1328#if !IMPORTER
1329 catch (Exception x)
1330 {
1331 throw new InternalException($"Exception during finishing of: {wrapper.Name}", x);
1332 }
1333#endif
1334 finally
1335 {
1336
1337 }
1338 }
1339
1340#if IMPORTER
1341
1342 bool IsValidAnnotationElementType(string type)
1343 {
1344 if (type[0] == '[')
1345 type = type.Substring(1);
1346
1347 switch (type)
1348 {
1349 case "Z":
1350 case "B":
1351 case "S":
1352 case "C":
1353 case "I":
1354 case "J":
1355 case "F":
1356 case "D":
1357 case "Ljava.lang.String;":
1358 case "Ljava.lang.Class;":
1359 return true;
1360 }
1361
1362 if (type.StartsWith("L") && type.EndsWith(";"))
1363 {
1364 try
1365 {
1366 var tw = wrapper.ClassLoader.TryLoadClassByName(type.Substring(1, type.Length - 2));
1367 if (tw != null)
1368 {
1369 if ((tw.Modifiers & Modifiers.Annotation) != 0)
1370 return true;
1371
1372 if ((tw.Modifiers & Modifiers.Enum) != 0)
1373 {
1374 var enumType = wrapper.Context.ClassLoaderFactory.GetBootstrapClassLoader().TryLoadClassByName("java.lang.Enum");
1375 if (enumType != null && tw.IsSubTypeOf(enumType))
1376 return true;
1377 }
1378 }
1379 }
1380 catch
1381 {
1382
1383 }
1384 }
1385
1386 return false;
1387 }
1388
1389 sealed class AnnotationBuilder : Annotation
1390 {
1391
1392 readonly RuntimeContext context;
1393
1394 JavaTypeImpl impl;
1395 TypeBuilder outer;
1396 TypeBuilder annotationTypeBuilder;
1397 TypeBuilder attributeTypeBuilder;
1398 MethodBuilder defineConstructor;
1399
1406 internal AnnotationBuilder(RuntimeContext context, JavaTypeImpl o, TypeBuilder outer)
1407 {
1408 this.context = context;
1409 this.impl = o;
1410 this.outer = outer;
1411 }
1412
1413 internal void Link()
1414 {
1415 if (impl == null)
1416 return;
1417
1418 var o = impl;
1419 impl = null;
1420
1421 // Make sure the annotation type only has valid methods
1422 for (int i = 0; i < o.methods.Length; i++)
1423 {
1424 if (!o.methods[i].IsStatic)
1425 {
1426 if (!o.methods[i].Signature.StartsWith("()"))
1427 return;
1428 if (!o.IsValidAnnotationElementType(o.methods[i].Signature.Substring(2)))
1429 return;
1430 }
1431 }
1432
1433 // we only set annotationTypeBuilder if we're valid
1434 annotationTypeBuilder = o.typeBuilder;
1435
1436 var annotationAttributeBaseType = context.ClassLoaderFactory.LoadClassCritical("ikvm.internal.AnnotationAttributeBase");
1437
1438 // make sure we don't clash with another class name
1439 var ccl = o.wrapper.classLoader;
1440 var name = UnicodeUtil.EscapeInvalidSurrogates(o.classFile.Name);
1441 while (!ccl.ReserveName(name + "Attribute"))
1442 name += "_";
1443
1444 var typeAttributes = TypeAttributes.Class | TypeAttributes.Sealed;
1445 if (o.enclosingClassWrapper != null)
1446 {
1447 if (o.wrapper.IsPublic)
1448 typeAttributes |= TypeAttributes.NestedPublic;
1449 else
1450 typeAttributes |= TypeAttributes.NestedAssembly;
1451
1452 attributeTypeBuilder = outer.DefineNestedType(o.AllocNestedTypeName(o.enclosingClassWrapper.Name, name + "Attribute"), typeAttributes, annotationAttributeBaseType.TypeAsBaseType);
1453 }
1454 else
1455 {
1456 if (o.wrapper.IsPublic)
1457 typeAttributes |= TypeAttributes.Public;
1458 else
1459 typeAttributes |= TypeAttributes.NotPublic;
1460
1461 attributeTypeBuilder = o.wrapper.classLoader.GetTypeWrapperFactory().ModuleBuilder.DefineType(name + "Attribute", typeAttributes, annotationAttributeBaseType.TypeAsBaseType);
1462 }
1463
1464 if (o.wrapper.IsPublic)
1465 {
1466 // In the Java world, the class appears as a non-public proxy class
1467 context.AttributeHelper.SetModifiers(attributeTypeBuilder, Modifiers.Final, false);
1468 }
1469
1470 // NOTE we "abuse" the InnerClassAttribute to add a custom attribute to name the class "$Proxy[Annotation]" in the Java world
1471 int dotindex = o.classFile.Name.LastIndexOf('.') + 1;
1472 context.AttributeHelper.SetInnerClass(attributeTypeBuilder, o.classFile.Name.Substring(0, dotindex) + "$Proxy" + o.classFile.Name.Substring(dotindex), Modifiers.Final);
1473 attributeTypeBuilder.AddInterfaceImplementation(o.typeBuilder);
1474 context.AttributeHelper.SetImplementsAttribute(attributeTypeBuilder, new RuntimeJavaType[] { o.wrapper });
1475
1476 if (o.classFile.Annotations != null)
1477 {
1478 CustomAttributeBuilder attributeUsageAttribute = null;
1479 bool hasAttributeUsageAttribute = false;
1480 foreach (object[] def in o.classFile.Annotations)
1481 {
1482 if (def[1].Equals("Ljava/lang/annotation/Target;") && !hasAttributeUsageAttribute)
1483 {
1484 for (int i = 2; i < def.Length; i += 2)
1485 {
1486 if (def[i].Equals("value"))
1487 {
1488 var val = def[i + 1] as object[];
1489 if (val != null &&
1490 val.Length > 0 &&
1492 {
1493 AttributeTargets targets = 0;
1494 for (int j = 1; j < val.Length; j++)
1495 {
1496 var eval = val[j] as object[];
1497 if (eval != null &&
1498 eval.Length == 3 &&
1499 eval[0].Equals(AnnotationDefaultAttribute.TAG_ENUM) &&
1500 eval[1].Equals("Ljava/lang/annotation/ElementType;"))
1501 {
1502 switch ((string)eval[2])
1503 {
1504 case "ANNOTATION_TYPE":
1505 targets |= AttributeTargets.Interface;
1506 break;
1507 case "CONSTRUCTOR":
1508 targets |= AttributeTargets.Constructor;
1509 break;
1510 case "FIELD":
1511 targets |= AttributeTargets.Field;
1512 break;
1513 case "LOCAL_VARIABLE":
1514 break;
1515 case "METHOD":
1516 targets |= AttributeTargets.Method;
1517 break;
1518 case "PACKAGE":
1519 targets |= AttributeTargets.Interface;
1520 break;
1521 case "PARAMETER":
1522 targets |= AttributeTargets.Parameter;
1523 break;
1524 case "TYPE":
1525 targets |= AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Delegate | AttributeTargets.Enum;
1526 break;
1527 }
1528 }
1529 }
1530
1531 attributeUsageAttribute = new CustomAttributeBuilder(context.Resolver.ResolveCoreType(typeof(AttributeUsageAttribute).FullName).GetConstructor([context.Resolver.ResolveCoreType(typeof(AttributeTargets).FullName)]).AsReflection(), [targets]);
1532 }
1533 }
1534 }
1535 }
1536 else
1537 {
1538 // apply any .NET custom attributes that are on the annotation to the custom attribute we synthesize
1539 // (for example, to allow AttributeUsageAttribute to be overridden)
1540 var annotation = Annotation.Load(o.wrapper, def);
1541 if (annotation != null && annotation.IsCustomAttribute)
1542 annotation.Apply(o.wrapper.ClassLoader, attributeTypeBuilder, def);
1543
1544 if (def[1].Equals("Lcli/System/AttributeUsageAttribute$Annotation;"))
1545 hasAttributeUsageAttribute = true;
1546 }
1547 }
1548
1549 if (attributeUsageAttribute != null && !hasAttributeUsageAttribute)
1550 attributeTypeBuilder.SetCustomAttribute(attributeUsageAttribute);
1551 }
1552
1553 defineConstructor = ReflectUtil.DefineConstructor(attributeTypeBuilder, MethodAttributes.Public, new Type[] { context.Resolver.ResolveCoreType(typeof(object).FullName).MakeArrayType().AsReflection() });
1554 context.AttributeHelper.SetEditorBrowsableNever(defineConstructor);
1555 }
1556
1557 static Type TypeWrapperToAnnotationParameterType(RuntimeJavaType tw)
1558 {
1559 var isArray = false;
1560 if (tw.IsArray)
1561 {
1562 isArray = true;
1563 tw = tw.ElementTypeWrapper;
1564 }
1565
1566 if (tw.Annotation != null)
1567 {
1568 // we don't support Annotation args
1569 return null;
1570 }
1571 else
1572 {
1573 Type argType;
1574 if (tw == tw.Context.JavaBase.TypeOfJavaLangClass)
1575 {
1576 argType = tw.Context.Types.Type;
1577 }
1578 else if (tw.EnumType != null) // is it a Java enum?
1579 {
1580 argType = tw.EnumType;
1581 }
1582 else if (IsDotNetEnum(tw))
1583 {
1584 argType = tw.DeclaringTypeWrapper.TypeAsSignatureType;
1585 }
1586 else
1587 {
1588 argType = tw.TypeAsSignatureType;
1589 }
1590
1591 if (isArray)
1592 argType = RuntimeArrayJavaType.MakeArrayType(argType, 1);
1593
1594 return argType;
1595 }
1596 }
1597
1598 static bool IsDotNetEnum(RuntimeJavaType tw)
1599 {
1600 return tw.IsFakeNestedType && (tw.Modifiers & Modifiers.Enum) != 0;
1601 }
1602
1603 internal string AttributeTypeName
1604 {
1605 get
1606 {
1607 Link();
1608
1609 if (attributeTypeBuilder != null)
1610 return attributeTypeBuilder.FullName;
1611
1612 return null;
1613 }
1614 }
1615
1616 static void EmitSetValueCall(RuntimeJavaType annotationAttributeBaseType, CodeEmitter ilgen, string name, RuntimeJavaType tw, int argIndex)
1617 {
1618 ilgen.Emit(OpCodes.Ldarg_0);
1619 ilgen.Emit(OpCodes.Ldstr, name);
1620 ilgen.EmitLdarg(argIndex);
1621
1622 if (tw.TypeAsSignatureType.IsValueType)
1623 ilgen.Emit(OpCodes.Box, tw.TypeAsSignatureType);
1624 else if (tw.EnumType != null) // is it a Java enum?
1625 ilgen.Emit(OpCodes.Box, tw.EnumType);
1626 else if (IsDotNetEnum(tw))
1627 ilgen.Emit(OpCodes.Box, tw.DeclaringTypeWrapper.TypeAsSignatureType);
1628
1629 var setValueMethod = annotationAttributeBaseType.GetMethod("setValue", "(Ljava.lang.String;Ljava.lang.Object;)V", false);
1630 setValueMethod.Link();
1631 setValueMethod.EmitCall(ilgen);
1632 }
1633
1634 internal void Finish(JavaTypeImpl o)
1635 {
1636 Link();
1637
1638 // not a valid annotation type
1639 if (annotationTypeBuilder == null)
1640 return;
1641
1642 var annotationAttributeBaseType = context.ClassLoaderFactory.LoadClassCritical("ikvm.internal.AnnotationAttributeBase");
1643 annotationAttributeBaseType.Finish();
1644
1645 int requiredArgCount = 0;
1646 int valueArg = -1;
1647 bool unsupported = false;
1648 for (int i = 0; i < o.methods.Length; i++)
1649 {
1650 if (!o.methods[i].IsStatic)
1651 {
1652 if (valueArg == -1 && o.methods[i].Name == "value")
1653 valueArg = i;
1654
1655 if (o.classFile.Methods[i].AnnotationDefault == null)
1656 {
1657 if (TypeWrapperToAnnotationParameterType(o.methods[i].ReturnType) == null)
1658 {
1659 unsupported = true;
1660 break;
1661 }
1662
1663 requiredArgCount++;
1664 }
1665 }
1666 }
1667
1668 var defaultConstructor = ReflectUtil.DefineConstructor(attributeTypeBuilder, unsupported || requiredArgCount > 0 ? MethodAttributes.Private : MethodAttributes.Public, Type.EmptyTypes);
1669 CodeEmitter ilgen;
1670
1671 if (!unsupported)
1672 {
1673 if (requiredArgCount > 0)
1674 {
1675 var args = new Type[requiredArgCount];
1676 for (int i = 0, j = 0; i < o.methods.Length; i++)
1677 if (!o.methods[i].IsStatic)
1678 if (o.classFile.Methods[i].AnnotationDefault == null)
1679 args[j++] = TypeWrapperToAnnotationParameterType(o.methods[i].ReturnType);
1680
1681 var reqArgConstructor = ReflectUtil.DefineConstructor(attributeTypeBuilder, MethodAttributes.Public, args);
1682 context.AttributeHelper.HideFromJava(reqArgConstructor);
1683 ilgen = context.CodeEmitterFactory.Create(reqArgConstructor);
1684 ilgen.Emit(OpCodes.Ldarg_0);
1685 ilgen.Emit(OpCodes.Call, defaultConstructor);
1686 for (int i = 0, j = 0; i < o.methods.Length; i++)
1687 {
1688 if (!o.methods[i].IsStatic)
1689 {
1690 if (o.classFile.Methods[i].AnnotationDefault == null)
1691 {
1692 reqArgConstructor.DefineParameter(++j, ParameterAttributes.None, o.methods[i].Name);
1693 EmitSetValueCall(annotationAttributeBaseType, ilgen, o.methods[i].Name, o.methods[i].ReturnType, j);
1694 }
1695 }
1696 }
1697
1698 ilgen.Emit(OpCodes.Ret);
1699 ilgen.DoEmit();
1700 }
1701 else if (valueArg != -1)
1702 {
1703 // We don't have any required parameters, but we do have an optional "value" parameter,
1704 // so we create an additional constructor (the default constructor will be public in this case)
1705 // that accepts the value parameter.
1706 var argType = TypeWrapperToAnnotationParameterType(o.methods[valueArg].ReturnType);
1707 if (argType != null)
1708 {
1709 var cb = ReflectUtil.DefineConstructor(attributeTypeBuilder, MethodAttributes.Public, [argType]);
1710 context.AttributeHelper.HideFromJava(cb);
1711 cb.DefineParameter(1, ParameterAttributes.None, "value");
1712 ilgen = context.CodeEmitterFactory.Create(cb);
1713 ilgen.Emit(OpCodes.Ldarg_0);
1714 ilgen.Emit(OpCodes.Call, defaultConstructor);
1715 EmitSetValueCall(annotationAttributeBaseType, ilgen, "value", o.methods[valueArg].ReturnType, 1);
1716 ilgen.Emit(OpCodes.Ret);
1717 ilgen.DoEmit();
1718 }
1719 }
1720 }
1721
1722 ilgen = context.CodeEmitterFactory.Create(defaultConstructor);
1723 ilgen.Emit(OpCodes.Ldarg_0);
1724 o.wrapper.EmitClassLiteral(ilgen);
1725 annotationAttributeBaseType.GetMethod("<init>", "(Ljava.lang.Class;)V", false).EmitCall(ilgen);
1726 ilgen.Emit(OpCodes.Ret);
1727 ilgen.DoEmit();
1728
1729 ilgen = context.CodeEmitterFactory.Create(defineConstructor);
1730 ilgen.Emit(OpCodes.Ldarg_0);
1731 ilgen.Emit(OpCodes.Call, defaultConstructor);
1732 ilgen.Emit(OpCodes.Ldarg_0);
1733 ilgen.Emit(OpCodes.Ldarg_1);
1734 annotationAttributeBaseType.GetMethod("setDefinition", "([Ljava.lang.Object;)V", false).EmitCall(ilgen);
1735 ilgen.Emit(OpCodes.Ret);
1736 ilgen.DoEmit();
1737
1738 var getValueMethod = annotationAttributeBaseType.GetMethod("getValue", "(Ljava.lang.String;)Ljava.lang.Object;", false);
1739 var getByteValueMethod = annotationAttributeBaseType.GetMethod("getByteValue", "(Ljava.lang.String;)B", false);
1740 var getBooleanValueMethod = annotationAttributeBaseType.GetMethod("getBooleanValue", "(Ljava.lang.String;)Z", false);
1741 var getCharValueMethod = annotationAttributeBaseType.GetMethod("getCharValue", "(Ljava.lang.String;)C", false);
1742 var getShortValueMethod = annotationAttributeBaseType.GetMethod("getShortValue", "(Ljava.lang.String;)S", false);
1743 var getIntValueMethod = annotationAttributeBaseType.GetMethod("getIntValue", "(Ljava.lang.String;)I", false);
1744 var getFloatValueMethod = annotationAttributeBaseType.GetMethod("getFloatValue", "(Ljava.lang.String;)F", false);
1745 var getLongValueMethod = annotationAttributeBaseType.GetMethod("getLongValue", "(Ljava.lang.String;)J", false);
1746 var getDoubleValueMethod = annotationAttributeBaseType.GetMethod("getDoubleValue", "(Ljava.lang.String;)D", false);
1747
1748 for (int i = 0; i < o.methods.Length; i++)
1749 {
1750 // skip <clinit> and non-virtual interface methods introduced in Java 8
1751 if (o.methods[i].IsVirtual)
1752 {
1753 var mb = o.methods[i].GetDefineMethodHelper().DefineMethod(o.wrapper, attributeTypeBuilder, o.methods[i].Name, MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot);
1754 attributeTypeBuilder.DefineMethodOverride(mb, (MethodInfo)o.methods[i].GetMethod());
1755 ilgen = context.CodeEmitterFactory.Create(mb);
1756 ilgen.Emit(OpCodes.Ldarg_0);
1757 ilgen.Emit(OpCodes.Ldstr, o.methods[i].Name);
1758 if (o.methods[i].ReturnType.IsPrimitive)
1759 {
1760 if (o.methods[i].ReturnType == context.PrimitiveJavaTypeFactory.BYTE)
1761 {
1762 getByteValueMethod.EmitCall(ilgen);
1763 }
1764 else if (o.methods[i].ReturnType == context.PrimitiveJavaTypeFactory.BOOLEAN)
1765 {
1766 getBooleanValueMethod.EmitCall(ilgen);
1767 }
1768 else if (o.methods[i].ReturnType == context.PrimitiveJavaTypeFactory.CHAR)
1769 {
1770 getCharValueMethod.EmitCall(ilgen);
1771 }
1772 else if (o.methods[i].ReturnType == context.PrimitiveJavaTypeFactory.SHORT)
1773 {
1774 getShortValueMethod.EmitCall(ilgen);
1775 }
1776 else if (o.methods[i].ReturnType == context.PrimitiveJavaTypeFactory.INT)
1777 {
1778 getIntValueMethod.EmitCall(ilgen);
1779 }
1780 else if (o.methods[i].ReturnType == context.PrimitiveJavaTypeFactory.FLOAT)
1781 {
1782 getFloatValueMethod.EmitCall(ilgen);
1783 }
1784 else if (o.methods[i].ReturnType == context.PrimitiveJavaTypeFactory.LONG)
1785 {
1786 getLongValueMethod.EmitCall(ilgen);
1787 }
1788 else if (o.methods[i].ReturnType == context.PrimitiveJavaTypeFactory.DOUBLE)
1789 {
1790 getDoubleValueMethod.EmitCall(ilgen);
1791 }
1792 else
1793 {
1794 throw new InvalidOperationException();
1795 }
1796 }
1797 else
1798 {
1799 getValueMethod.EmitCall(ilgen);
1800 o.methods[i].ReturnType.EmitCheckcast(ilgen);
1801 }
1802
1803 ilgen.Emit(OpCodes.Ret);
1804 ilgen.DoEmit();
1805
1806 if (o.classFile.Methods[i].AnnotationDefault != null &&
1807 !(o.methods[i].Name == "value" && requiredArgCount == 0))
1808 {
1809 // now add a .NET property for this annotation optional parameter
1810 var argType = TypeWrapperToAnnotationParameterType(o.methods[i].ReturnType);
1811 if (argType != null)
1812 {
1813 var property = attributeTypeBuilder.DefineProperty(o.methods[i].Name, PropertyAttributes.None, argType, Type.EmptyTypes);
1814 context.AttributeHelper.HideFromJava(property);
1815
1816 var setter = attributeTypeBuilder.DefineMethod("set_" + o.methods[i].Name, MethodAttributes.Public, context.Types.Void, [argType]);
1817 context.AttributeHelper.HideFromJava(setter);
1818 property.SetSetMethod(setter);
1819
1820 ilgen = context.CodeEmitterFactory.Create(setter);
1821 EmitSetValueCall(annotationAttributeBaseType, ilgen, o.methods[i].Name, o.methods[i].ReturnType, 1);
1822 ilgen.Emit(OpCodes.Ret);
1823 ilgen.DoEmit();
1824
1825 var getter = attributeTypeBuilder.DefineMethod("get_" + o.methods[i].Name, MethodAttributes.Public, argType, Type.EmptyTypes);
1826 context.AttributeHelper.HideFromJava(getter);
1827 property.SetGetMethod(getter);
1828
1829 // TODO implement the getter method
1830 ilgen = context.CodeEmitterFactory.Create(getter);
1831 ilgen.ThrowException(context.Resolver.ResolveCoreType(typeof(NotImplementedException).FullName).AsReflection());
1832 ilgen.DoEmit();
1833 }
1834 }
1835 }
1836 }
1837
1838 attributeTypeBuilder.CreateType();
1839 }
1840
1841 CustomAttributeBuilder MakeCustomAttributeBuilder(RuntimeClassLoader loader, object annotation)
1842 {
1843 Link();
1844
1845 ConstructorInfo ctor = defineConstructor != null
1846 ? defineConstructor.__AsConstructorInfo()
1847 : context.Resolver.ResolveRuntimeType("IKVM.Attributes.DynamicAnnotationAttribute").AsReflection().GetConstructor([context.Types.Object.MakeArrayType()]);
1848
1849 return new CustomAttributeBuilder(ctor, [AnnotationDefaultAttribute.Escape(QualifyClassNames(loader, annotation))]);
1850 }
1851
1852 internal override void Apply(RuntimeClassLoader loader, TypeBuilder tb, object annotation)
1853 {
1854 tb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1855 }
1856
1857 internal override void Apply(RuntimeClassLoader loader, MethodBuilder mb, object annotation)
1858 {
1859 mb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1860 }
1861
1862 internal override void Apply(RuntimeClassLoader loader, FieldBuilder fb, object annotation)
1863 {
1864 fb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1865 }
1866
1867 internal override void Apply(RuntimeClassLoader loader, ParameterBuilder pb, object annotation)
1868 {
1869 pb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1870 }
1871
1872 internal override void Apply(RuntimeClassLoader loader, AssemblyBuilder ab, object annotation)
1873 {
1874 ab.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1875 }
1876
1877 internal override void Apply(RuntimeClassLoader loader, PropertyBuilder pb, object annotation)
1878 {
1879 pb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1880 }
1881
1882 internal override bool IsCustomAttribute
1883 {
1884 get { return false; }
1885 }
1886 }
1887
1888#endif // IMPORTER
1889
1890 internal override RuntimeJavaType[] InnerClasses => throw new InvalidOperationException("InnerClasses is only available for finished types");
1891
1892 internal override RuntimeJavaType DeclaringTypeWrapper => throw new InvalidOperationException("DeclaringTypeWrapper is only available for finished types");
1893
1894 internal override Modifiers ReflectiveModifiers
1895 {
1896 get
1897 {
1898 Modifiers mods;
1899
1900 var innerclasses = classFile.InnerClasses;
1901 if (innerclasses != null)
1902 {
1903 for (int i = 0; i < innerclasses.Length; i++)
1904 {
1905 if (innerclasses[i].innerClass.IsNotNil)
1906 {
1907 if (classFile.GetConstantPoolClass(innerclasses[i].innerClass) == wrapper.Name)
1908 {
1909 // the mask comes from RECOGNIZED_INNER_CLASS_MODIFIERS in src/hotspot/share/vm/classfile/classFileParser.cpp
1910 // (minus ACC_SUPER)
1911 mods = innerclasses[i].accessFlags & (Modifiers)0x761F;
1912 if (classFile.IsInterface)
1913 mods |= Modifiers.Abstract;
1914
1915 return mods;
1916 }
1917 }
1918 }
1919 }
1920
1921 // the mask comes from JVM_RECOGNIZED_CLASS_MODIFIERS in src/hotspot/share/vm/prims/jvm.h
1922 // (minus ACC_SUPER)
1923 mods = classFile.Modifiers & (Modifiers)0x7611;
1924 if (classFile.IsInterface)
1925 mods |= Modifiers.Abstract;
1926
1927 return mods;
1928 }
1929 }
1930
1937 RuntimeJavaMethod[] FindBaseMethods(ClassFile.Method m, out bool explicitOverride)
1938 {
1939 Debug.Assert(!classFile.IsInterface);
1940 Debug.Assert(m.Name != "<init>");
1941
1942 // starting with Java 7 the algorithm changed
1943 return classFile.MajorVersion >= 51 ? FindBaseMethods7(m.Name, m.Signature, m.IsFinal && !m.IsPublic && !m.IsProtected, out explicitOverride) : FindBaseMethodsLegacy(m.Name, m.Signature, out explicitOverride);
1944 }
1945
1946 RuntimeJavaMethod[] FindBaseMethods7(string name, string sig, bool packageFinal, out bool explicitOverride)
1947 {
1948 // NOTE this implements the (completely broken) OpenJDK 7 b147 HotSpot behavior,
1949 // not the algorithm specified in section 5.4.5 of the JavaSE7 JVM spec
1950 // see http://weblog.ikvm.net/PermaLink.aspx?guid=bde44d8b-7ba9-4e0e-b3a6-b735627118ff and subsequent posts
1951 // UPDATE as of JDK 7u65 and JDK 8u11, the algorithm changed again to handle package private methods differently
1952 // this code has not been updated to reflect these changes (we're still at JDK 8 GA level)
1953 explicitOverride = false;
1954 RuntimeJavaMethod topPublicOrProtectedMethod = null;
1955 var tw = wrapper.BaseTypeWrapper;
1956 while (tw != null)
1957 {
1958 var baseMethod = tw.GetMethod(name, sig, true);
1959 if (baseMethod == null)
1960 break;
1961 else if (baseMethod.IsAccessStub)
1962 {
1963 // ignore
1964 }
1965 else if (!baseMethod.IsStatic && (baseMethod.IsPublic || baseMethod.IsProtected))
1966 topPublicOrProtectedMethod = baseMethod;
1967
1968 tw = baseMethod.DeclaringType.BaseTypeWrapper;
1969 }
1970
1971 tw = wrapper.BaseTypeWrapper;
1972
1973 while (tw != null)
1974 {
1975 var baseMethod = tw.GetMethod(name, sig, true);
1976 if (baseMethod == null)
1977 {
1978 break;
1979 }
1980 else if (baseMethod.IsAccessStub)
1981 {
1982 // ignore
1983 }
1984 else if (baseMethod.IsPrivate)
1985 {
1986 // skip
1987 }
1988 else if (baseMethod.IsFinal && (baseMethod.IsPublic || baseMethod.IsProtected || IsAccessibleInternal(baseMethod) || baseMethod.DeclaringType.IsPackageAccessibleFrom(wrapper)))
1989 {
1990 throw new VerifyError("final method " + baseMethod.Name + baseMethod.Signature + " in " + baseMethod.DeclaringType.Name + " is overridden in " + wrapper.Name);
1991 }
1992 else if (baseMethod.IsStatic)
1993 {
1994 // skip
1995 }
1996 else if (topPublicOrProtectedMethod == null && !baseMethod.IsPublic && !baseMethod.IsProtected && !IsAccessibleInternal(baseMethod) && !baseMethod.DeclaringType.IsPackageAccessibleFrom(wrapper))
1997 {
1998 // this is a package private method that we're not overriding (unless its vtable stream interleaves ours, which is a case we handle below)
1999 explicitOverride = true;
2000 }
2001 else if (topPublicOrProtectedMethod != null && baseMethod.IsFinal && !baseMethod.IsPublic && !baseMethod.IsProtected && !IsAccessibleInternal(baseMethod) && !baseMethod.DeclaringType.IsPackageAccessibleFrom(wrapper))
2002 {
2003 // this is package private final method that we would override had it not been final, but which is ignored by HotSpot (instead of throwing a VerifyError)
2004 explicitOverride = true;
2005 }
2006 else if (topPublicOrProtectedMethod == null)
2007 {
2008 if (explicitOverride)
2009 {
2010 var list = new List<RuntimeJavaMethod>();
2011 list.Add(baseMethod);
2012
2013 // we might still have to override package methods from another package if the vtable streams are interleaved with ours
2014 tw = wrapper.BaseTypeWrapper;
2015 while (tw != null)
2016 {
2017 var baseMethod2 = tw.GetMethod(name, sig, true);
2018 if (baseMethod2 == null || baseMethod2 == baseMethod)
2019 break;
2020
2021 var baseMethod3 = GetPackageBaseMethod(baseMethod.DeclaringType.BaseTypeWrapper, name, sig, baseMethod2.DeclaringType);
2022 if (baseMethod3 != null)
2023 {
2024 if (baseMethod2.IsFinal)
2025 baseMethod2 = baseMethod3;
2026
2027 var found = false;
2028 foreach (var mw in list)
2029 {
2030 if (mw.DeclaringType.IsPackageAccessibleFrom(baseMethod2.DeclaringType))
2031 {
2032 // we should only add each package once
2033 found = true;
2034 break;
2035 }
2036 }
2037
2038 if (found == false)
2039 list.Add(baseMethod2);
2040 }
2041
2042 tw = baseMethod2.DeclaringType.BaseTypeWrapper;
2043 }
2044
2045 return list.ToArray();
2046 }
2047 else
2048 {
2049 return [baseMethod];
2050 }
2051 }
2052 else
2053 {
2054 if (packageFinal)
2055 {
2056 // when a package final method overrides a public or protected method, HotSpot does not mark that vtable slot as final,
2057 // so we need an explicit override to force the MethodAttributes.NewSlot flag, otherwise the CLR won't allow us
2058 // to override the original method in subsequent derived types
2059 explicitOverride = true;
2060 }
2061
2062 int majorVersion = 0;
2063 if (!baseMethod.IsPublic && !baseMethod.IsProtected &&
2064 ((TryGetClassFileVersion(baseMethod.DeclaringType, ref majorVersion) && majorVersion < 51)
2065 // if TryGetClassFileVersion fails, we know that it is safe to call GetMethod() so we look at the actual method attributes here,
2066 // because access widing ensures that if the method had overridden the top level method it would also be public or protected
2067 || (majorVersion == 0 && (LinkAndGetMethod(baseMethod).Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly)))
2068 {
2069 // the method we're overriding is not public or protected, but there is a public or protected top level method,
2070 // this means that baseMethod is part of a class with a major version < 51, so we have to explicitly override the top level method as well
2071 // (we don't need to look for another package method to override, because by necessity baseMethod is already in our package)
2072 return [baseMethod, topPublicOrProtectedMethod];
2073 }
2074 else if (!topPublicOrProtectedMethod.DeclaringType.IsPackageAccessibleFrom(wrapper))
2075 {
2076 // check if there is another method (in the same package) that we should override
2077 tw = topPublicOrProtectedMethod.DeclaringType.BaseTypeWrapper;
2078 while (tw != null)
2079 {
2080 var baseMethod2 = tw.GetMethod(name, sig, true);
2081 if (baseMethod2 == null)
2082 break;
2083
2084 if (baseMethod2.IsAccessStub)
2085 {
2086 // ignore
2087 }
2088 else if (baseMethod2.DeclaringType.IsPackageAccessibleFrom(wrapper) && !baseMethod2.IsPrivate)
2089 {
2090 if (baseMethod2.IsFinal)
2091 throw new VerifyError("final method " + baseMethod2.Name + baseMethod2.Signature + " in " + baseMethod2.DeclaringType.Name + " is overridden in " + wrapper.Name);
2092
2093 if (!baseMethod2.IsStatic)
2094 {
2095 if (baseMethod2.IsPublic || baseMethod2.IsProtected)
2096 break;
2097
2098 return [baseMethod, baseMethod2];
2099 }
2100 }
2101
2102 tw = baseMethod2.DeclaringType.BaseTypeWrapper;
2103 }
2104 }
2105
2106 return [baseMethod];
2107 }
2108
2109 tw = baseMethod.DeclaringType.BaseTypeWrapper;
2110 }
2111
2112 return null;
2113 }
2114
2115 bool IsAccessibleInternal(RuntimeJavaMethod mw)
2116 {
2117 return mw.IsInternal && mw.DeclaringType.InternalsVisibleTo(wrapper);
2118 }
2119
2120 static MethodBase LinkAndGetMethod(RuntimeJavaMethod mw)
2121 {
2122 mw.Link();
2123 return mw.GetMethod();
2124 }
2125
2126 static bool TryGetClassFileVersion(RuntimeJavaType tw, ref int majorVersion)
2127 {
2128 if (tw is RuntimeByteCodeJavaType dtw)
2129 {
2130 var impl = dtw.impl as JavaTypeImpl;
2131 if (impl != null)
2132 {
2133 majorVersion = impl.classFile.MajorVersion;
2134 return true;
2135 }
2136 }
2137
2138 return false;
2139 }
2140
2141 static RuntimeJavaMethod GetPackageBaseMethod(RuntimeJavaType tw, string name, string sig, RuntimeJavaType package)
2142 {
2143 while (tw != null)
2144 {
2145 var mw = tw.GetMethod(name, sig, true);
2146 if (mw == null)
2147 break;
2148
2149 if (mw.DeclaringType.IsPackageAccessibleFrom(package))
2150 return mw.IsFinal ? null : mw;
2151
2152 tw = mw.DeclaringType.BaseTypeWrapper;
2153 }
2154
2155 return null;
2156 }
2157
2158 RuntimeJavaMethod[] FindBaseMethodsLegacy(string name, string sig, out bool explicitOverride)
2159 {
2160 explicitOverride = false;
2161 var tw = wrapper.BaseTypeWrapper;
2162 while (tw != null)
2163 {
2164 var baseMethod = tw.GetMethod(name, sig, true);
2165 if (baseMethod == null)
2166 {
2167 return null;
2168 }
2169 else if (baseMethod.IsAccessStub)
2170 {
2171 // ignore
2172 }
2173
2174 // here are the complex rules for determining whether this method overrides the method we found
2175 // RULE 1: final methods may not be overridden
2176 // (note that we intentionally not check IsStatic here!)
2177 else if (baseMethod.IsFinal && !baseMethod.IsPrivate && (baseMethod.IsPublic || baseMethod.IsProtected || baseMethod.DeclaringType.IsPackageAccessibleFrom(wrapper)))
2178 {
2179 throw new VerifyError("final method " + baseMethod.Name + baseMethod.Signature + " in " + baseMethod.DeclaringType.Name + " is overridden in " + wrapper.Name);
2180 }
2181 // RULE 1a: static methods are ignored (other than the RULE 1 check)
2182 else if (baseMethod.IsStatic)
2183 {
2184 }
2185 // RULE 2: public & protected methods can be overridden (package methods are handled by RULE 4)
2186 // (by public, protected & *package* methods [even if they are in a different package])
2187 else if (baseMethod.IsPublic || baseMethod.IsProtected)
2188 {
2189 // if we already encountered a package method, we cannot override the base method of
2190 // that package method
2191 if (explicitOverride)
2192 {
2193 explicitOverride = false;
2194 return null;
2195 }
2196 if (!baseMethod.DeclaringType.IsPackageAccessibleFrom(wrapper))
2197 {
2198 // check if there is another method (in the same package) that we should override
2199 tw = baseMethod.DeclaringType.BaseTypeWrapper;
2200 while (tw != null)
2201 {
2202 RuntimeJavaMethod baseMethod2 = tw.GetMethod(name, sig, true);
2203 if (baseMethod2 == null)
2204 {
2205 break;
2206 }
2207 if (baseMethod2.IsAccessStub)
2208 {
2209 // ignore
2210 }
2211 else if (baseMethod2.DeclaringType.IsPackageAccessibleFrom(wrapper) && !baseMethod2.IsPrivate)
2212 {
2213 if (baseMethod2.IsFinal)
2214 {
2215 throw new VerifyError("final method " + baseMethod2.Name + baseMethod2.Signature + " in " + baseMethod2.DeclaringType.Name + " is overridden in " + wrapper.Name);
2216 }
2217 if (!baseMethod2.IsStatic)
2218 {
2219 if (baseMethod2.IsPublic || baseMethod2.IsProtected)
2220 {
2221 break;
2222 }
2223 return new RuntimeJavaMethod[] { baseMethod, baseMethod2 };
2224 }
2225 }
2226 tw = baseMethod2.DeclaringType.BaseTypeWrapper;
2227 }
2228 }
2229 return new RuntimeJavaMethod[] { baseMethod };
2230 }
2231 // RULE 3: private and static methods are ignored
2232 else if (!baseMethod.IsPrivate)
2233 {
2234 // RULE 4: package methods can only be overridden in the same package
2235 if (baseMethod.DeclaringType.IsPackageAccessibleFrom(wrapper) || (baseMethod.IsInternal && baseMethod.DeclaringType.InternalsVisibleTo(wrapper)))
2236 {
2237 return new RuntimeJavaMethod[] { baseMethod };
2238 }
2239 // since we encountered a method with the same name/signature that we aren't overriding,
2240 // we need to specify an explicit override
2241 // NOTE we only do this if baseMethod isn't private, because if it is, Reflection.Emit
2242 // will complain about the explicit MethodOverride (possibly a bug)
2243 explicitOverride = true;
2244 }
2245 tw = baseMethod.DeclaringType.BaseTypeWrapper;
2246 }
2247
2248 return null;
2249 }
2250
2251 static MethodInfo GetBaseFinalizeMethod(RuntimeJavaType wrapper)
2252 {
2253 for (; ; )
2254 {
2255 // HACK we get called during method linking (which is probably a bad idea) and
2256 // it is possible for the base type not to be finished yet, so we look at the
2257 // private state of the unfinished base types to find the finalize method.
2258 var dtw = wrapper as RuntimeByteCodeJavaType;
2259 if (dtw == null)
2260 break;
2261
2262 var mw = dtw.GetMethod(StringConstants.FINALIZE, StringConstants.SIG_VOID, false);
2263 if (mw != null)
2264 mw.Link();
2265
2266 var finalizeImpl = dtw.impl.GetFinalizeMethod();
2267 if (finalizeImpl != null)
2268 return finalizeImpl;
2269
2270 wrapper = wrapper.BaseTypeWrapper;
2271 }
2272
2273 if (wrapper == wrapper.Context.JavaBase.TypeOfJavaLangObject || wrapper == wrapper.Context.JavaBase.TypeOfjavaLangThrowable)
2274 {
2275 return wrapper.Context.Types.Object.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance);
2276 }
2277
2278 var type = wrapper.TypeAsBaseType;
2279 var baseFinalize = type.GetMethod("__<Finalize>", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
2280 if (baseFinalize != null)
2281 return baseFinalize;
2282
2283 while (type != null)
2284 {
2285 foreach (MethodInfo m in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
2286 {
2287 if (m.Name == "Finalize"
2288 && m.ReturnType == wrapper.Context.Types.Void
2289 && m.GetParameters().Length == 0)
2290 {
2291 if (m.GetBaseDefinition().DeclaringType == wrapper.Context.Types.Object)
2292 {
2293 return m;
2294 }
2295 }
2296 }
2297 type = type.BaseType;
2298 }
2299 return null;
2300 }
2301
2302 MethodAttributes GetPropertyAccess(RuntimeJavaMethod mw)
2303 {
2304 var sig = mw.ReturnType.SigName;
2305 if (sig == "V")
2306 sig = mw.GetParameters()[0].SigName;
2307
2308 int access = -1;
2309 foreach (var field in classFile.Fields)
2310 {
2311 if (field.IsProperty && field.IsStatic == mw.IsStatic && field.Signature == sig && (field.PropertyGetter == mw.Name || field.PropertySetter == mw.Name))
2312 {
2313 int nacc;
2314 if (field.IsPublic)
2315 {
2316 nacc = 3;
2317 }
2318 else if (field.IsProtected)
2319 {
2320 nacc = 2;
2321 }
2322 else if (field.IsPrivate)
2323 {
2324 nacc = 0;
2325 }
2326 else
2327 {
2328 nacc = 1;
2329 }
2330 if (nacc > access)
2331 {
2332 access = nacc;
2333 }
2334 }
2335 }
2336
2337 switch (access)
2338 {
2339 case 0:
2340 return MethodAttributes.Private;
2341 case 1:
2342 return MethodAttributes.Assembly;
2343 case 2:
2344 return MethodAttributes.FamORAssem;
2345 case 3:
2346 return MethodAttributes.Public;
2347 default:
2348 throw new InvalidOperationException();
2349 }
2350 }
2351
2352 internal override MethodBase LinkMethod(RuntimeJavaMethod mw)
2353 {
2354 Debug.Assert(mw != null);
2355
2356 if (mw is DelegateConstructorMethodWrapper dcmw)
2357 {
2358 dcmw.DoLink(typeBuilder);
2359 return null;
2360 }
2361
2362 if (mw is DelegateInvokeStubMethodWrapper stub)
2363 {
2364 return stub.DoLink(typeBuilder);
2365 }
2366
2367 if (mw.IsClassInitializer && mw.IsNoOp && (!wrapper.IsSerializable || HasSerialVersionUID))
2368 {
2369 // we don't need to emit the <clinit>, because it is empty and we're not serializable or have an explicit serialVersionUID
2370 // (because we cannot affect serialVersionUID computation (which is the only way the presence of a <clinit> can surface)
2371 // we cannot do this optimization if the class is serializable but doesn't have a serialVersionUID)
2372 return null;
2373 }
2374
2375 int index = GetMethodIndex(mw);
2376 if (baseMethods[index] != null)
2377 {
2378 foreach (var baseMethod in baseMethods[index])
2379 {
2380 baseMethod.Link();
2381 CheckLoaderConstraints(mw, baseMethod);
2382 }
2383 }
2384
2385 Debug.Assert(mw.GetMethod() == null);
2386 methods[index].AssertLinked();
2387 Profiler.Enter("JavaTypeImpl.GenerateMethod");
2388
2389 try
2390 {
2391 // index is outside the range of methods declared on class file
2392 if (index >= classFile.Methods.Length)
2393 {
2394 // method is a miranda method
2395 if (methods[index].IsMirandaMethod)
2396 {
2397 // we're a Miranda method or we're an inherited default interface method
2398 Debug.Assert(baseMethods[index].Length == 1 && baseMethods[index][0].DeclaringType.IsInterface);
2399
2400 var mmw = (RuntimeMirandaJavaMethod)methods[index];
2401 var attr = MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.CheckAccessOnOverride;
2402
2403 RuntimeJavaMethod baseMiranda = null;
2404 bool baseMirandaOverrideStub = false;
2405
2406 if (wrapper.BaseTypeWrapper == null || (baseMiranda = wrapper.BaseTypeWrapper.GetMethod(mw.Name, mw.Signature, true)) == null || !baseMiranda.IsMirandaMethod)
2407 {
2408 // we're not overriding a miranda method in a base class, so can we set the newslot flag
2409 attr |= MethodAttributes.NewSlot;
2410 }
2411 else
2412 {
2413 baseMiranda.Link();
2414 if (CheckRequireOverrideStub(methods[index], baseMiranda))
2415 {
2416 baseMirandaOverrideStub = true;
2417 attr |= MethodAttributes.NewSlot;
2418 }
2419 }
2420
2421 if (wrapper.IsInterface || (wrapper.IsAbstract && mmw.BaseMethod.IsAbstract && mmw.Error == null))
2422 {
2423 attr |= MethodAttributes.Abstract;
2424 }
2425
2426 var mb = methods[index].GetDefineMethodHelper().DefineMethod(wrapper, typeBuilder, methods[index].Name, attr);
2427 wrapper.Context.AttributeHelper.HideFromReflection(mb);
2428
2429 if (baseMirandaOverrideStub)
2430 {
2431 wrapper.GenerateOverrideStub(typeBuilder, baseMiranda, mb, methods[index]);
2432 }
2433
2434 if ((!wrapper.IsAbstract && mmw.BaseMethod.IsAbstract) || (!wrapper.IsInterface && mmw.Error != null))
2435 {
2436 var message = mmw.Error ?? (wrapper.Name + "." + methods[index].Name + methods[index].Signature);
2437 var ilgen = wrapper.Context.CodeEmitterFactory.Create(mb);
2438 ilgen.EmitThrow(mmw.IsConflictError ? "java.lang.IncompatibleClassChangeError" : "java.lang.AbstractMethodError", message);
2439 ilgen.DoEmit();
2440 wrapper.EmitLevel4Warning(mmw.IsConflictError ? HardError.IncompatibleClassChangeError : HardError.AbstractMethodError, message);
2441 }
2442#if IMPORTER
2443 if (wrapper.IsInterface && !mmw.IsAbstract)
2444 {
2445 // even though we're not visible to reflection we need to record the fact that we have a default implementation
2446 wrapper.Context.AttributeHelper.SetModifiers(mb, mmw.Modifiers, false);
2447 }
2448#endif
2449 return mb;
2450 }
2451 else
2452 {
2453 throw new InvalidOperationException();
2454 }
2455 }
2456
2457 var m = classFile.Methods[index];
2458 MethodBuilder method;
2459 // Record the Java-private modifier when a CLR assembly-visible
2460 // member is required for Java 11 nestmate access.
2461 bool setModifiers = m.IsPrivate && HasNestmates();
2462
2463 if (methods[index].HasCallerID && (m.Modifiers & Modifiers.VarArgs) != 0)
2464 {
2465 // the implicit callerID parameter was added at the end so that means we shouldn't use ParamArrayAttribute,
2466 // so we need to explicitly record that the method is varargs
2467 setModifiers = true;
2468 }
2469
2470 if (m.IsConstructor)
2471 {
2472 method = GenerateConstructor(methods[index]);
2473
2474 // strictfp is the only modifier that a constructor can have
2475 if (m.IsStrictfp)
2476 setModifiers = true;
2477 }
2478 else if (m.IsClassInitializer)
2479 {
2480 method = ReflectUtil.DefineTypeInitializer(typeBuilder, wrapper.classLoader);
2481 }
2482 else
2483 {
2484 method = GenerateMethod(index, m, ref setModifiers);
2485 }
2486
2487 // apply 'throws' Exceptions as attributes
2488 var exceptions = m.ExceptionsAttribute;
2489 methods[index].SetDeclaredExceptions(exceptions);
2490
2491#if IMPORTER
2492 wrapper.Context.AttributeHelper.SetThrowsAttribute(method, exceptions);
2493
2494 if (setModifiers || m.IsInternal || (m.Modifiers & (Modifiers.Synthetic | Modifiers.Bridge)) != 0)
2495 wrapper.Context.AttributeHelper.SetModifiers(method, m.Modifiers, m.IsInternal);
2496
2497 // synthetic and bridge methods should not be visible to the user and set as compiler generated
2498 if ((m.Modifiers & (Modifiers.Synthetic | Modifiers.Bridge)) != 0 && (m.IsPublic || m.IsProtected) && wrapper.IsPublic && !IsAccessBridge(classFile, m))
2499 {
2500 wrapper.Context.AttributeHelper.SetCompilerGenerated(method);
2501 wrapper.Context.AttributeHelper.SetEditorBrowsableNever(method);
2502 }
2503
2504 // ensure deprecated attribute appears on method if obsolete not specified
2505 if (m.DeprecatedAttribute && !Annotation.HasObsoleteAttribute(m.Annotations))
2506 {
2507 wrapper.Context.AttributeHelper.SetDeprecatedAttribute(method);
2508 }
2509
2510 // apply .NET attribute to record Java generic signature
2511 if (m.GenericSignature != null)
2512 {
2513 wrapper.Context.AttributeHelper.SetSignatureAttribute(method, m.GenericSignature);
2514 }
2515
2516 if (wrapper.ClassLoader.NoParameterReflection)
2517 {
2518 // ignore MethodParameters (except to extract parameter names)
2519 }
2520 else if (m.MalformedMethodParameters)
2521 {
2522 wrapper.Context.AttributeHelper.SetMethodParametersAttribute(method, null);
2523 }
2524 else if (m.MethodParameters != null)
2525 {
2526 var modifiers = new Modifiers[m.MethodParameters.Length];
2527 for (int i = 0; i < modifiers.Length; i++)
2528 modifiers[i] = (Modifiers)m.MethodParameters[i].accessFlags;
2529
2530 wrapper.Context.AttributeHelper.SetMethodParametersAttribute(method, modifiers);
2531 }
2532
2533 // copy runtime visible annotations as attributes
2534 if (m.RuntimeVisibleTypeAnnotations.Count > 0)
2535 wrapper.Context.AttributeHelper.SetRuntimeVisibleTypeAnnotationsAttribute(method, in m.RuntimeVisibleTypeAnnotations);
2536
2537#else // IMPORTER
2538
2539 if (setModifiers)
2540 {
2541 // shut up the compiler
2542 }
2543
2544#endif // IMPORTER
2545
2546 return method;
2547 }
2548 finally
2549 {
2550 Profiler.Leave("JavaTypeImpl.GenerateMethod");
2551 }
2552 }
2553
2554 private bool HasSerialVersionUID
2555 {
2556 get
2557 {
2558 foreach (var field in fields)
2559 if (field.IsSerialVersionUID)
2560 return true;
2561
2562 return false;
2563 }
2564 }
2565
2566 MethodBuilder GenerateConstructor(RuntimeJavaMethod mw)
2567 {
2568 return mw.GetDefineMethodHelper().DefineConstructor(wrapper, typeBuilder, GetMethodAccess(mw) | MethodAttributes.HideBySig);
2569 }
2570
2571 MethodBuilder GenerateMethod(int index, ClassFile.Method m, ref bool setModifiers)
2572 {
2573 var attribs = MethodAttributes.HideBySig;
2574 if (m.IsNative)
2575 {
2576 if (wrapper.IsPInvokeMethod(m))
2577 {
2578 // this doesn't appear to be necessary, but we use the flag in Finish to know
2579 // that we shouldn't emit a method body
2580 attribs |= MethodAttributes.PinvokeImpl;
2581 }
2582 else
2583 {
2584 setModifiers = true;
2585 }
2586 }
2587 if (methods[index].IsPropertyAccessor)
2588 {
2589 attribs |= GetPropertyAccess(methods[index]);
2590 attribs |= MethodAttributes.SpecialName;
2591 setModifiers = true;
2592 }
2593 else
2594 {
2595 attribs |= GetMethodAccess(methods[index]);
2596 }
2597
2598 if (m.IsAbstract || (!m.IsStatic && m.IsPublic && classFile.IsInterface))
2599 {
2600 // only if the classfile is abstract, we make the CLR method abstract, otherwise,
2601 // we have to generate a method that throws an AbstractMethodError (because the JVM
2602 // allows abstract methods in non-abstract classes)
2603 if (classFile.IsAbstract)
2604 {
2605 if (classFile.IsPublic && !classFile.IsFinal && !(m.IsPublic || m.IsProtected))
2606 {
2607 setModifiers = true;
2608 }
2609 else
2610 {
2611 if (!m.IsAbstract)
2612 {
2613 setModifiers = true;
2614 }
2615 attribs |= MethodAttributes.Abstract;
2616 }
2617 }
2618 else
2619 {
2620 setModifiers = true;
2621 }
2622 }
2623 if (m.IsFinal)
2624 {
2625 if (m.IsVirtual)
2626 {
2627 attribs |= MethodAttributes.Final;
2628 }
2629 else
2630 {
2631 setModifiers = true;
2632 }
2633 }
2634 if (m.IsStatic)
2635 {
2636 attribs |= MethodAttributes.Static;
2637 if (m.IsSynchronized)
2638 {
2639 setModifiers = true;
2640 }
2641 }
2642 else if (!m.IsPrivate)
2643 {
2644 attribs |= MethodAttributes.Virtual | MethodAttributes.CheckAccessOnOverride;
2645 }
2646 string name = UnicodeUtil.EscapeInvalidSurrogates(m.Name);
2647 if (!ReferenceEquals(name, m.Name))
2648 {
2649 // mark as specialname to remind us to unescape the name
2650 attribs |= MethodAttributes.SpecialName;
2651 }
2652#if IMPORTER
2653 if ((m.Modifiers & Modifiers.Bridge) != 0 && (m.IsPublic || m.IsProtected) && wrapper.IsPublic)
2654 {
2655 string sigbase = m.Signature.Substring(0, m.Signature.LastIndexOf(')') + 1);
2656 foreach (var mw in methods)
2657 {
2658 if (mw.Name == m.Name && mw.Signature.StartsWith(sigbase) && mw.Signature != m.Signature)
2659 {
2660 // To prevent bridge methods with covariant return types from confusing
2661 // other .NET compilers (like C#), we rename the bridge method.
2662 name = NamePrefix.Bridge + name;
2663 break;
2664 }
2665 }
2666 }
2667#endif
2668 if ((attribs & MethodAttributes.Virtual) != 0 && !classFile.IsInterface)
2669 {
2670 if (baseMethods[index] == null || (baseMethods[index].Length == 1 && baseMethods[index][0].DeclaringType.IsInterface))
2671 {
2672 // we need to set NewSlot here, to prevent accidentally overriding methods
2673 // (for example, if a Java class has a method "boolean Equals(object)", we don't want that method
2674 // to override System.Object.Equals)
2675 attribs |= MethodAttributes.NewSlot;
2676 }
2677 else
2678 {
2679 // if we have a method overriding a more accessible method (the JVM allows this), we need to make the
2680 // method more accessible, because otherwise the CLR will complain that we're reducing access
2681 bool hasPublicBaseMethod = false;
2682 foreach (RuntimeJavaMethod baseMethodWrapper in baseMethods[index])
2683 {
2684 MethodBase baseMethod = baseMethodWrapper.GetMethod();
2685 if ((baseMethod.IsPublic && !m.IsPublic) ||
2686 ((baseMethod.IsFamily || baseMethod.IsFamilyOrAssembly) && !m.IsPublic && !m.IsProtected) ||
2687 (!m.IsPublic && !m.IsProtected && !baseMethodWrapper.DeclaringType.IsPackageAccessibleFrom(wrapper)))
2688 {
2689 hasPublicBaseMethod |= baseMethod.IsPublic;
2690 attribs &= ~MethodAttributes.MemberAccessMask;
2691 attribs |= hasPublicBaseMethod ? MethodAttributes.Public : MethodAttributes.FamORAssem;
2692 setModifiers = true;
2693 }
2694 }
2695 }
2696 }
2697 MethodBuilder mb = null;
2698#if IMPORTER
2699 mb = wrapper.DefineGhostMethod(typeBuilder, name, attribs, methods[index]);
2700#endif
2701 if (mb == null)
2702 {
2703 bool needFinalize = false;
2704 bool needDispatch = false;
2705 MethodInfo baseFinalize = null;
2706 if (baseMethods[index] != null && ReferenceEquals(m.Name, StringConstants.FINALIZE) && ReferenceEquals(m.Signature, StringConstants.SIG_VOID))
2707 {
2708 baseFinalize = GetBaseFinalizeMethod(wrapper.BaseTypeWrapper);
2709 if (baseMethods[index][0].DeclaringType == wrapper.Context.JavaBase.TypeOfJavaLangObject)
2710 {
2711 // This type is the first type in the hierarchy to introduce a finalize method
2712 // (other than the one in java.lang.Object obviously), so we need to override
2713 // the real Finalize method and emit a dispatch call to our finalize method.
2714 needFinalize = true;
2715 needDispatch = true;
2716 }
2717 else if (m.IsFinal)
2718 {
2719 // One of our base classes already has a finalize method, so we already are
2720 // hooked into the real Finalize, but we need to override it again, to make it
2721 // final (so that non-Java types cannot override it either).
2722 needFinalize = true;
2723 needDispatch = false;
2724 // If the base class finalize was optimized away, we need a dispatch call after all.
2725 if (baseFinalize.DeclaringType == wrapper.Context.Types.Object)
2726 {
2727 needDispatch = true;
2728 }
2729 }
2730 else
2731 {
2732 // One of our base classes already has a finalize method, but it may have been an empty
2733 // method so that the hookup to the real Finalize was optimized away, we need to check
2734 // for that.
2735 if (baseFinalize.DeclaringType == wrapper.Context.Types.Object)
2736 {
2737 needFinalize = true;
2738 needDispatch = true;
2739 }
2740 }
2741 if (needFinalize &&
2742 !m.IsAbstract && !m.IsNative &&
2743 (!m.IsFinal || classFile.IsFinal) &&
2744 m.Instructions.Length > 0 &&
2745 m.Instructions[0].NormalizedOpCode == NormalizedByteCode.__return)
2746 {
2747 // we've got an empty finalize method, so we don't need to override the real finalizer
2748 // (not having a finalizer makes a huge perf difference)
2749 needFinalize = false;
2750 }
2751 }
2752 bool newslot = baseMethods[index] != null
2753 && (methods[index].IsExplicitOverride || baseMethods[index][0].RealName != name || CheckRequireOverrideStub(methods[index], baseMethods[index][0]))
2754 && !needFinalize;
2755 if (newslot)
2756 {
2757 attribs |= MethodAttributes.NewSlot;
2758 }
2759 if (classFile.IsInterface && !m.IsPublic && !wrapper.IsGhost)
2760 {
2761 var tb = typeBuilder;
2762 if (m.IsStatic)
2763 {
2764 mb = methods[index].GetDefineMethodHelper().DefineMethod(wrapper, tb, name, attribs);
2765 }
2766 else
2767 {
2768 // the CLR doesn't allow (non-virtual) instance methods in interfaces,
2769 // so we need to turn it into a static method
2770 mb = methods[index].GetDefineMethodHelper().DefineMethod(wrapper.ClassLoader.GetTypeWrapperFactory(),
2771 tb, NamePrefix.PrivateInterfaceInstanceMethod + name, attribs | MethodAttributes.Static | MethodAttributes.SpecialName,
2772 typeBuilder, false);
2773#if IMPORTER
2774 wrapper.Context.AttributeHelper.SetNameSig(mb, m.Name, m.Signature);
2775#endif
2776 }
2777 setModifiers = true;
2778 }
2779 else
2780 {
2781 mb = methods[index].GetDefineMethodHelper().DefineMethod(wrapper, typeBuilder, name, attribs);
2782 }
2783 if (baseMethods[index] != null && !needFinalize)
2784 {
2785 bool subsequent = false;
2786 foreach (RuntimeJavaMethod baseMethod in baseMethods[index])
2787 {
2788 if (CheckRequireOverrideStub(methods[index], baseMethod))
2789 {
2790 wrapper.GenerateOverrideStub(typeBuilder, baseMethod, mb, methods[index]);
2791 }
2792 else if (subsequent || methods[index].IsExplicitOverride || baseMethod.RealName != name)
2793 {
2794 typeBuilder.DefineMethodOverride(mb, (MethodInfo)baseMethod.GetMethod());
2795 }
2796
2797 // the non-primary base methods always need an explicit method override
2798 subsequent = true;
2799 }
2800 }
2801 // if we're overriding java.lang.Object.finalize we need to emit a stub to override System.Object.Finalize,
2802 // or if we're subclassing a non-Java class that has a Finalize method, we need a new Finalize override
2803 if (needFinalize)
2804 {
2805 var finalizeName = baseFinalize.Name;
2806 var mwClash = wrapper.GetMethod(finalizeName, StringConstants.SIG_VOID, true);
2807 if (mwClash != null && mwClash.GetMethod() != baseFinalize)
2808 finalizeName = "__<Finalize>";
2809
2810 var attr = MethodAttributes.HideBySig | MethodAttributes.Virtual;
2811 attr |= baseFinalize.IsPublic ? MethodAttributes.Public : MethodAttributes.Family;
2812 if (m.IsFinal)
2813 attr |= MethodAttributes.Final;
2814
2815 finalizeMethod = typeBuilder.DefineMethod(finalizeName, attr, CallingConventions.Standard, wrapper.Context.Types.Void, Type.EmptyTypes);
2816 if (finalizeName != baseFinalize.Name)
2817 typeBuilder.DefineMethodOverride(finalizeMethod, baseFinalize);
2818
2819 wrapper.Context.AttributeHelper.HideFromJava(finalizeMethod);
2820
2821 var ilgen = wrapper.Context.CodeEmitterFactory.Create(finalizeMethod);
2822 ilgen.EmitLdarg(0);
2823 ilgen.Emit(OpCodes.Call, wrapper.Context.ByteCodeHelperMethods.SkipFinalizerOf);
2824 var skip = ilgen.DefineLabel();
2825 ilgen.EmitBrtrue(skip);
2826
2827 if (needDispatch)
2828 {
2829 ilgen.BeginExceptionBlock();
2830 ilgen.Emit(OpCodes.Ldarg_0);
2831 ilgen.Emit(OpCodes.Callvirt, mb);
2832 ilgen.EmitLeave(skip);
2833 ilgen.BeginCatchBlock(wrapper.Context.Types.Object);
2834 ilgen.EmitLeave(skip);
2835 ilgen.EndExceptionBlock();
2836 }
2837 else
2838 {
2839 ilgen.Emit(OpCodes.Ldarg_0);
2840 ilgen.Emit(OpCodes.Call, baseFinalize);
2841 }
2842
2843 ilgen.MarkLabel(skip);
2844 ilgen.Emit(OpCodes.Ret);
2845 ilgen.DoEmit();
2846 }
2847#if IMPORTER
2848 if (classFile.Methods[index].AnnotationDefault != null)
2849 {
2850 var cab = new CustomAttributeBuilder(wrapper.Context.Resolver.ResolveRuntimeType("IKVM.Attributes.AnnotationDefaultAttribute").AsReflection().GetConstructor([wrapper.Context.Types.Object]), [AnnotationDefaultAttribute.Escape(classFile.Methods[index].AnnotationDefault)]);
2851 mb.SetCustomAttribute(cab);
2852 }
2853#endif
2854 }
2855
2856 // method is a synchronized method
2857 if ((methods[index].Modifiers & (Modifiers.Synchronized | Modifiers.Static)) == Modifiers.Synchronized)
2858 mb.SetImplementationFlags(mb.GetMethodImplementationFlags() | MethodImplAttributes.Synchronized);
2859
2860 // java method specifies to force inline, the best we can do is set aggressive inlining
2861 if (classFile.Methods[index].IsForceInline)
2862 mb.SetImplementationFlags(mb.GetMethodImplementationFlags() | MethodImplAttributes.AggressiveInlining);
2863
2864 if (classFile.Methods[index].IsLambdaFormCompiled || classFile.Methods[index].IsLambdaFormHidden)
2865 {
2866 var flags = HideFromJavaFlags.None;
2867 if (classFile.Methods[index].IsLambdaFormCompiled)
2868 flags |= HideFromJavaFlags.StackWalk;
2869 if (classFile.Methods[index].IsLambdaFormHidden)
2870 flags |= HideFromJavaFlags.StackTrace;
2871
2872 wrapper.Context.AttributeHelper.HideFromJava(mb, flags);
2873 }
2874
2875 if (classFile.IsInterface && methods[index].IsVirtual && !methods[index].IsAbstract)
2876 {
2877 if (wrapper.IsGhost)
2878 {
2879 RuntimeDefaultInterfaceJavaMethod.SetImpl(methods[index], methods[index].GetDefineMethodHelper().DefineMethod(wrapper.ClassLoader.GetTypeWrapperFactory(),
2880 typeBuilder, NamePrefix.DefaultMethod + mb.Name, MethodAttributes.Public | MethodAttributes.SpecialName,
2881 null, false));
2882 }
2883 else
2884 {
2885 RuntimeDefaultInterfaceJavaMethod.SetImpl(methods[index], methods[index].GetDefineMethodHelper().DefineMethod(wrapper.ClassLoader.GetTypeWrapperFactory(),
2886 typeBuilder, NamePrefix.DefaultMethod + mb.Name, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName,
2887 typeBuilder, false));
2888 }
2889 }
2890
2891 return mb;
2892 }
2893
2894 private MethodAttributes GetMethodAccess(RuntimeJavaMethod mw)
2895 {
2896 switch (mw.Modifiers & Modifiers.AccessMask)
2897 {
2898 case Modifiers.Private:
2899 // Java nestmates may call one another's private methods and
2900 // constructors. The CLR has no corresponding access rule,
2901 // so retain the Java modifier as metadata while exposing the
2902 // emitted member to the converted assembly.
2903 return HasNestmates() ? MethodAttributes.Assembly : MethodAttributes.Private;
2904 case Modifiers.Protected:
2905 return MethodAttributes.FamORAssem;
2906 case Modifiers.Public:
2907 return MethodAttributes.Public;
2908 default:
2909 return MethodAttributes.Assembly;
2910 }
2911 }
2912
2913#if IMPORTER
2914 // The classic example of an access bridge is StringBuilder.length(), the JDK 6 compiler
2915 // generates this to work around a reflection problem (which otherwise wouldn't surface the
2916 // length() method, because it is defined in the non-public base class AbstractStringBuilder.)
2917 private static bool IsAccessBridge(ClassFile classFile, ClassFile.Method m)
2918 {
2919 // HACK this is a pretty gross hack
2920 // We look at the method body to figure out if the bridge method calls another method with the exact
2921 // same name/signature and if that is the case, we assume that it is an access bridge.
2922 // This code is based on the javac algorithm in addBridgeIfNeeded(...) in com/sun/tools/javac/comp/TransTypes.java.
2923 if ((m.Modifiers & (Modifiers.Abstract | Modifiers.Native | Modifiers.Public | Modifiers.Bridge)) == (Modifiers.Public | Modifiers.Bridge))
2924 {
2925 foreach (ClassFile.Method.Instruction instr in m.Instructions)
2926 {
2927 if (instr.NormalizedOpCode == NormalizedByteCode.__invokespecial)
2928 {
2929 ClassFile.ConstantPoolItemMI cpi = classFile.SafeGetMethodref(instr.Arg1);
2930 return cpi != null && cpi.Name == m.Name && cpi.Signature == m.Signature;
2931 }
2932 }
2933 }
2934 return false;
2935 }
2936#endif // IMPORTER
2937
2938 internal override Type Type
2939 {
2940 get
2941 {
2942 return typeBuilder;
2943 }
2944 }
2945
2946 internal override string GetGenericSignature()
2947 {
2948 Debug.Fail("Unreachable code");
2949 return null;
2950 }
2951
2952 internal override string[] GetEnclosingMethod()
2953 {
2954 Debug.Fail("Unreachable code");
2955 return null;
2956 }
2957
2958 internal override string GetGenericMethodSignature(int index)
2959 {
2960 Debug.Fail("Unreachable code");
2961 return null;
2962 }
2963
2964 internal override string GetGenericFieldSignature(int index)
2965 {
2966 Debug.Fail("Unreachable code");
2967 return null;
2968 }
2969
2970 internal override object[] GetDeclaredAnnotations()
2971 {
2972 Debug.Fail("Unreachable code");
2973 return null;
2974 }
2975
2976 internal override object GetMethodDefaultValue(int index)
2977 {
2978 Debug.Fail("Unreachable code");
2979 return null;
2980 }
2981
2982 internal override object[] GetMethodAnnotations(int index)
2983 {
2984 Debug.Fail("Unreachable code");
2985 return null;
2986 }
2987
2988 internal override object[][] GetParameterAnnotations(int index)
2989 {
2990 Debug.Fail("Unreachable code");
2991 return null;
2992 }
2993
2994 internal override MethodParametersEntry[] GetMethodParameters(int index)
2995 {
2996 Debug.Fail("Unreachable code");
2997 return null;
2998 }
2999
3000 internal override object[] GetFieldAnnotations(int index)
3001 {
3002 Debug.Fail("Unreachable code");
3003 return null;
3004 }
3005
3006 internal override MethodInfo GetFinalizeMethod()
3007 {
3008 return finalizeMethod;
3009 }
3010
3011 internal override object[] GetConstantPool()
3012 {
3013 Debug.Fail("Unreachable code");
3014 return null;
3015 }
3016
3017 internal override byte[] GetRawTypeAnnotations()
3018 {
3019 Debug.Fail("Unreachable code");
3020 return null;
3021 }
3022
3023 internal override byte[] GetMethodRawTypeAnnotations(int index)
3024 {
3025 Debug.Fail("Unreachable code");
3026 return null;
3027 }
3028
3029 internal override byte[] GetFieldRawTypeAnnotations(int index)
3030 {
3031 Debug.Fail("Unreachable code");
3032 return null;
3033 }
3034
3035 internal override RuntimeJavaType Host
3036 {
3037 get { return host; }
3038 }
3039
3040 }
3041
3042 }
3043
3044}
IKVM.Reflection.Type Type
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.FieldInfo FieldInfo
IKVM.Reflection.MethodInfo MethodInfo
IKVM.Reflection.MethodBase MethodBase
global::java.lang.invoke.LambdaForm.Name Name
IKVM.Runtime.RuntimeByteCodeJavaType RuntimeDynamicOrImportJavaType
Implementation of RuntimeClassLoader that emits loaded Java types to an AssemblyBuilder.
Implementation of RuntimeByteCodeJavaType that customizes output for the importer.
MemberFlags
Describes various options applied to a member.