IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
RuntimeManagedByteCodeJavaType.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;
27
29using IKVM.Attributes;
31using IKVM.ByteCode;
32using System.Text;
33
34
35#if IMPORTER || EXPORTER
36using IKVM.Reflection;
38
39using Type = IKVM.Reflection.Type;
40#else
41using System.Reflection;
42using System.Reflection.Emit;
43#endif
44
45#if IMPORTER
47#endif
48
49namespace IKVM.Runtime
50{
51
53 {
54
55 readonly RuntimeContext context;
56
62 {
63 this.context = context ?? throw new ArgumentNullException(nameof(context));
64 }
65
73 {
74 // TODO since ghost and remapped types can only exist in the core library assembly, we probably
75 // should be able to remove the Type.IsDefined() tests in most cases
76 if (type.IsValueType && context.AttributeHelper.IsGhostInterface(type))
77 {
78 return new RuntimeManagedByteCodeJavaType.GhostJavaType(context, name, type);
79 }
80 else if (context.AttributeHelper.IsRemappedType(type))
81 {
82 return new RuntimeManagedByteCodeJavaType.RemappedJavaType(context, name, type);
83 }
84 else
85 {
86 return new RuntimeManagedByteCodeJavaType(context, name, type);
87 }
88 }
89
90 }
91
95 internal partial class RuntimeManagedByteCodeJavaType : RuntimeJavaType
96 {
97
98 readonly Type type;
99
100 RuntimeJavaType baseTypeWrapper;
101 volatile RuntimeJavaType[] interfaces;
102 MethodInfo clinitMethod;
103 volatile bool clinitMethodSet;
104 Modifiers reflectiveModifiers;
105
112 internal static JavaTypeName? GetName(RuntimeContext context, Type type)
113 {
114 if (type.HasElementType)
115 return null;
116 if (type.IsGenericType)
117 return null;
118 if (context.AttributeHelper.IsJavaModule(type.Module) == false)
119 return null;
120
121 // look for our custom attribute, that contains the real name of the type (for inner classes)
122 var attr = context.AttributeHelper.GetInnerClass(type);
123 if (attr != null)
124 {
125 var name = attr.InnerClassName;
126 if (name != null)
127 return name;
128 }
129
130 // type is an inner type
131 if (type.DeclaringType != null)
132 return GetName(context, type.DeclaringType) + "$" + TypeNameUtil.Unescape(type.Name);
133
134 return TypeNameUtil.Unescape(type.FullName);
135 }
136
137 static RuntimeJavaType GetBaseTypeWrapper(RuntimeContext context, Type type)
138 {
139 if (type.IsInterface || context.AttributeHelper.IsGhostInterface(type))
140 {
141 return null;
142 }
143 else if (type.BaseType == null)
144 {
145 // System.Object must appear to be derived from java.lang.Object
146 return context.JavaBase.TypeOfJavaLangObject;
147 }
148 else
149 {
150 var attr = context.AttributeHelper.GetRemappedType(type);
151 if (attr != null)
152 {
153 if (attr.Type == context.Types.Object)
154 return null;
155 else
156 return context.JavaBase.TypeOfJavaLangObject;
157 }
158 else if (context.ClassLoaderFactory.IsRemappedType(type.BaseType))
159 {
160 // if we directly extend System.Object or System.Exception, the base class must be cli.System.Object or cli.System.Exception
161 return context.ManagedJavaTypeFactory.GetJavaTypeFromManagedType(type.BaseType);
162 }
163
164 RuntimeJavaType tw = null;
165 while (tw == null)
166 {
167 type = type.BaseType;
168 tw = context.ClassLoaderFactory.GetJavaTypeFromType(type);
169 }
170
171 return tw;
172 }
173 }
174
181 public RuntimeManagedByteCodeJavaType(RuntimeContext context, ExModifiers exmod, string name) :
182 base(context, exmod.IsInternal ? TypeFlags.InternalAccess : TypeFlags.None, exmod.Modifiers, name)
183 {
184 baseTypeWrapper = context.VerifierJavaTypeFactory.Null;
185 }
186
193 public RuntimeManagedByteCodeJavaType(RuntimeContext context, string name, Type type) :
194 this(context, GetModifiers(context, type), name)
195 {
196 Debug.Assert(!(type is TypeBuilder));
197 Debug.Assert(!type.Name.EndsWith("[]"));
198
199 this.type = type;
200 }
201
202 internal override RuntimeJavaType BaseTypeWrapper
203 {
204 get
205 {
206 if (baseTypeWrapper != Context.VerifierJavaTypeFactory.Null)
207 return baseTypeWrapper;
208
209 return baseTypeWrapper = GetBaseTypeWrapper(Context, type);
210 }
211 }
212
213 internal override RuntimeClassLoader ClassLoader => Context.AssemblyClassLoaderFactory.FromAssembly(type.Assembly);
214
215 static ExModifiers GetModifiers(RuntimeContext context, Type type)
216 {
217 ModifiersAttribute attr = context.AttributeHelper.GetModifiersAttribute(type);
218 if (attr != null)
219 {
220 return new ExModifiers(attr.Modifiers, attr.IsInternal);
221 }
222 // only returns public, protected, private, final, static, abstract and interface (as per
223 // the documentation of Class.getModifiers())
224 Modifiers modifiers = 0;
225 if (type.IsPublic || type.IsNestedPublic)
226 {
227 modifiers |= Modifiers.Public;
228 }
229 if (type.IsSealed)
230 {
231 modifiers |= Modifiers.Final;
232 }
233 if (type.IsAbstract)
234 {
235 modifiers |= Modifiers.Abstract;
236 }
237 if (type.IsInterface)
238 {
239 modifiers |= Modifiers.Interface;
240 }
241 else
242 {
243 modifiers |= Modifiers.Super;
244 }
245
246 return new ExModifiers(modifiers, false);
247 }
248
249 internal override bool HasStaticInitializer
250 {
251 get
252 {
253 if (!clinitMethodSet)
254 {
255 try
256 {
257 clinitMethod = type.GetMethod("__<clinit>", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
258 }
259#if IMPORTER
261#endif
262 finally { }
263 clinitMethodSet = true;
264 }
265 return clinitMethod != null;
266 }
267 }
268
269 internal override RuntimeJavaType[] Interfaces
270 {
271 get
272 {
273 if (interfaces == null)
274 {
275 interfaces = GetInterfaces();
276 }
277 return interfaces;
278 }
279 }
280
281 private RuntimeJavaType[] GetInterfaces()
282 {
283 // NOTE instead of getting the interfaces list from Type, we use a custom
284 // attribute to list the implemented interfaces, because Java reflection only
285 // reports the interfaces *directly* implemented by the type, not the inherited
286 // interfaces. This is significant for serialVersionUID calculation (for example).
287 var attr = Context.AttributeHelper.GetImplements(type);
288 if (attr == null)
289 {
290 if (BaseTypeWrapper == Context.JavaBase.TypeOfJavaLangObject)
291 return GetImplementedInterfacesAsTypeWrappers(Context, type);
292
293 return Array.Empty<RuntimeJavaType>();
294 }
295
296 var interfaceNames = attr.Interfaces;
297 var interfaceWrappers = new RuntimeJavaType[interfaceNames.Length];
298 if (IsRemapped)
299 {
300 for (int i = 0; i < interfaceWrappers.Length; i++)
301 interfaceWrappers[i] = Context.ClassLoaderFactory.LoadClassCritical(interfaceNames[i]);
302 }
303 else
304 {
305 var typeWrappers = GetImplementedInterfacesAsTypeWrappers(Context, type);
306 for (int i = 0; i < interfaceWrappers.Length; i++)
307 {
308 for (int j = 0; j < typeWrappers.Length; j++)
309 {
310 if (typeWrappers[j].Name == interfaceNames[i])
311 {
312 interfaceWrappers[i] = typeWrappers[j];
313 break;
314 }
315 }
316
317 if (interfaceWrappers[i] == null)
318 {
319#if IMPORTER
320 throw new FatalCompilerErrorException(DiagnosticEvent.UnableToResolveInterface(interfaceNames[i], ToString()));
321#else
322 throw new InternalException($"Unable to resolve interface {interfaceNames[i]} on type {this}");
323#endif
324 }
325 }
326 }
327
328 return interfaceWrappers;
329 }
330
331 private bool IsNestedTypeAnonymousOrLocalClass(Type type)
332 {
333 switch (type.Attributes & (TypeAttributes.SpecialName | TypeAttributes.VisibilityMask))
334 {
335 case TypeAttributes.SpecialName | TypeAttributes.NestedPublic:
336 case TypeAttributes.SpecialName | TypeAttributes.NestedAssembly:
337 return Context.AttributeHelper.HasEnclosingMethodAttribute(type);
338 default:
339 return false;
340 }
341 }
342
343 private bool IsAnnotationAttribute(Type type)
344 {
345 return type.Name.EndsWith("Attribute", StringComparison.Ordinal) && type.IsClass && type.BaseType.FullName == "ikvm.internal.AnnotationAttributeBase";
346 }
347
348 internal override RuntimeJavaType[] InnerClasses
349 {
350 get
351 {
352 var wrappers = new List<RuntimeJavaType>();
353 foreach (var nested in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
354 {
355 if (IsAnnotationAttribute(nested))
356 {
357 // HACK it's the custom attribute we generated for a corresponding annotation, so we shouldn't surface it as an inner classes
358 // (we can't put a HideFromJavaAttribute on it, because we do want the class to be visible as a $Proxy)
359 }
360 else if (IsNestedTypeAnonymousOrLocalClass(nested))
361 {
362 // anonymous and local classes are not reported as inner classes
363 }
364 else if (Context.AttributeHelper.IsHideFromJava(nested))
365 {
366 // ignore
367 }
368 else
369 {
370 wrappers.Add(Context.ClassLoaderFactory.GetJavaTypeFromType(nested));
371 }
372 }
373 foreach (string s in Context.AttributeHelper.GetNonNestedInnerClasses(type))
374 {
375 wrappers.Add(ClassLoader.LoadClassByName(s));
376 }
377
378 return wrappers.ToArray();
379 }
380 }
381
382 internal override RuntimeJavaType DeclaringTypeWrapper
383 {
384 get
385 {
386 if (IsNestedTypeAnonymousOrLocalClass(type))
387 {
388 return null;
389 }
390 Type declaringType = type.DeclaringType;
391 if (declaringType != null)
392 {
393 return Context.ClassLoaderFactory.GetJavaTypeFromType(declaringType);
394 }
395 string decl = Context.AttributeHelper.GetNonNestedOuterClasses(type);
396 if (decl != null)
397 {
398 return ClassLoader.LoadClassByName(decl);
399 }
400
401 return null;
402 }
403 }
404
405 // returns true iff name is of the form "...$<n>"
406 private static bool IsAnonymousClassName(string name)
407 {
408 int index = name.LastIndexOf('$') + 1;
409 if (index > 1 && index < name.Length)
410 {
411 while (index < name.Length)
412 {
413 if ("0123456789".IndexOf(name[index++]) == -1)
414 {
415 return false;
416 }
417 }
418 return true;
419 }
420 return false;
421 }
422
423 // This method uses some heuristics to predict the reflective modifiers and if the prediction matches
424 // we can avoid storing the InnerClassesAttribute to record the modifiers.
425 // The heuristics are based on javac from Java 7.
426 internal static Modifiers PredictReflectiveModifiers(RuntimeJavaType tw)
427 {
428 Modifiers modifiers = Modifiers.Static | (tw.Modifiers & (Modifiers.Public | Modifiers.Abstract | Modifiers.Interface));
429 // javac marks anonymous classes as final, but the InnerClasses attribute access_flags does not have the ACC_FINAL flag set
430 if (tw.IsFinal && !IsAnonymousClassName(tw.Name))
431 {
432 modifiers |= Modifiers.Final;
433 }
434 // javac uses the this$0 field to store the outer instance reference for non-static inner classes
435 foreach (RuntimeJavaField fw in tw.GetFields())
436 {
437 if (fw.Name == "this$0")
438 {
439 modifiers &= ~Modifiers.Static;
440 break;
441 }
442 }
443 return modifiers;
444 }
445
446 internal override Modifiers ReflectiveModifiers
447 {
448 get
449 {
450 if (reflectiveModifiers == 0)
451 {
452 Modifiers mods;
453 InnerClassAttribute attr = Context.AttributeHelper.GetInnerClass(type);
454 if (attr != null)
455 {
456 // the mask comes from RECOGNIZED_INNER_CLASS_MODIFIERS in src/hotspot/share/vm/classfile/classFileParser.cpp
457 // (minus ACC_SUPER)
458 mods = attr.Modifiers & (Modifiers)0x761F;
459 }
460 else if (type.DeclaringType != null)
461 {
462 mods = PredictReflectiveModifiers(this);
463 }
464 else
465 {
466 // the mask comes from JVM_RECOGNIZED_CLASS_MODIFIERS in src/hotspot/share/vm/prims/jvm.h
467 // (minus ACC_SUPER)
468 mods = Modifiers & (Modifiers)0x7611;
469 }
470 if (IsInterface)
471 {
472 mods |= Modifiers.Abstract;
473 }
474 reflectiveModifiers = mods;
475 }
476 return reflectiveModifiers;
477 }
478 }
479
480 internal override Type TypeAsBaseType
481 {
482 get
483 {
484 return type;
485 }
486 }
487
488 private void SigTypePatchUp(string sigtype, ref RuntimeJavaType type)
489 {
490 if (sigtype != type.SigName)
491 {
492 // if type is an array, we know that it is a ghost array, because arrays of unloadable are compiled
493 // as object (not as arrays of object)
494 if (type.IsArray)
495 {
496 type = ClassLoader.FieldTypeWrapperFromSig(sigtype, LoadMode.LoadOrThrow);
497 }
498 else if (type.IsPrimitive)
499 {
500 type = Context.ManagedJavaTypeFactory.GetJavaTypeFromManagedType(type.TypeAsTBD);
501 if (sigtype != type.SigName)
502 {
503 throw new InvalidOperationException();
504 }
505 }
506 else if (type.IsNonPrimitiveValueType)
507 {
508 // this can't happen and even if it does happen we cannot return
509 // UnloadableTypeWrapper because that would result in incorrect code
510 // being generated
511 throw new InvalidOperationException();
512 }
513 else
514 {
515 if (sigtype[0] == 'L')
516 {
517 sigtype = sigtype.Substring(1, sigtype.Length - 2);
518 }
519 try
520 {
521 RuntimeJavaType tw = ClassLoader.TryLoadClassByName(sigtype);
522 if (tw != null && tw.IsRemapped)
523 {
524 type = tw;
525 return;
526 }
527 }
529 {
530 }
531 type = new RuntimeUnloadableJavaType(Context, sigtype);
532 }
533 }
534 }
535
536 private static void ParseSig(string sig, out string[] sigparam, out string sigret)
537 {
538 List<string> list = new List<string>();
539 int pos = 1;
540 for (; ; )
541 {
542 switch (sig[pos])
543 {
544 case 'L':
545 {
546 int end = sig.IndexOf(';', pos) + 1;
547 list.Add(sig.Substring(pos, end - pos));
548 pos = end;
549 break;
550 }
551 case '[':
552 {
553 int skip = 1;
554 while (sig[pos + skip] == '[') skip++;
555 if (sig[pos + skip] == 'L')
556 {
557 int end = sig.IndexOf(';', pos) + 1;
558 list.Add(sig.Substring(pos, end - pos));
559 pos = end;
560 }
561 else
562 {
563 skip++;
564 list.Add(sig.Substring(pos, skip));
565 pos += skip;
566 }
567 break;
568 }
569 case ')':
570 sigparam = list.ToArray();
571 sigret = sig.Substring(pos + 1);
572 return;
573 default:
574 list.Add(sig.Substring(pos, 1));
575 pos++;
576 break;
577 }
578 }
579 }
580
581 private static bool IsCallerID(RuntimeContext context, Type type)
582 {
583#if EXPORTER
584 return type.FullName == "ikvm.internal.CallerID";
585#else
586 return type == context.JavaBase.TypeOfIkvmInternalCallerID.TypeAsSignatureType;
587#endif
588 }
589
590 private static bool IsCallerSensitive(MethodBase mb)
591 {
592#if FIRST_PASS
593 return false;
594#elif IMPORTER || EXPORTER
595 foreach (CustomAttributeData cad in mb.GetCustomAttributesData())
596 {
597 if (cad.AttributeType.FullName == "sun.reflect.CallerSensitiveAttribute")
598 {
599 return true;
600 }
601 }
602 return false;
603#else
604 return mb.IsDefined(typeof(global::sun.reflect.CallerSensitiveAttribute), false);
605#endif
606 }
607
608 void GetNameSigFromMethodBase(MethodBase method, out string name, out string sig, out RuntimeJavaType retType, out RuntimeJavaType[] paramTypes, ref MemberFlags flags)
609 {
610 retType = method is ConstructorInfo ? Context.PrimitiveJavaTypeFactory.VOID : GetParameterTypeWrapper(Context, ((MethodInfo)method).ReturnParameter);
611 var parameters = method.GetParameters();
612 int len = parameters.Length;
613 if (len > 0 && IsCallerID(Context, parameters[len - 1].ParameterType) && ClassLoader == Context.ClassLoaderFactory.GetBootstrapClassLoader() && IsCallerSensitive(method))
614 {
615 len--;
616 flags |= MemberFlags.CallerID;
617 }
618 paramTypes = new RuntimeJavaType[len];
619 for (int i = 0; i < len; i++)
620 paramTypes[i] = GetParameterTypeWrapper(Context, parameters[i]);
621
622 var attr = Context.AttributeHelper.GetNameSig(method);
623 if (attr != null)
624 {
625 name = attr.Name;
626 sig = attr.Sig;
627 ParseSig(sig, out var sigparams, out var sigret);
628 // HACK newhelper methods have a return type, but it should be void
629 if (name == "<init>")
630 retType = Context.PrimitiveJavaTypeFactory.VOID;
631 SigTypePatchUp(sigret, ref retType);
632 // if we have a remapped method, the paramTypes array contains an additional entry for "this" so we have
633 // to remove that
634 if (paramTypes.Length == sigparams.Length + 1)
635 paramTypes = ArrayUtil.DropFirst(paramTypes);
636
637 Debug.Assert(sigparams.Length == paramTypes.Length);
638 for (int i = 0; i < sigparams.Length; i++)
639 SigTypePatchUp(sigparams[i], ref paramTypes[i]);
640 }
641 else
642 {
643 if (method is ConstructorInfo)
644 {
645 name = method.IsStatic ? "<clinit>" : "<init>";
646 }
647 else
648 {
649 name = method.Name;
650 if (name.StartsWith(NamePrefix.Bridge, StringComparison.Ordinal))
651 name = name.Substring(NamePrefix.Bridge.Length);
652 if (method.IsSpecialName)
653 name = UnicodeUtil.UnescapeInvalidSurrogates(name);
654 }
655
656 if (method.IsSpecialName && method.Name.StartsWith(NamePrefix.DefaultMethod, StringComparison.Ordinal))
657 paramTypes = ArrayUtil.DropFirst(paramTypes);
658
659 var sb = new ValueStringBuilder();
660 sb.Append("(");
661 foreach (var tw in paramTypes)
662 sb.Append(tw.SigName);
663 sb.Append(")");
664 sb.Append(retType.SigName);
665 sig = sb.ToString();
666 }
667 }
668
669 protected override void LazyPublishMethods()
670 {
671 const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
672
673 var isDelegate = type.BaseType == Context.Types.MulticastDelegate;
674 var methods = new List<RuntimeJavaMethod>();
675
676 foreach (var ctor in type.GetConstructors(flags))
677 {
678 var hideFromJavaFlags = Context.AttributeHelper.GetHideFromJavaFlags(ctor);
679 if (isDelegate && !ctor.IsStatic && (hideFromJavaFlags & HideFromJavaFlags.Code) == 0)
680 methods.Add(new DelegateConstructorJavaMethod(this, ctor));
681 else
682 AddMethodOrConstructor(ctor, hideFromJavaFlags, methods);
683 }
684
685 AddMethods(type.GetMethods(flags), methods);
686
687 if (type.IsInterface && (type.IsPublic || type.IsNestedPublic))
688 {
689 var privateInterfaceMethods = type.GetNestedType(NestedTypeName.PrivateInterfaceMethods, BindingFlags.NonPublic);
690 if (privateInterfaceMethods != null)
691 AddMethods(privateInterfaceMethods.GetMethods(flags), methods);
692 }
693
694 SetMethods(methods.ToArray());
695 }
696
697 private void AddMethods(MethodInfo[] add, List<RuntimeJavaMethod> methods)
698 {
699 foreach (var method in add)
700 AddMethodOrConstructor(method, Context.AttributeHelper.GetHideFromJavaFlags(method), methods);
701 }
702
703 private void AddMethodOrConstructor(MethodBase method, HideFromJavaFlags hideFromJavaFlags, List<RuntimeJavaMethod> methods)
704 {
705 if ((hideFromJavaFlags & HideFromJavaFlags.Code) != 0)
706 {
707 if (method.Name.StartsWith(NamePrefix.Incomplete, StringComparison.Ordinal))
708 {
709 SetHasIncompleteInterfaceImplementation();
710 }
711 }
712 else
713 {
714 if (method.IsSpecialName && (method.Name.StartsWith("__<", StringComparison.Ordinal) || method.Name.StartsWith(NamePrefix.DefaultMethod, StringComparison.Ordinal)))
715 {
716 // skip
717 }
718 else
719 {
720 var mi = method as MethodInfo;
721 var hideFromReflection = mi != null && (hideFromJavaFlags & HideFromJavaFlags.Reflection) != 0;
722 var flags = hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None;
723 GetNameSigFromMethodBase(method, out var name, out var sig, out var retType, out var paramTypes, ref flags);
724 var mods = Context.AttributeHelper.GetModifiers(method, false);
725 if (mods.IsInternal)
726 {
727 flags |= MemberFlags.InternalAccess;
728 }
729 if (hideFromReflection && name.StartsWith(NamePrefix.AccessStub, StringComparison.Ordinal))
730 {
731 int id = Int32.Parse(name.Substring(NamePrefix.AccessStub.Length, name.IndexOf('|', NamePrefix.AccessStub.Length) - NamePrefix.AccessStub.Length));
732 name = name.Substring(name.IndexOf('|', NamePrefix.AccessStub.Length) + 1);
733 flags |= MemberFlags.AccessStub;
734 MethodInfo nonvirt = type.GetMethod(NamePrefix.NonVirtual + id, BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance);
735 methods.Add(new RuntimeAccessStubJavaMethod(this, name, sig, mi, mi, nonvirt ?? mi, retType, paramTypes, mods.Modifiers & ~Modifiers.Final, flags));
736 return;
737 }
738
739 MethodInfo impl;
741 if (IsGhost && (mods.Modifiers & (Modifiers.Static | Modifiers.Private)) == 0)
742 {
743 var types = new Type[paramTypes.Length];
744 for (int i = 0; i < types.Length; i++)
745 types[i] = paramTypes[i].TypeAsSignatureType;
746
747 var ifmethod = TypeAsBaseType.GetMethod(method.Name, types);
748 mw = new RuntimeGhostJavaMethod(this, name, sig, ifmethod, (MethodInfo)method, retType, paramTypes, mods.Modifiers, flags);
749 if (!mw.IsAbstract)
750 ((RuntimeGhostJavaMethod)mw).SetDefaultImpl(TypeAsSignatureType.GetMethod(NamePrefix.DefaultMethod + method.Name, types));
751 }
752 else if (method.IsSpecialName && method.Name.StartsWith(NamePrefix.PrivateInterfaceInstanceMethod, StringComparison.Ordinal))
753 {
754 mw = new RuntimePrivateInterfaceJavaMethod(this, name, sig, method, retType, paramTypes, mods.Modifiers, flags);
755 }
756 else if (IsInterface && method.IsAbstract && (mods.Modifiers & Modifiers.Abstract) == 0 && (impl = GetDefaultInterfaceMethodImpl(mi, sig)) != null)
757 {
758 mw = new RuntimeDefaultInterfaceJavaMethod(this, name, sig, mi, impl, retType, paramTypes, mods.Modifiers, flags);
759 }
760 else
761 {
762 mw = new RuntimeTypicalJavaMethod(this, name, sig, method, retType, paramTypes, mods.Modifiers, flags);
763 }
764 if (mw.HasNonPublicTypeInSignature)
765 {
766 if (mi != null)
767 {
768 MethodInfo stubVirt;
769 MethodInfo stubNonVirt;
770 if (GetType2AccessStubs(name, sig, out stubVirt, out stubNonVirt))
771 {
772 mw = new RuntimeAccessStubJavaMethod(this, name, sig, mi, stubVirt, stubNonVirt ?? stubVirt, retType, paramTypes, mw.Modifiers, flags);
773 }
774 }
775 else
776 {
777 ConstructorInfo stub;
778 if (GetType2AccessStub(sig, out stub))
779 {
780 mw = new RuntimeConstructorAccessStubJavaMethod(this, sig, (ConstructorInfo)method, stub, paramTypes, mw.Modifiers, flags);
781 }
782 }
783 }
784 methods.Add(mw);
785 }
786 }
787 }
788
789 MethodInfo GetDefaultInterfaceMethodImpl(MethodInfo method, string expectedSig)
790 {
791 foreach (MethodInfo candidate in method.DeclaringType.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly))
792 {
793 if (candidate.IsSpecialName
794 && candidate.Name.StartsWith(NamePrefix.DefaultMethod, StringComparison.Ordinal)
795 && candidate.Name.Length == method.Name.Length + NamePrefix.DefaultMethod.Length
796 && candidate.Name.EndsWith(method.Name, StringComparison.Ordinal))
797 {
798 string name;
799 string sig;
800 RuntimeJavaType retType;
801 RuntimeJavaType[] paramTypes;
802 MemberFlags flags = MemberFlags.None;
803 GetNameSigFromMethodBase(candidate, out name, out sig, out retType, out paramTypes, ref flags);
804 if (sig == expectedSig)
805 {
806 return candidate;
807 }
808 }
809 }
810 return null;
811 }
812
813 bool GetType2AccessStubs(string name, string sig, out MethodInfo stubVirt, out MethodInfo stubNonVirt)
814 {
815 const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
816
817 stubVirt = null;
818 stubNonVirt = null;
819 foreach (var method in type.GetMethods(flags))
820 {
821 if (Context.AttributeHelper.IsHideFromJava(method))
822 {
823 var attr = Context.AttributeHelper.GetNameSig(method);
824 if (attr != null && attr.Name == name && attr.Sig == sig)
825 {
826 if (method.Name.StartsWith(NamePrefix.NonVirtual, StringComparison.Ordinal))
827 {
828 stubNonVirt = method;
829 }
830 else
831 {
832 stubVirt = method;
833 }
834 }
835 }
836 }
837
838 return stubVirt != null;
839 }
840
841 bool GetType2AccessStub(string sig, out ConstructorInfo stub)
842 {
843 const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
844
845 stub = null;
846 foreach (var ctor in type.GetConstructors(flags))
847 {
848 if (Context.AttributeHelper.IsHideFromJava(ctor))
849 {
850 var attr = Context.AttributeHelper.GetNameSig(ctor);
851 if (attr != null && attr.Sig == sig)
852 {
853 stub = ctor;
854 }
855 }
856 }
857
858 return stub != null;
859 }
860
861 static int SortFieldByToken(FieldInfo field1, FieldInfo field2)
862 {
863 return field1.MetadataToken.CompareTo(field2.MetadataToken);
864 }
865
866 protected override void LazyPublishFields()
867 {
868 const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
869
870 var fields = new List<RuntimeJavaField>();
871 var rawfields = type.GetFields(flags);
872 Array.Sort(rawfields, SortFieldByToken);
873
874 // FXBUG on .NET 3.5 and Mono Type.GetProperties() will not return "duplicate" properties (i.e. that have the same name and type, but differ in custom modifiers).
875 // .NET 4.0 works as expected. We don't have a workaround, because that would require name mangling again and this situation is very unlikely anyway.
876 var properties = type.GetProperties(flags);
877 foreach (var field in rawfields)
878 {
879 var hideFromJavaFlags = Context.AttributeHelper.GetHideFromJavaFlags(field);
880 if ((hideFromJavaFlags & HideFromJavaFlags.Code) != 0)
881 {
882 if (field.Name.StartsWith(NamePrefix.Type2AccessStubBackingField, StringComparison.Ordinal))
883 {
884 var tw = GetFieldTypeWrapper(Context, field);
885 var name = field.Name.Substring(NamePrefix.Type2AccessStubBackingField.Length);
886 for (int i = 0; i < properties.Length; i++)
887 {
888 if (properties[i] != null && name == properties[i].Name && MatchTypes(tw, GetPropertyTypeWrapper(properties[i])))
889 {
890 fields.Add(new RuntimeManagedByteCodeAccessStubJavaField(this, properties[i], field, tw));
891 properties[i] = null;
892 break;
893 }
894 }
895 }
896 }
897 else
898 {
899 if (field.IsSpecialName && field.Name.StartsWith("__<", StringComparison.Ordinal))
900 {
901 // skip
902 }
903 else
904 {
905 fields.Add(CreateFieldWrapper(field, hideFromJavaFlags));
906 }
907 }
908 }
909
910 foreach (var property in properties)
911 if (property != null)
912 AddPropertyFieldWrapper(fields, property, null);
913
914 SetFields(fields.ToArray());
915 }
916
917 static bool MatchTypes(RuntimeJavaType tw1, RuntimeJavaType tw2)
918 {
919 return tw1 == tw2 || (tw1.IsUnloadable && tw2.IsUnloadable && tw1.Name == tw2.Name);
920 }
921
922 void AddPropertyFieldWrapper(List<RuntimeJavaField> fields, PropertyInfo property, FieldInfo field)
923 {
924 // NOTE explictly defined properties (in map.xml) are decorated with HideFromJava,
925 // so we don't need to worry about them here
926 var hideFromJavaFlags = Context.AttributeHelper.GetHideFromJavaFlags(property);
927 if ((hideFromJavaFlags & HideFromJavaFlags.Code) == 0)
928 {
929 // is it a type 1 access stub?
930 if ((hideFromJavaFlags & HideFromJavaFlags.Reflection) != 0)
931 {
932 fields.Add(new RuntimeManagedByteCodeAccessStubJavaField(this, property, GetPropertyTypeWrapper(property)));
933 }
934 else
935 {
936 // It must be an explicit property
937 // (defined in Java source by an @ikvm.lang.Property annotation)
938 var mods = Context.AttributeHelper.GetModifiersAttribute(property);
939 fields.Add(new RuntimeManagedByteCodePropertyJavaField(this, property, new ExModifiers(mods.Modifiers, mods.IsInternal)));
940 }
941 }
942 }
943
944 static RuntimeJavaType TypeWrapperFromModOpt(RuntimeContext context, Type[] modopt)
945 {
946 int rank = 0;
947 RuntimeJavaType tw = null;
948 foreach (var type in modopt)
949 {
950 if (type == context.Resolver.ResolveRuntimeType(typeof(IKVM.Attributes.AccessStub).FullName).AsReflection())
951 {
952 // ignore
953 }
954 else if (type == context.Types.Array)
955 {
956 rank++;
957 }
958 else if (type == context.Types.Void || type.IsPrimitive || context.ClassLoaderFactory.IsRemappedType(type))
959 {
961 }
962 else if (type.DeclaringType != null && type.DeclaringType.FullName == RuntimeUnloadableJavaType.ContainerTypeName)
963 {
964 tw = new RuntimeUnloadableJavaType(context, TypeNameUtil.UnmangleNestedTypeName(type.Name), type);
965 }
966 else
967 {
968 tw = context.ClassLoaderFactory.GetJavaTypeFromType(type);
969 }
970 }
971 if (rank != 0)
972 {
973 tw = tw.MakeArrayType(rank);
974 }
975 return tw;
976 }
977
978 RuntimeJavaType GetPropertyTypeWrapper(PropertyInfo property)
979 {
980 return TypeWrapperFromModOpt(Context, property.GetOptionalCustomModifiers()) ?? Context.ClassLoaderFactory.GetJavaTypeFromType(property.PropertyType);
981 }
982
983 internal static RuntimeJavaType GetFieldTypeWrapper(RuntimeContext context, FieldInfo field)
984 {
985 return TypeWrapperFromModOpt(context, field.GetOptionalCustomModifiers()) ?? context.ClassLoaderFactory.GetJavaTypeFromType(field.FieldType);
986 }
987
988 internal static RuntimeJavaType GetParameterTypeWrapper(RuntimeContext context, ParameterInfo param)
989 {
990 var tw = TypeWrapperFromModOpt(context, param.GetOptionalCustomModifiers());
991 if (tw != null)
992 return tw;
993
994 var parameterType = param.ParameterType;
995 if (parameterType.IsByRef)
996 {
997 // we only support ByRef parameters for automatically generated delegate invoke stubs
998 parameterType = parameterType.GetElementType().MakeArrayType();
999 }
1000
1001 return context.ClassLoaderFactory.GetJavaTypeFromType(parameterType);
1002 }
1003
1004 RuntimeJavaField CreateFieldWrapper(FieldInfo field, HideFromJavaFlags hideFromJavaFlags)
1005 {
1006 var modifiers = Context.AttributeHelper.GetModifiers(field, false);
1007 var type = GetFieldTypeWrapper(Context, field);
1008 var name = field.Name;
1009
1010 if (field.IsSpecialName)
1011 name = UnicodeUtil.UnescapeInvalidSurrogates(name);
1012
1013 if (field.IsLiteral)
1014 {
1015 var flags = MemberFlags.None;
1016 if ((hideFromJavaFlags & HideFromJavaFlags.Reflection) != 0)
1017 {
1018 flags |= MemberFlags.HideFromReflection;
1019 }
1020 if (modifiers.IsInternal)
1021 {
1022 flags |= MemberFlags.InternalAccess;
1023 }
1024 return new RuntimeConstantJavaField(this, type, name, type.SigName, modifiers.Modifiers, field, null, flags);
1025 }
1026 else
1027 {
1028 return RuntimeJavaField.Create(this, type, field, name, type.SigName, modifiers);
1029 }
1030 }
1031
1032 internal override Type TypeAsTBD => type;
1033
1034 internal override bool IsMapUnsafeException => Context.AttributeHelper.IsExceptionIsUnsafeForMapping(type);
1035
1036#if EMITTERS
1037
1038 internal override void EmitRunClassConstructor(CodeEmitter ilgen)
1039 {
1040 if (HasStaticInitializer)
1041 {
1042 ilgen.Emit(OpCodes.Call, clinitMethod);
1043 }
1044 }
1045
1046#endif // EMITTERS
1047
1048 internal override string GetGenericSignature()
1049 {
1050 var attr = Context.AttributeHelper.GetSignature(type);
1051 if (attr != null)
1052 return attr.Signature;
1053
1054 return null;
1055 }
1056
1057 internal override string GetGenericMethodSignature(RuntimeJavaMethod method)
1058 {
1059 if (method is RemappedJavaMethod remappedMethod)
1060 return remappedMethod.GetGenericSignature();
1061
1062 var methodBase = method.GetMethod();
1063 if (methodBase != null)
1064 {
1065 var attr = Context.AttributeHelper.GetSignature(methodBase);
1066 if (attr != null)
1067 return attr.Signature;
1068 }
1069
1070 return null;
1071 }
1072
1073 internal override string GetGenericFieldSignature(RuntimeJavaField field)
1074 {
1075 var fi = field.GetField();
1076 if (fi != null)
1077 {
1078 var attr = Context.AttributeHelper.GetSignature(fi);
1079 if (attr != null)
1080 return attr.Signature;
1081 }
1082
1083 return null;
1084 }
1085
1086 internal override MethodParametersEntry[] GetMethodParameters(RuntimeJavaMethod method)
1087 {
1088 var mb = method.GetMethod();
1089 if (mb == null)
1090 return null; // delegate constructor
1091
1092 var attr = Context.AttributeHelper.GetMethodParameters(mb);
1093 if (attr == null)
1094 return null;
1095 if (attr.IsMalformed)
1096 return MethodParametersEntry.Malformed;
1097
1098 var parameters = mb.GetParameters();
1099 var mp = new MethodParametersEntry[attr.Modifiers.Length];
1100 for (int i = 0; i < mp.Length; i++)
1101 {
1102 mp[i].name = i < parameters.Length ? parameters[i].Name : null;
1103 mp[i].accessFlags = (AccessFlag)attr.Modifiers[i];
1104 }
1105
1106 return mp;
1107 }
1108
1109#if !IMPORTER && !EXPORTER
1110
1111 internal override string[] GetEnclosingMethod()
1112 {
1113 var enc = Context.AttributeHelper.GetEnclosingMethodAttribute(type);
1114 if (enc != null)
1115 return new string[] { enc.ClassName, enc.MethodName, enc.MethodSignature };
1116
1117 return null;
1118 }
1119
1120 internal override object[] GetDeclaredAnnotations()
1121 {
1122 return type.GetCustomAttributes(false);
1123 }
1124
1125 internal override object[] GetMethodAnnotations(RuntimeJavaMethod mw)
1126 {
1127 var mb = mw.GetMethod();
1128 if (mb == null)
1129 {
1130 // delegate constructor
1131 return null;
1132 }
1133
1134 return mb.GetCustomAttributes(false);
1135 }
1136
1137 internal override object[][] GetParameterAnnotations(RuntimeJavaMethod mw)
1138 {
1139 var mb = mw.GetMethod();
1140 if (mb == null)
1141 {
1142 // delegate constructor
1143 return null;
1144 }
1145
1146 var parameters = mb.GetParameters();
1147 int skip = 0;
1148 if (mb.IsStatic && !mw.IsStatic && mw.Name != "<init>")
1149 skip = 1;
1150
1151 int skipEnd = 0;
1152 if (mw.HasCallerID)
1153 skipEnd = 1;
1154
1155 var attribs = new object[parameters.Length - skip - skipEnd][];
1156 for (int i = skip; i < parameters.Length - skipEnd; i++)
1157 attribs[i - skip] = parameters[i].GetCustomAttributes(false);
1158
1159 return attribs;
1160 }
1161
1162 internal override object[] GetFieldAnnotations(RuntimeJavaField fw)
1163 {
1164 var field = fw.GetField();
1165 if (field != null)
1166 return field.GetCustomAttributes(false);
1167
1169 return prop.GetProperty().GetCustomAttributes(false);
1170
1171 return Array.Empty<object>();
1172 }
1173
1174#endif
1175
1176 internal sealed class CompiledAnnotation : Annotation
1177 {
1178
1179 readonly RuntimeContext context;
1180 readonly ConstructorInfo constructor;
1181
1187 internal CompiledAnnotation(RuntimeContext context, Type type)
1188 {
1189 this.context = context ?? throw new ArgumentNullException(nameof(context));
1190 constructor = type.GetConstructor(new Type[] { context.Resolver.ResolveCoreType(typeof(object).FullName).MakeArrayType().AsReflection() });
1191 }
1192
1193 private CustomAttributeBuilder MakeCustomAttributeBuilder(RuntimeClassLoader loader, object annotation)
1194 {
1195 return new CustomAttributeBuilder(constructor, new object[] { AnnotationDefaultAttribute.Escape(QualifyClassNames(loader, annotation)) });
1196 }
1197
1198 internal override void Apply(RuntimeClassLoader loader, TypeBuilder tb, object annotation)
1199 {
1200 tb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1201 }
1202
1203 internal override void Apply(RuntimeClassLoader loader, MethodBuilder mb, object annotation)
1204 {
1205 mb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1206 }
1207
1208 internal override void Apply(RuntimeClassLoader loader, FieldBuilder fb, object annotation)
1209 {
1210 fb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1211 }
1212
1213 internal override void Apply(RuntimeClassLoader loader, ParameterBuilder pb, object annotation)
1214 {
1215 pb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1216 }
1217
1218 internal override void Apply(RuntimeClassLoader loader, AssemblyBuilder ab, object annotation)
1219 {
1220 ab.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1221 }
1222
1223 internal override void Apply(RuntimeClassLoader loader, PropertyBuilder pb, object annotation)
1224 {
1225 pb.SetCustomAttribute(MakeCustomAttributeBuilder(loader, annotation));
1226 }
1227
1228 internal override bool IsCustomAttribute
1229 {
1230 get { return false; }
1231 }
1232 }
1233
1234 internal override Annotation Annotation
1235 {
1236 get
1237 {
1238 var annotationAttribute = Context.AttributeHelper.GetAnnotationAttributeType(type);
1239 if (annotationAttribute != null)
1240 return new CompiledAnnotation(Context, type.Assembly.GetType(annotationAttribute, true));
1241
1242 return null;
1243 }
1244 }
1245
1246 internal override Type EnumType
1247 {
1248 get
1249 {
1250 if ((this.Modifiers & Modifiers.Enum) != 0)
1251 return type.GetNestedType("__Enum");
1252
1253 return null;
1254 }
1255 }
1256
1257#if !IMPORTER && !EXPORTER
1258
1259 internal override string GetSourceFileName()
1260 {
1261 var attr = type.GetCustomAttributes(typeof(SourceFileAttribute), false);
1262 if (attr.Length == 1)
1263 return ((SourceFileAttribute)attr[0]).SourceFile;
1264
1265 if (DeclaringTypeWrapper != null)
1266 return DeclaringTypeWrapper.GetSourceFileName();
1267
1268 if (IsNestedTypeAnonymousOrLocalClass(type))
1269 return Context.ClassLoaderFactory.GetJavaTypeFromType(type.DeclaringType).GetSourceFileName();
1270
1271 if (type.Module.IsDefined(typeof(SourceFileAttribute), false))
1272 return type.Name + ".java";
1273
1274 return null;
1275 }
1276
1277 internal override int GetSourceLineNumber(MethodBase mb, int ilOffset)
1278 {
1279 var attr = mb.GetCustomAttributes(typeof(LineNumberTableAttribute), false);
1280 if (attr.Length == 1)
1281 return ((LineNumberTableAttribute)attr[0]).GetLineNumber(ilOffset);
1282
1283 return -1;
1284 }
1285#endif
1286
1287 internal override bool IsFastClassLiteralSafe
1288 {
1289 get { return true; }
1290 }
1291
1292 internal override object[] GetConstantPool()
1293 {
1294 return Context.AttributeHelper.GetConstantPool(type);
1295 }
1296
1297 internal override byte[] GetRawTypeAnnotations()
1298 {
1299 return Context.AttributeHelper.GetRuntimeVisibleTypeAnnotations(type);
1300 }
1301
1302 internal override byte[] GetMethodRawTypeAnnotations(RuntimeJavaMethod mw)
1303 {
1304 MethodBase mb = mw.GetMethod();
1305 return mb == null ? null : Context.AttributeHelper.GetRuntimeVisibleTypeAnnotations(mb);
1306 }
1307
1308 internal override byte[] GetFieldRawTypeAnnotations(RuntimeJavaField fw)
1309 {
1310 FieldInfo fi = fw.GetField();
1311 return fi == null ? null : Context.AttributeHelper.GetRuntimeVisibleTypeAnnotations(fi);
1312 }
1313
1314 }
1315
1316}
IKVM.Reflection.Type Type
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.FieldInfo FieldInfo
IKVM.Reflection.PropertyInfo PropertyInfo
IKVM.Reflection.MethodInfo MethodInfo
IKVM.Reflection.ParameterInfo ParameterInfo
IKVM.Reflection.MethodBase MethodBase
global::java.lang.invoke.LambdaForm.Name Name
static object QualifyClassNames(RuntimeClassLoader loader, object annotation)
Represents an internal error that occurred within IKVM.
.NET exception that corresponds to a Java exception.
Runtime support for a class loader.
Maintains services relevant to an instane of the IKVM runtime.
AttributeHelper AttributeHelper
Gets the AttributeHelper associated with this instance of the runtime.
Types Types
Gets the Types associated with this instance of the runtime.
RuntimeManagedJavaTypeFactory ManagedJavaTypeFactory
Gets the RuntimeManagedJavaTypeFactory associated with this instance of the runtime.
RuntimePrimitiveJavaTypeFactory PrimitiveJavaTypeFactory
Gets the RuntimePrimitiveJavaTypeFactory associated with this instance of the runtime.
RuntimeVerifierJavaTypeFactory VerifierJavaTypeFactory
Gets the RuntimeVerifierJavaTypeFactory associated with this instance of the runtime.
ISymbolResolver Resolver
Gets the ISymbolResolver associated with this instance of the runtime.
CoreClasses JavaBase
Gets the CoreClasses associated with this instance of the runtime.
RuntimeClassLoaderFactory ClassLoaderFactory
Gets the RuntimeClassLoaderFactory associated with this instance of the runtime.
RuntimeManagedByteCodeJavaType newInstance(string name, Type type)
Creates a new instance of the appropriate runtime type.
RuntimeManagedByteCodeJavaTypeFactory(RuntimeContext context)
Initializes a new instance.
Represents a runtime Java type derived from a .NET assembly which was the result of the IKVM compiler...
RuntimeManagedByteCodeJavaType(RuntimeContext context, ExModifiers exmod, string name)
Initializes a new instance.
RuntimeManagedByteCodeJavaType(RuntimeContext context, string name, Type type)
Initializes a new instance.
Represents a .NET property defined in Java with the 'ikvm.lang.Property' annotation.
RuntimeJavaType GetJavaTypeFromManagedType(Type type)
Gets the RuntimeJavaType associated with the specified managed type, or creates one on demand.
Type MulticastDelegate
Definition Types.cs:109
MemberFlags
Describes various options applied to a member.
@ InternalAccess
Member should be generated with "internal" .NET access.
static DiagnosticEvent UnableToResolveInterface(string arg0, string arg1, Exception? exception=null, DiagnosticLocation location=default)
The 'UnableToResolveInterface' diagnostic.
Provides methods to parse a Java class name.