IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
RuntimeByteCodeJavaType.FinishContext.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
28using IKVM.Attributes;
29using IKVM.ByteCode;
30using IKVM.ByteCode.Decoding;
32
33
34#if IMPORTER
35using IKVM.Reflection;
38
39using Type = IKVM.Reflection.Type;
41#else
42using System.Reflection;
43using System.Reflection.Emit;
44
46#endif
47
48namespace IKVM.Runtime
49{
50
51 partial class RuntimeByteCodeJavaType
52 {
53
54 internal sealed class FinishContext
55 {
56
57 readonly RuntimeContext context;
58 readonly RuntimeJavaType host;
59 readonly ClassFile classFile;
60 readonly DynamicOrAotTypeWrapper wrapper;
61 readonly TypeBuilder typeBuilder;
62 List<TypeBuilder> nestedTypeBuilders;
63 MethodInfo callerIDMethod;
64 List<Item> items;
65 Dictionary<RuntimeJavaField, MethodBuilder> arfuMap;
66 Dictionary<MethodKey, MethodInfo> invokespecialstubcache;
67 Dictionary<string, MethodInfo> dynamicClassLiteral;
68#if IMPORTER
69 TypeBuilder interfaceHelperMethodsTypeBuilder;
70#else
71 List<object> liveObjects;
72#endif
73
74 private struct Item
75 {
76 internal int key;
77 internal object value;
78 }
79
88 internal FinishContext(RuntimeContext context, RuntimeJavaType host, ClassFile classFile, DynamicOrAotTypeWrapper wrapper, TypeBuilder typeBuilder)
89 {
90 this.context = context;
91 this.host = host;
92 this.classFile = classFile;
93 this.wrapper = wrapper;
94 this.typeBuilder = typeBuilder;
95 }
96
100 public RuntimeContext Context => context;
101
102 internal RuntimeByteCodeJavaType TypeWrapper
103 {
104 get { return wrapper; }
105 }
106
107 internal T GetValue<T>(int key)
108 where T : class, new()
109 {
110 items ??= new List<Item>();
111 for (int i = 0; i < items.Count; i++)
112 if (items[i].key == key && items[i].value is T value)
113 return value;
114
115 Item item;
116 item.key = key;
117 T val = new T();
118 item.value = val;
119 items.Add(item);
120 return val;
121 }
122
123 internal void EmitDynamicClassLiteral(CodeEmitter ilgen, RuntimeJavaType tw, bool dynamicCallerID)
124 {
125 Debug.Assert(tw.IsUnloadable);
126
127 dynamicClassLiteral ??= new Dictionary<string, MethodInfo>();
128
129 var cacheKey = tw.Name;
130 if (dynamicCallerID)
131 cacheKey += ";dynamic";
132
133 if (!dynamicClassLiteral.TryGetValue(cacheKey, out var method))
134 {
135 var fb = typeBuilder.DefineField("__<>class", context.JavaBase.TypeOfJavaLangClass.TypeAsSignatureType, FieldAttributes.PrivateScope | FieldAttributes.Static);
136 var mb = DefineHelperMethod("__<>class", context.JavaBase.TypeOfJavaLangClass.TypeAsSignatureType, Type.EmptyTypes);
137 var ilgen2 = context.CodeEmitterFactory.Create(mb);
138 ilgen2.Emit(OpCodes.Ldsfld, fb);
139 var label = ilgen2.DefineLabel();
140 ilgen2.EmitBrtrue(label);
141 ilgen2.Emit(OpCodes.Ldstr, tw.Name);
142 EmitCallerID(ilgen2, dynamicCallerID);
143 ilgen2.Emit(OpCodes.Call, context.ByteCodeHelperMethods.DynamicClassLiteral);
144 ilgen2.Emit(OpCodes.Stsfld, fb);
145 ilgen2.MarkLabel(label);
146 ilgen2.Emit(OpCodes.Ldsfld, fb);
147 ilgen2.Emit(OpCodes.Ret);
148 ilgen2.DoEmit();
149 method = mb;
150 dynamicClassLiteral.Add(cacheKey, method);
151 }
152
153 ilgen.Emit(OpCodes.Call, method);
154 }
155
156 internal void EmitHostCallerID(CodeEmitter ilgen)
157 {
158#if IMPORTER || FIRST_PASS
159 throw new InvalidOperationException();
160#else
161 EmitLiveObjectLoad(ilgen, DynamicCallerIDProvider.CreateCallerID(host));
162 context.JavaBase.TypeOfIkvmInternalCallerID.EmitCheckcast(ilgen);
163#endif
164 }
165
166 internal void EmitCallerID(CodeEmitter ilgen, bool dynamic)
167 {
168#if !FIRST_PASS && !IMPORTER
169 if (dynamic)
170 {
171 EmitLiveObjectLoad(ilgen, DynamicCallerIDProvider.Instance);
172 ilgen.Emit(OpCodes.Call, context.ByteCodeHelperMethods.DynamicCallerID);
173 return;
174 }
175#endif
176 if (callerIDMethod == null)
177 {
178 CreateGetCallerID();
179 }
180
181 ilgen.Emit(OpCodes.Call, callerIDMethod);
182 }
183
184 private void CreateGetCallerID()
185 {
186 RuntimeJavaType tw = context.JavaBase.TypeOfIkvmInternalCallerID;
187 FieldBuilder callerIDField = typeBuilder.DefineField("__<callerID>", tw.TypeAsSignatureType, FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.SpecialName);
188 MethodBuilder mb = DefineHelperMethod("__<GetCallerID>", tw.TypeAsSignatureType, Type.EmptyTypes);
189 callerIDMethod = mb;
190 CodeEmitter ilgen = context.CodeEmitterFactory.Create(mb);
191 ilgen.Emit(OpCodes.Ldsfld, callerIDField);
192 CodeEmitterLabel done = ilgen.DefineLabel();
193 ilgen.EmitBrtrue(done);
194 EmitCallerIDInitialization(ilgen, callerIDField);
195 ilgen.MarkLabel(done);
196 ilgen.Emit(OpCodes.Ldsfld, callerIDField);
197 ilgen.Emit(OpCodes.Ret);
198 ilgen.DoEmit();
199 }
200
201 private void RegisterNestedTypeBuilder(TypeBuilder tb)
202 {
203 nestedTypeBuilders ??= new List<TypeBuilder>();
204 nestedTypeBuilders.Add(tb);
205 }
206
207 internal Type FinishImpl()
208 {
209 var methods = wrapper.GetMethods();
210 var fields = wrapper.GetFields();
211#if IMPORTER
212 wrapper.FinishGhost(typeBuilder, methods);
213#endif
214
215 if (!classFile.IsInterface)
216 {
217 // set the base type (this needs to be done before we emit any methods, because in the static compiler
218 // GetBaseTypeForDefineType() has the side effect of inserting the __WorkaroundBaseClass__ when necessary)
219 typeBuilder.SetParent(wrapper.GetBaseTypeForDefineType());
220 }
221
222 // if we're not abstract make sure we don't inherit any abstract methods
223 if (!wrapper.IsAbstract)
224 {
225 var parent = wrapper.BaseTypeWrapper;
226
227 // if parent is not abstract, the .NET implementation will never have abstract methods (only
228 // stubs that throw AbstractMethodError)
229 // NOTE interfaces are supposed to be abstract, but the VM doesn't enforce this, so
230 // we have to check for a null parent (interfaces have no parent).
231 while (parent != null && parent.IsAbstract)
232 {
233 foreach (RuntimeJavaMethod mw in parent.GetMethods())
234 {
235 var mi = mw.GetMethod() as MethodInfo;
236 if (mi != null && mi.IsAbstract && !mi.DeclaringType.IsInterface)
237 {
238 bool needStub = false;
239 bool needRename = false;
240 if (mw.IsPublic || mw.IsProtected)
241 {
242 var fmw = wrapper.GetMethod(mw.Name, mw.Signature, true);
243 while (fmw != mw && (fmw.IsStatic || fmw.IsPrivate))
244 {
245 needRename = true;
246 fmw = fmw.DeclaringType.BaseTypeWrapper.GetMethod(mw.Name, mw.Signature, true);
247 }
248 if (fmw == mw && fmw.DeclaringType != wrapper)
249 {
250 needStub = true;
251 }
252 }
253 else
254 {
255 var fmw = wrapper.GetMethod(mw.Name, mw.Signature, true);
256 while (fmw != mw && (fmw.IsStatic || fmw.IsPrivate || !(mw.DeclaringType.IsPackageAccessibleFrom(fmw.DeclaringType) || (mw.IsInternal && mw.DeclaringType.InternalsVisibleTo(fmw.DeclaringType)))))
257 {
258 needRename = true;
259 fmw = fmw.DeclaringType.BaseTypeWrapper.GetMethod(mw.Name, mw.Signature, true);
260 }
261 if (fmw == mw && fmw.DeclaringType != wrapper)
262 {
263 needStub = true;
264 }
265 }
266 if (needStub)
267 {
268 // NOTE in Sun's JRE 1.4.1 this method cannot be overridden by subclasses,
269 // but I think this is a bug, so we'll support it anyway.
270 string name = mi.Name;
271 MethodAttributes attr = mi.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.NewSlot);
272 if (needRename)
273 {
274 name = "__<>" + name + "/" + mi.DeclaringType.FullName;
275 attr = MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.NewSlot;
276 }
277 MethodBuilder mb = mw.GetDefineMethodHelper().DefineMethod(wrapper, typeBuilder, name, attr);
278 if (needRename)
279 {
280 typeBuilder.DefineMethodOverride(mb, mi);
281 }
282 context.AttributeHelper.HideFromJava(mb);
283 CodeEmitter ilgen = context.CodeEmitterFactory.Create(mb);
284 ilgen.EmitThrow("java.lang.AbstractMethodError", mw.DeclaringType.Name + "." + mw.Name + mw.Signature);
285 ilgen.DoEmit();
286 wrapper.EmitLevel4Warning(HardError.AbstractMethodError, mw.DeclaringType.Name + "." + mw.Name + mw.Signature);
287 }
288 }
289 }
290
291 parent = parent.BaseTypeWrapper;
292 }
293 }
294#if IMPORTER
295 TypeBuilder tbDefaultMethods = null;
296#endif
297 bool basehasclinit = wrapper.BaseTypeWrapper != null && wrapper.BaseTypeWrapper.HasStaticInitializer;
298 int clinitIndex = -1;
299 bool hasConstructor = false;
300 for (int i = 0; i < classFile.Methods.Length; i++)
301 {
302 var m = classFile.Methods[i];
303 var mb = (MethodBuilder)methods[i].GetMethod();
304 if (mb == null)
305 {
306 // method doesn't really exist (e.g. delegate constructor or <clinit> that is optimized away)
307 if (m.IsConstructor)
308 {
309 hasConstructor = true;
310 }
311 }
312 else if (m.IsClassInitializer)
313 {
314 // we handle the <clinit> after we've done the other methods,
315 // to make it easier to inject code needed by the other methods
316 clinitIndex = i;
317 continue;
318 }
319 else if (m.IsConstructor)
320 {
321 hasConstructor = true;
322 var ilGenerator = context.CodeEmitterFactory.Create(mb);
323 CompileConstructorBody(this, ilGenerator, i);
324 }
325 else
326 {
327#if IMPORTER
328 if (methods[i].GetParameters().Length > MethodHandleUtil.MaxArity && methods[i].RequiresNonVirtualDispatcher && wrapper.ClassLoader.EmitNoRefEmitHelpers)
329 {
330 wrapper.ClassLoader.GetTypeWrapperFactory().DefineDelegate(methods[i].GetParameters().Length, methods[i].ReturnType == context.PrimitiveJavaTypeFactory.VOID);
331 }
332#endif
333 if (m.IsAbstract)
334 {
335 var stub = false;
336 if (!classFile.IsAbstract)
337 {
338 // NOTE in the JVM it is apparently legal for a non-abstract class to have abstract methods, but
339 // the CLR doens't allow this, so we have to emit a method that throws an AbstractMethodError
340 stub = true;
341 wrapper.EmitLevel4Warning(HardError.AbstractMethodError, classFile.Name + "." + m.Name + m.Signature);
342 }
343 else if (classFile.IsPublic && !classFile.IsFinal && !(m.IsPublic || m.IsProtected))
344 {
345 // We have an abstract package accessible method in our public class. To allow a class in another
346 // assembly to subclass this class, we must fake the abstractness of this method.
347 stub = true;
348 }
349
350 if (stub)
351 {
352 var ilGenerator = context.CodeEmitterFactory.Create(mb);
353 ilGenerator.EmitThrow("java.lang.AbstractMethodError", classFile.Name + "." + m.Name + m.Signature);
354 ilGenerator.DoEmit();
355 }
356 }
357 else if (m.IsNative)
358 {
359 if ((mb.Attributes & MethodAttributes.PinvokeImpl) != 0)
360 {
361 continue;
362 }
363
364 if (wrapper.IsDelegate)
365 {
366 mb.SetImplementationFlags(mb.GetMethodImplementationFlags() | MethodImplAttributes.Runtime);
367 continue;
368 }
369
370 Profiler.Enter("JavaTypeImpl.Finish.Native");
371 try
372 {
373 var ilGenerator = context.CodeEmitterFactory.Create(mb);
374#if IMPORTER
375 // do we have an implementation in map.xml?
376 if (wrapper.EmitMapXmlMethodPrologueAndOrBody(ilGenerator, classFile, m))
377 {
378 ilGenerator.DoEmit();
379 continue;
380 }
381
382 if (m.InterlockedCompareAndSetField != null && EmitInterlockedCompareAndSet(methods[i], m.InterlockedCompareAndSetField, ilGenerator))
383 {
384 ilGenerator.DoEmit();
385 continue;
386 }
387#endif
388
389 MethodInfo nativeMethod = null;
390 var args = methods[i].GetParameters();
391 var nargs = args;
392
393#if IMPORTER
394 // see if there exists a "managed JNI" class for this type
395 var nativeCodeType = context.Resolver.ResolveRuntimeType("IKVM.Java.Externs." + classFile.Name.Replace("$", "+")).AsReflection();
396 if (nativeCodeType != null)
397 {
398 if (!m.IsStatic)
399 nargs = ArrayUtil.Concat(wrapper, args);
400
401 if (methods[i].HasCallerID)
402 nargs = ArrayUtil.Concat(nargs, context.JavaBase.TypeOfIkvmInternalCallerID);
403
404 foreach (var method in nativeCodeType.GetMethods(BindingFlags.Static | BindingFlags.Public))
405 {
406 var param = method.GetParameters();
407 int paramLength = param.Length;
408
409 while (paramLength != 0 && (param[paramLength - 1].IsIn || param[paramLength - 1].ParameterType.IsByRef))
410 paramLength--;
411
412 var match = new RuntimeJavaType[paramLength];
413 for (int j = 0; j < paramLength; j++)
414 match[j] = context.ClassLoaderFactory.GetJavaTypeFromType(param[j].ParameterType);
415
416 if (m.Name == method.Name && IsCompatibleArgList(nargs, match))
417 {
418 nativeMethod = method;
419 break;
420 }
421 }
422 }
423
424#endif
425
426 if (nativeMethod != null)
427 {
428#if IMPORTER
429 for (int j = 0; j < nargs.Length; j++)
430 ilGenerator.EmitLdarg(j);
431
432 var param = nativeMethod.GetParameters();
433 for (int j = nargs.Length; j < param.Length; j++)
434 {
435 var paramType = param[j].ParameterType;
436 var fieldTypeWrapper = context.ClassLoaderFactory.GetJavaTypeFromType(paramType.IsByRef ? paramType.GetElementType() : paramType);
437 var field = wrapper.GetFieldWrapper(param[j].Name, fieldTypeWrapper.SigName);
438 if (field == null)
439 {
440 wrapper.Context.Diagnostics.GenericCompilerError($"Error: Native method field binding not found: {classFile.Name}.{param[j].Name}{fieldTypeWrapper.SigName}");
441 wrapper.Context.StaticCompiler.errorCount++;
442 continue;
443 }
444 if (m.IsStatic && !field.IsStatic)
445 {
446 wrapper.Context.Diagnostics.GenericCompilerError($"Error: Native method field binding cannot access instance field from static method: {classFile.Name}.{param[j].Name}{fieldTypeWrapper.SigName}");
447 wrapper.Context.StaticCompiler.errorCount++;
448 continue;
449 }
450 if (!field.IsAccessibleFrom(wrapper, wrapper, wrapper))
451 {
452 wrapper.Context.Diagnostics.GenericCompilerError($"Error: Native method field binding not accessible: {classFile.Name}.{param[j].Name}{fieldTypeWrapper.SigName}");
453 wrapper.Context.StaticCompiler.errorCount++;
454 continue;
455 }
456 if (paramType.IsByRef && field.IsFinal)
457 {
458 wrapper.Context.Diagnostics.GenericCompilerError($"Error: Native method field binding cannot use ByRef for final field: {classFile.Name}.{param[j].Name}{fieldTypeWrapper.SigName}");
459 wrapper.Context.StaticCompiler.errorCount++;
460 continue;
461 }
462 field.Link();
463 if (paramType.IsByRef && field.GetField() == null)
464 {
465 wrapper.Context.Diagnostics.GenericCompilerError($"Error: Native method field binding cannot use ByRef on field without backing field: {classFile.Name}.{param[j].Name}{fieldTypeWrapper.SigName}");
466 wrapper.Context.StaticCompiler.errorCount++;
467 continue;
468 }
469 if (!field.IsStatic)
470 {
471 ilGenerator.EmitLdarg(0);
472 }
473 if (paramType.IsByRef)
474 {
475 ilGenerator.Emit(field.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldflda, field.GetField());
476 }
477 else
478 {
479 field.EmitGet(ilGenerator);
480 }
481 }
482 ilGenerator.Emit(OpCodes.Call, nativeMethod);
483 var retTypeWrapper = methods[i].ReturnType;
484 if (!retTypeWrapper.TypeAsTBD.Equals(nativeMethod.ReturnType) && !retTypeWrapper.IsGhost)
485 ilGenerator.Emit(OpCodes.Castclass, retTypeWrapper.TypeAsTBD);
486
487 ilGenerator.Emit(OpCodes.Ret);
488#endif
489 }
490 else
491 {
492 if (wrapper.ClassLoader.NoJNI)
493 {
494 // since NoJniStubs can only be set when we're statically compiling, it is safe to use the "compiler" trace switch
495 wrapper.ClassLoader.Diagnostics.GenericCompilerWarning($"Native method not implemented: {classFile.Name}.{m.Name}.{m.Signature}");
496 ilGenerator.EmitThrow("java.lang.UnsatisfiedLinkError", "Native method not implemented (compiled with -nojni): " + classFile.Name + "." + m.Name + m.Signature);
497 }
498 else
499 {
500 new JniBuilder(context).Generate(this, ilGenerator, wrapper, methods[i], typeBuilder, classFile, m, args, false);
501 }
502 }
503
504 ilGenerator.DoEmit();
505 }
506 finally
507 {
508 Profiler.Leave("JavaTypeImpl.Finish.Native");
509 }
510 }
511 else
512 {
513 if (m.IsVirtual && classFile.IsInterface)
514 {
515 mb = (MethodBuilder)RuntimeDefaultInterfaceJavaMethod.GetImpl(methods[i]);
516#if IMPORTER
517 CreateDefaultMethodInterop(ref tbDefaultMethods, mb, methods[i]);
518#endif
519 }
520
521 var ilGenerator = context.CodeEmitterFactory.Create(mb);
522 if (!m.IsStatic && !m.IsPublic && classFile.IsInterface)
523 {
524 // Java 8 non-virtual interface method that we compile as a static method,
525 // we need to make sure the passed in this reference isn't null
526 ilGenerator.EmitLdarg(0);
527 if (wrapper.IsGhost)
528 ilGenerator.Emit(OpCodes.Ldfld, wrapper.GhostRefField);
529 ilGenerator.EmitNullCheck();
530 }
531
532#if IMPORTER
533 // do we have an implementation in map.xml?
534 if (wrapper.EmitMapXmlMethodPrologueAndOrBody(ilGenerator, classFile, m))
535 {
536 ilGenerator.DoEmit();
537 continue;
538 }
539#endif
540 var nonleaf = false;
541 Compiler.Compile(this, host, wrapper, methods[i], classFile, m, ilGenerator, ref nonleaf);
542 ilGenerator.CheckLabels();
543 ilGenerator.DoEmit();
544 if (nonleaf)
545 mb.SetImplementationFlags(mb.GetMethodImplementationFlags());
546#if IMPORTER
547 ilGenerator.EmitLineNumberTable(mb);
548#else
549 var linenumbers = ilGenerator.GetLineNumberTable();
550 if (linenumbers != null)
551 {
552 wrapper.lineNumberTables ??= new byte[methods.Length][];
553 wrapper.lineNumberTables[i] = linenumbers;
554 }
555#endif // IMPORTER
556 }
557 }
558 }
559
560 AddInheritedDefaultInterfaceMethods(methods);
561
562 if (clinitIndex != -1 || (basehasclinit && !classFile.IsInterface) || classFile.HasInitializedFields)
563 {
564 MethodBuilder cb;
565 if (clinitIndex != -1)
566 {
567 cb = (MethodBuilder)methods[clinitIndex].GetMethod();
568 }
569 else
570 {
571 cb = ReflectUtil.DefineTypeInitializer(typeBuilder, wrapper.classLoader);
572 context.AttributeHelper.HideFromJava(cb);
573 }
574 var ilGenerator = context.CodeEmitterFactory.Create(cb);
575
576 // before we call the base class initializer, we need to set the non-final static ConstantValue fields
577 EmitConstantValueInitialization(fields, ilGenerator);
578 if (basehasclinit)
579 wrapper.BaseTypeWrapper.EmitRunClassConstructor(ilGenerator);
580
581 if (clinitIndex != -1)
582 {
583 CompileConstructorBody(this, ilGenerator, clinitIndex);
584 }
585 else
586 {
587 ilGenerator.Emit(OpCodes.Ret);
588 ilGenerator.DoEmit();
589 }
590
591 ilGenerator.CheckLabels();
592 }
593
594 // add all interfaces that we implement (including the magic ones) and handle ghost conversions
595 ImplementInterfaces(wrapper.Interfaces, new List<RuntimeJavaType>());
596
597 // NOTE non-final fields aren't allowed in interfaces so we don't have to initialize constant fields
598 if (!classFile.IsInterface)
599 {
600 // if a class has no constructor, we generate one otherwise Ref.Emit will create a default ctor
601 // and that has several problems:
602 // - base type may not have an accessible default constructor
603 // - Ref.Emit uses BaseType.GetConstructors() which may trigger a TypeResolve event
604 // - we don't want the synthesized constructor to show up in Java
605 if (!hasConstructor)
606 {
607 var ilgen = context.CodeEmitterFactory.Create(ReflectUtil.DefineConstructor(typeBuilder, MethodAttributes.PrivateScope, Type.EmptyTypes));
608 ilgen.Emit(OpCodes.Ldnull);
609 ilgen.Emit(OpCodes.Throw);
610 ilgen.DoEmit();
611 }
612
613 // here we loop thru all the interfaces to explicitly implement any methods that we inherit from
614 // base types that may have a different name from the name in the interface
615 // (e.g. interface that has an equals() method that should override System.Object.Equals())
616 // also deals with interface methods that aren't implemented (generate a stub that throws AbstractMethodError)
617 // and with methods that aren't public (generate a stub that throws IllegalAccessError)
618 var doneSet = new Dictionary<RuntimeJavaType, RuntimeJavaType>();
619 var interfaces = wrapper.Interfaces;
620 for (int i = 0; i < interfaces.Length; i++)
621 ImplementInterfaceMethodStubs(doneSet, interfaces[i], false);
622
623 // if any of our base classes has an incomplete interface implementation we need to look through all
624 // the base class interfaces to see if we've got an implementation now
625 var baseTypeWrapper = wrapper.BaseTypeWrapper;
626 while (baseTypeWrapper.HasIncompleteInterfaceImplementation)
627 {
628 for (int i = 0; i < baseTypeWrapper.Interfaces.Length; i++)
629 ImplementInterfaceMethodStubs(doneSet, baseTypeWrapper.Interfaces[i], true);
630
631 baseTypeWrapper = baseTypeWrapper.BaseTypeWrapper;
632 }
633
634 if (!wrapper.IsAbstract && wrapper.HasUnsupportedAbstractMethods)
635 AddUnsupportedAbstractMethods();
636
637 if (!wrapper.ClassLoader.NoAutomagicSerialization)
638 wrapper.automagicSerializationCtor = context.Serialization.AddAutomagicSerialization(wrapper, typeBuilder);
639 }
640
641#if IMPORTER
642
643 // If we're an interface that has public/protected fields, we create an inner class
644 // to expose these fields to C# (which stubbornly refuses to see fields in interfaces).
645 AddInterfaceFieldsInterop(fields);
646
647 // If we're a Java 8 interface with static methods, we create an inner class
648 // to expose these methods to C#.
649 AddInterfaceMethodsInterop(methods);
650
651 // See if there is any additional metadata
652 wrapper.EmitMapXmlMetadata(typeBuilder, classFile, fields, methods);
653
654 // if we inherit public members from non-public base classes or have public members with non-public types in their signature, we need access stubs
655 if (wrapper.IsPublic)
656 AddAccessStubs();
657
658 AddConstantPoolAttributeIfNecessary(context, classFile, typeBuilder);
659
660#endif
661
662 for (int i = 0; i < classFile.Methods.Length; i++)
663 {
664 var m = classFile.Methods[i];
665 var mb = (MethodBuilder)methods[i].GetMethod();
666 if (mb == null)
667 continue;
668
669 if (m.Annotations != null)
670 {
671 ParameterBuilder returnParameter = null;
672 foreach (object[] def in m.Annotations)
673 {
674 var annotation = Annotation.Load(wrapper, def);
675 if (annotation != null)
676 {
677 annotation.Apply(wrapper.ClassLoader, mb, def);
678 annotation.ApplyReturnValue(wrapper.ClassLoader, mb, ref returnParameter, def);
679 }
680 }
681 }
682
683 AddMethodParameterInfo(m, methods[i], mb, out var parameterNames);
684
685#if IMPORTER
686 if (methods[i].HasCallerID)
687 {
688 context.AttributeHelper.SetEditorBrowsableNever(mb);
689 EmitCallerIDStub(methods[i], parameterNames);
690 }
691#endif
692 }
693
694 for (int i = 0; i < classFile.Fields.Length; i++)
695 {
696 if (classFile.Fields[i].Annotations != null)
697 {
698 foreach (object[] def in classFile.Fields[i].Annotations)
699 {
700 var annotation = Annotation.Load(wrapper, def);
701 if (annotation != null)
702 {
703 {
704 var prop = fields[i] as RuntimeByteCodePropertyJavaField;
705 if (prop != null)
706 {
707 annotation.Apply(wrapper.ClassLoader, prop.GetPropertyBuilder(), def);
708 }
709 else
710 {
711 annotation.Apply(wrapper.ClassLoader, (FieldBuilder)fields[i].GetField(), def);
712 }
713 }
714 }
715 }
716 }
717 }
718
719 if (classFile.Annotations != null)
720 {
721 foreach (object[] def in classFile.Annotations)
722 {
723 var annotation = Annotation.Load(wrapper, def);
724 if (annotation != null)
725 annotation.Apply(wrapper.ClassLoader, typeBuilder, def);
726 }
727 }
728
729#if IMPORTER
730 AddImplementsAttribute();
731#endif
732
733 Type type;
734 Profiler.Enter("TypeBuilder.CreateType");
735
736 try
737 {
738 type = typeBuilder.CreateType();
739 if (nestedTypeBuilders != null)
740 {
741 context.ClassLoaderFactory.LoadClassCritical("ikvm.internal.IntrinsicAtomicReferenceFieldUpdater").Finish();
742 context.ClassLoaderFactory.LoadClassCritical("ikvm.internal.IntrinsicThreadLocal").Finish();
743 foreach (TypeBuilder tb in nestedTypeBuilders)
744 tb.CreateType();
745 }
746#if !IMPORTER
747 if (liveObjects != null)
748 typeof(IKVM.Runtime.LiveObjectHolder<>).MakeGenericType(type).GetField("values", BindingFlags.Static | BindingFlags.Public).SetValue(null, liveObjects.ToArray());
749#endif
750 }
751 finally
752 {
753 Profiler.Leave("TypeBuilder.CreateType");
754 }
755#if !IMPORTER
756 // When we're statically compiling we don't need to set the wrapper here, because we've already done so for the typeBuilder earlier.
757 context.ClassLoaderFactory.SetWrapperForType(type, wrapper);
758#endif
759
760#if IMPORTER
761 wrapper.FinishGhostStep2();
762#endif
763
764 return type;
765 }
766
767#if IMPORTER
768
769 static void AddConstantPoolAttributeIfNecessary(RuntimeContext context, ClassFile classFile, TypeBuilder typeBuilder)
770 {
771 object[] constantPool = null;
772 bool[] inUse = null;
773
774 ref readonly var runtimeVisibleTypeAnnotations = ref classFile.RuntimeVisibleTypeAnnotations;
775 MarkConstantPoolUsage(classFile, in runtimeVisibleTypeAnnotations, ref constantPool, ref inUse);
776
777 foreach (var method in classFile.Methods)
778 {
779 ref readonly var methodRuntimeVisibleTypeAnnotations = ref method.RuntimeVisibleTypeAnnotations;
780 MarkConstantPoolUsage(classFile, in methodRuntimeVisibleTypeAnnotations, ref constantPool, ref inUse);
781 }
782
783 foreach (var field in classFile.Fields)
784 {
785 ref readonly var fieldRuntimeVisibleTypeAnnotations = ref field.RuntimeVisibleTypeAnnotations;
786 MarkConstantPoolUsage(classFile, in field.RuntimeVisibleTypeAnnotations, ref constantPool, ref inUse);
787 }
788
789 if (constantPool != null)
790 {
791 // to save space, we clear out the items that aren't used by the RuntimeVisibleTypeAnnotations and
792 // use an RLE for the empty slots
793 context.AttributeHelper.SetConstantPoolAttribute(typeBuilder, ConstantPoolAttribute.Compress(constantPool, inUse));
794 }
795 }
796
804 static void MarkConstantPoolUsage(ClassFile classFile, ref readonly TypeAnnotationTable runtimeVisibleTypeAnnotations, ref object[] constantPool, ref bool[] inUse)
805 {
806 if (runtimeVisibleTypeAnnotations.Count > 0)
807 {
808 if (constantPool == null)
809 {
810 constantPool = classFile.GetConstantPool();
811 inUse = new bool[constantPool.Length];
812 }
813 try
814 {
815 foreach (ref readonly var annotation in runtimeVisibleTypeAnnotations)
816 {
817 ref readonly var i = ref annotation;
818 MarkConstantPoolUsageForTypeAnnotation(in i, inUse);
819 }
820
821 return;
822 }
823 catch (ClassFormatError)
824 {
825
826 }
827 catch (IndexOutOfRangeException)
828 {
829
830 }
831 catch (ByteCodeException)
832 {
833
834 }
835
836 // if we fail to parse the annotations (e.g. due to a malformed attribute), we simply keep all the constant pool entries
837 for (int i = 0; i < inUse.Length; i++)
838 inUse[i] = true;
839 }
840 }
841
842 static void MarkConstantPoolUsageForAnnotation(ref readonly IKVM.ByteCode.Decoding.Annotation annotation, bool[] inUse)
843 {
844 inUse[annotation.Type.Slot] = true;
845
846 for (int i = 0; i < annotation.Elements.Count; i++)
847 {
848 ref readonly var element = ref annotation.Elements[i];
849 ref readonly var elementValue = ref element.Value;
850 inUse[element.Name.Slot] = true;
851 MarkConstantPoolUsageForAnnotationComponentValue(in elementValue, inUse);
852 }
853 }
854
855 static void MarkConstantPoolUsageForTypeAnnotation(ref readonly TypeAnnotation annotation, bool[] inUse)
856 {
857 inUse[annotation.Type.Slot] = true;
858
859 for (int i = 0; i < annotation.Elements.Count; i++)
860 {
861 ref readonly var element = ref annotation.Elements[i];
862 ref readonly var elementValue = ref element.Value;
863 inUse[element.Name.Slot] = true;
864 MarkConstantPoolUsageForAnnotationComponentValue(in elementValue, inUse);
865 }
866 }
867
868 static void MarkConstantPoolUsageForAnnotationComponentValue(ref readonly ElementValue element, bool[] inUse)
869 {
870 switch (element.Kind)
871 {
872 case ElementValueKind.Boolean:
873 case ElementValueKind.Byte:
874 case ElementValueKind.Char:
875 case ElementValueKind.Double:
876 case ElementValueKind.Float:
877 case ElementValueKind.Integer:
878 case ElementValueKind.Long:
879 case ElementValueKind.Short:
880 case ElementValueKind.String:
881 inUse[((ConstantElementValue)element).Handle.Slot] = true;
882 break;
883 case ElementValueKind.Class:
884 inUse[((ClassElementValue)element).Class.Slot] = true;
885 break;
886 case ElementValueKind.Enum:
887 var enum_ = (EnumElementValue)element;
888 inUse[enum_.TypeName.Slot] = true;
889 inUse[enum_.ConstantName.Slot] = true;
890 break;
891 case ElementValueKind.Annotation:
892 var annotation = ((AnnotationElementValue)element).Annotation;
893 MarkConstantPoolUsageForAnnotation(ref annotation, inUse);
894 break;
895 case ElementValueKind.Array:
896 foreach (ref readonly var i in (ArrayElementValue)element)
897 MarkConstantPoolUsageForAnnotationComponentValue(in i, inUse);
898 break;
899 }
900 }
901
902 private bool EmitInterlockedCompareAndSet(RuntimeJavaMethod method, string fieldName, CodeEmitter ilGenerator)
903 {
904 if (method.ReturnType != context.PrimitiveJavaTypeFactory.BOOLEAN)
905 return false;
906
907 var parameters = method.GetParameters();
908 RuntimeJavaType target;
909 int firstValueIndex;
910
911 if (method.IsStatic)
912 {
913 if (parameters.Length != 3)
914 return false;
915
916 target = parameters[0];
917 firstValueIndex = 1;
918 }
919 else
920 {
921 if (parameters.Length != 2)
922 return false;
923
924 target = method.DeclaringType;
925 firstValueIndex = 0;
926 }
927
928 if (target.IsUnloadable || target.IsPrimitive || target.IsNonPrimitiveValueType || target.IsGhost)
929 {
930 return false;
931 }
932
933 var fieldType = parameters[firstValueIndex];
934 if (fieldType != parameters[firstValueIndex + 1])
935 {
936 return false;
937 }
938 if (fieldType.IsUnloadable || fieldType.IsNonPrimitiveValueType || fieldType.IsGhost)
939 {
940 return false;
941 }
942 if (fieldType.IsPrimitive && fieldType != context.PrimitiveJavaTypeFactory.LONG && fieldType != context.PrimitiveJavaTypeFactory.INT)
943 {
944 return false;
945 }
946
947 RuntimeJavaField casField = null;
948 foreach (var fw in target.GetFields())
949 {
950 if (fw.Name == fieldName)
951 {
952 if (casField != null)
953 return false;
954
955 casField = fw;
956 }
957 }
958
959 if (casField == null)
960 return false;
961
962 if (casField.IsStatic)
963 return false;
964
965 casField.Link();
966 if (casField.FieldTypeWrapper != fieldType)
967 return false;
968
969 if (casField.IsPropertyAccessor)
970 return false;
971
972 if (casField.DeclaringType.TypeAsBaseType == typeBuilder.DeclaringType)
973 {
974 // allow access to fields in outer class
975 }
976 else if (!casField.IsAccessibleFrom(casField.DeclaringType, wrapper, casField.DeclaringType))
977 {
978 return false;
979 }
980
981 FieldInfo fi = casField.GetField();
982 if (fi == null)
983 {
984 return false;
985 }
986 ilGenerator.EmitLdarg(0);
987 ilGenerator.Emit(OpCodes.Ldflda, fi);
988 ilGenerator.EmitLdarg(2);
989 ilGenerator.EmitLdarg(1);
990 if (fieldType == context.PrimitiveJavaTypeFactory.LONG)
991 {
992 ilGenerator.Emit(OpCodes.Call, context.InterlockedMethods.CompareExchangeInt64);
993 }
994 else if (fieldType == context.PrimitiveJavaTypeFactory.INT)
995 {
996 ilGenerator.Emit(OpCodes.Call, context.InterlockedMethods.CompareExchangeInt32);
997 }
998 else
999 {
1000 ilGenerator.Emit(OpCodes.Call, AtomicReferenceFieldUpdaterEmitter.MakeCompareExchange(context, casField.FieldTypeWrapper.TypeAsSignatureType));
1001 }
1002 ilGenerator.EmitLdarg(1);
1003 ilGenerator.Emit(OpCodes.Ceq);
1004 ilGenerator.Emit(OpCodes.Ret);
1005 return true;
1006 }
1007#endif
1008
1009 private void AddMethodParameterInfo(ClassFile.Method m, RuntimeJavaMethod mw, MethodBuilder mb, out string[] parameterNames)
1010 {
1011 parameterNames = null;
1012 ParameterBuilder[] parameterBuilders = null;
1013
1014 if (wrapper.ClassLoader.EmitSymbols
1015#if IMPORTER
1016 || (classFile.IsPublic && (m.IsPublic || m.IsProtected))
1017 || (m.MethodParameters != null && !wrapper.ClassLoader.NoParameterReflection)
1018#endif
1019 )
1020 {
1021 parameterNames = new string[mw.GetParameters().Length];
1022 GetParameterNamesFromMP(m, parameterNames);
1023#if IMPORTER
1024 if (m.MethodParameters == null)
1025#endif
1026 {
1027 GetParameterNamesFromLVT(m, parameterNames);
1028 GetParameterNamesFromSig(m.Signature, parameterNames);
1029 }
1030#if IMPORTER
1031 wrapper.GetParameterNamesFromXml(m.Name, m.Signature, parameterNames);
1032#endif
1033 parameterBuilders = GetParameterBuilders(mb, parameterNames.Length, parameterNames);
1034 }
1035
1036#if IMPORTER
1037 if ((m.Modifiers & Modifiers.VarArgs) != 0 && !mw.HasCallerID)
1038 {
1039 parameterBuilders ??= GetParameterBuilders(mb, mw.GetParameters().Length, null);
1040 if (parameterBuilders.Length > 0)
1041 context.AttributeHelper.SetParamArrayAttribute(parameterBuilders[parameterBuilders.Length - 1]);
1042 }
1043
1044 wrapper.AddXmlMapParameterAttributes(mb, classFile.Name, m.Name, m.Signature, ref parameterBuilders);
1045#endif
1046
1047 if (m.ParameterAnnotations != null)
1048 {
1049 parameterBuilders ??= GetParameterBuilders(mb, mw.GetParameters().Length, null);
1050
1051 object[][] defs = m.ParameterAnnotations;
1052 for (int j = 0; j < defs.Length; j++)
1053 {
1054 foreach (object[] def in defs[j])
1055 {
1056 var annotation = Annotation.Load(wrapper, def);
1057 if (annotation != null)
1058 annotation.Apply(wrapper.ClassLoader, parameterBuilders[j], def);
1059 }
1060 }
1061 }
1062 }
1063
1064#if IMPORTER
1065
1066 private void AddImplementsAttribute()
1067 {
1068 var interfaces = wrapper.Interfaces;
1069 if (wrapper.BaseTypeWrapper == context.JavaBase.TypeOfJavaLangObject)
1070 {
1071 // We special case classes extending java.lang.Object to optimize the metadata encoding
1072 // for anonymous classes that implement an interface.
1073 Type[] actualInterfaces = typeBuilder.GetInterfaces();
1074 if (actualInterfaces.Length == 0)
1075 {
1076 return;
1077 }
1078 else if (actualInterfaces.Length == 1
1079 && interfaces.Length == 1
1080 && !interfaces[0].IsRemapped
1081 && interfaces[0].TypeAsBaseType == actualInterfaces[0])
1082 {
1083 // We extend java.lang.Object and implement only a single (non-remapped) interface,
1084 // in this case we can omit the ImplementAttribute since the runtime will be able
1085 // to reliable reproduce the "list" of implemented interfaces.
1086 return;
1087 }
1088 }
1089 else if (interfaces.Length == 0)
1090 {
1091 return;
1092 }
1093 context.AttributeHelper.SetImplementsAttribute(typeBuilder, interfaces);
1094 }
1095
1096 private TypeBuilder DefineNestedInteropType(string name)
1097 {
1098 ImportClassLoader ccl = wrapper.classLoader;
1099 while (!ccl.ReserveName(classFile.Name + "$" + name))
1100 {
1101 name += "_";
1102 }
1103 TypeBuilder tb = typeBuilder.DefineNestedType(name, TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.Sealed | TypeAttributes.Abstract);
1104 RegisterNestedTypeBuilder(tb);
1105 context.AttributeHelper.HideFromJava(tb);
1106 return tb;
1107 }
1108
1109 void AddInterfaceFieldsInterop(RuntimeJavaField[] fields)
1110 {
1111
1112 }
1113
1114 void AddInterfaceMethodsInterop(RuntimeJavaMethod[] methods)
1115 {
1116
1117 }
1118
1119 private void CreateDefaultMethodInterop(ref TypeBuilder tbDefaultMethods, MethodBuilder defaultMethod, RuntimeJavaMethod mw)
1120 {
1121 if (!ParametersAreAccessible(mw))
1122 {
1123 return;
1124 }
1125
1126 if (tbDefaultMethods == null)
1127 {
1128 tbDefaultMethods = DefineNestedInteropType(NestedTypeName.DefaultMethods);
1129 }
1130
1131 var mb = mw.GetDefineMethodHelper().DefineMethod(wrapper.ClassLoader.GetTypeWrapperFactory(), tbDefaultMethods, mw.Name, MethodAttributes.Public | MethodAttributes.Static, wrapper.TypeAsSignatureType, true);
1132 var ilgen = context.CodeEmitterFactory.Create(mb);
1133 if (wrapper.IsGhost)
1134 {
1135 ilgen.EmitLdarga(0);
1136 ilgen.Emit(OpCodes.Ldfld, wrapper.GhostRefField);
1137 ilgen.EmitNullCheck();
1138 ilgen.EmitLdarga(0);
1139 }
1140 else
1141 {
1142 ilgen.EmitLdarg(0);
1143 ilgen.Emit(OpCodes.Dup);
1144 ilgen.EmitNullCheck();
1145 }
1146 RuntimeJavaType[] parameters = mw.GetParameters();
1147 for (int i = 0; i < parameters.Length; i++)
1148 {
1149 ilgen.EmitLdarg(i + 1);
1150 if (!parameters[i].IsUnloadable && !parameters[i].IsPublic)
1151 {
1152 parameters[i].EmitCheckcast(ilgen);
1153 }
1154 }
1155 ilgen.Emit(OpCodes.Call, defaultMethod);
1156 ilgen.Emit(OpCodes.Ret);
1157 ilgen.DoEmit();
1158 }
1159#endif
1160
1161 private void AddInheritedDefaultInterfaceMethods(RuntimeJavaMethod[] methods)
1162 {
1163 // look at the miranda methods to see if we inherit any default interface methods
1164 for (int i = classFile.Methods.Length; i < methods.Length; i++)
1165 {
1166 if (methods[i].IsMirandaMethod)
1167 {
1168 RuntimeMirandaJavaMethod mmw = (RuntimeMirandaJavaMethod)methods[i];
1169 if (mmw.Error == null && !mmw.BaseMethod.IsAbstract)
1170 {
1171 // we inherited a default interface method, so we need to forward the miranda method to the default method
1172 MethodBuilder mb = (MethodBuilder)mmw.GetMethod();
1173 if (classFile.IsInterface)
1174 {
1175 // if we're an interface with a default miranda method, we need to create a new default method that forwards to the original
1176 mb = methods[i].GetDefineMethodHelper().DefineMethod(wrapper.ClassLoader.GetTypeWrapperFactory(),
1177 typeBuilder, NamePrefix.DefaultMethod + mb.Name, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName, typeBuilder, false);
1178 }
1179 EmitCallDefaultInterfaceMethod(mb, mmw.BaseMethod);
1180 }
1181 }
1182 }
1183 }
1184
1185 internal void EmitCallDefaultInterfaceMethod(MethodBuilder mb, RuntimeJavaMethod defaultMethod)
1186 {
1187 CodeEmitter ilgen = context.CodeEmitterFactory.Create(mb);
1188 if (defaultMethod.DeclaringType.IsGhost)
1189 {
1190 CodeEmitterLocal local = ilgen.DeclareLocal(defaultMethod.DeclaringType.TypeAsSignatureType);
1191 ilgen.Emit(OpCodes.Ldloca, local);
1192 ilgen.EmitLdarg(0);
1193 ilgen.Emit(OpCodes.Stfld, defaultMethod.DeclaringType.GhostRefField);
1194 ilgen.Emit(OpCodes.Ldloca, local);
1195 }
1196 else
1197 {
1198 ilgen.EmitLdarg(0);
1199 }
1200 for (int j = 0, count = defaultMethod.GetParameters().Length; j < count; j++)
1201 {
1202 ilgen.EmitLdarg(j + 1);
1203 }
1204 ilgen.Emit(OpCodes.Call, RuntimeDefaultInterfaceJavaMethod.GetImpl(defaultMethod));
1205 ilgen.Emit(OpCodes.Ret);
1206 ilgen.DoEmit();
1207 }
1208
1209#if IMPORTER
1210 void AddAccessStubs()
1211 {
1212 /*
1213 * There are two types of access stubs:
1214 *
1215 * Type 1 These are required when a public class extends a non-public class.
1216 * In that case we need access stubs for all public and protected members
1217 * of the non-public base classes.
1218 *
1219 * Type 2 When a public class exposes a member that contains a non-public type in
1220 * its signature, we need an access stub for that member (where we convert
1221 * the non-public type in the signature to the first public base type).
1222 * Additionally, when a public or protected final field is compiled
1223 * without -strictfinalfieldsemantics, a the field will be wrapper with a
1224 * read-only property.
1225 *
1226 * Note that type 1 access stubs may also need the type 2 signature type widening
1227 * if the signature contains non-public types.
1228 *
1229 * Type 1 access stubs are always required, because the JVM allow access to these
1230 * members via the derived class while the CLR doesn't. Historically, we've exposed
1231 * these access stubs in such a way that they are also consumable from other .NET
1232 * languages (when feasible), so we'll continue to do that for back compat.
1233 *
1234 * Type 2 access stubs are only required by the CLR when running on CLR v4 and the
1235 * caller assembly is security transparent code (level 2). We also want the access
1236 * stubs to allow other .NET languages (e.g. C#) to consume broken APIs that
1237 * (accidentally) expose these members.
1238 */
1239 AddType2FieldAccessStubs();
1240 AddType1FieldAccessStubs(wrapper);
1241 if (!wrapper.IsInterface)
1242 {
1243 int id = 0;
1244 AddType2MethodAccessStubs(ref id);
1245 AddType1MethodAccessStubs(ref id);
1246 }
1247 }
1248
1249 void AddType1FieldAccessStubs(RuntimeJavaType tw)
1250 {
1251 do
1252 {
1253 if (!tw.IsPublic)
1254 {
1255 foreach (RuntimeJavaField fw in tw.GetFields())
1256 {
1257 if ((fw.IsPublic || (fw.IsProtected && !wrapper.IsFinal)) && wrapper.GetFieldWrapper(fw.Name, fw.Signature) == fw)
1258 {
1259 GenerateAccessStub(fw, true);
1260 }
1261 }
1262 }
1263
1264 foreach (RuntimeJavaType iface in tw.Interfaces)
1265 AddType1FieldAccessStubs(iface);
1266
1267 tw = tw.BaseTypeWrapper;
1268 } while (tw != null && !tw.IsPublic);
1269 }
1270
1271 void AddType2FieldAccessStubs()
1272 {
1273 foreach (var fw in wrapper.GetFields())
1274 if (wrapper.NeedsType2AccessStub(fw))
1275 GenerateAccessStub(fw, false);
1276 }
1277
1278 void GenerateAccessStub(RuntimeJavaField fw, bool type1)
1279 {
1280 if (fw is RuntimeConstantJavaField cjf)
1281 {
1282 // constants cannot have a type 2 access stub, because constant types are always public
1283 Debug.Assert(type1);
1284
1285 var attribs = fw.IsPublic ? FieldAttributes.Public : FieldAttributes.FamORAssem;
1286 attribs |= FieldAttributes.Static | FieldAttributes.Literal;
1287
1288 // we attach the AccessStub custom modifier because the C# compiler prefers fields without custom modifiers
1289 // so if this class defines a field with the same name, that will be preferred over this one by the C# compiler
1290 var fb = typeBuilder.DefineField(fw.Name, fw.FieldTypeWrapper.TypeAsSignatureType, null, new Type[] { context.Resolver.ResolveRuntimeType(typeof(IKVM.Attributes.AccessStub).FullName).AsReflection() }, attribs);
1291 context.AttributeHelper.HideFromReflection(fb);
1292 fb.SetConstant(cjf.GetConstantValue());
1293 }
1294 else
1295 {
1296 var propType = fw.FieldTypeWrapper.TypeAsPublicSignatureType;
1297 var modopt = wrapper.GetModOpt(fw.FieldTypeWrapper, true);
1298 var pb = typeBuilder.DefineProperty(fw.Name, PropertyAttributes.None, propType, null, modopt, Type.EmptyTypes, null, null);
1299 if (type1)
1300 context.AttributeHelper.HideFromReflection(pb);
1301 else
1302 context.AttributeHelper.SetModifiers(pb, fw.Modifiers, fw.IsInternal);
1303 var attribs = fw.IsPublic ? MethodAttributes.Public : MethodAttributes.FamORAssem;
1304 attribs |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;
1305 if (fw.IsStatic)
1306 attribs |= MethodAttributes.Static;
1307
1308 // we append the IKVM.Attributes.AccessStub type to the modopt array for use in the property accessor method signature
1309 // to make sure they never conflict with any user defined methhods
1310 var modopt2 = ArrayUtil.Concat(modopt, context.Resolver.ResolveRuntimeType(typeof(IKVM.Attributes.AccessStub).FullName).AsReflection());
1311 var getter = typeBuilder.DefineMethod("get_" + fw.Name, attribs, CallingConventions.Standard, propType, null, modopt2, Type.EmptyTypes, null, null);
1312 context.AttributeHelper.HideFromJava(getter);
1313 pb.SetGetMethod(getter);
1314 var ilgen = context.CodeEmitterFactory.Create(getter);
1315 if (!fw.IsStatic)
1316 ilgen.Emit(OpCodes.Ldarg_0);
1317 fw.EmitGet(ilgen);
1318 ilgen.Emit(OpCodes.Ret);
1319 ilgen.DoEmit();
1320
1321 if (!fw.IsFinal || (!fw.IsStatic && !type1))
1322 {
1323 if (fw.IsFinal)
1324 {
1325 // we need to generate a (private) setter for final fields for reflection and serialization
1326 attribs &= ~MethodAttributes.MemberAccessMask;
1327 attribs |= MethodAttributes.Private;
1328 }
1329
1330 var setter = typeBuilder.DefineMethod("set_" + fw.Name, attribs, CallingConventions.Standard, null, null, null, new Type[] { propType }, null, new Type[][] { modopt2 });
1331 context.AttributeHelper.HideFromJava(setter);
1332 pb.SetSetMethod(setter);
1333 ilgen = context.CodeEmitterFactory.Create(setter);
1334 ilgen.Emit(OpCodes.Ldarg_0);
1335 if (!fw.IsStatic)
1336 ilgen.Emit(OpCodes.Ldarg_1);
1337
1338 // we don't do a DynamicCast if fw.FieldTypeWrapper is unloadable, because for normal unloadable fields we don't enfore the type either
1339 if (propType != fw.FieldTypeWrapper.TypeAsSignatureType)
1340 ilgen.Emit(OpCodes.Castclass, fw.FieldTypeWrapper.TypeAsSignatureType);
1341 fw.EmitSet(ilgen);
1342 ilgen.Emit(OpCodes.Ret);
1343 ilgen.DoEmit();
1344 }
1345 }
1346 }
1347
1348 void AddType1MethodAccessStubs(ref int id)
1349 {
1350 for (var tw = wrapper.BaseTypeWrapper; tw != null && !tw.IsPublic; tw = tw.BaseTypeWrapper)
1351 {
1352 foreach (var mw in tw.GetMethods())
1353 {
1354 if ((mw.IsPublic || (mw.IsProtected && !wrapper.IsFinal))
1355 && (!mw.IsAbstract || wrapper.IsAbstract)
1356 && mw.Name != StringConstants.INIT
1357 && wrapper.GetMethod(mw.Name, mw.Signature, true) == mw
1358 && ParametersAreAccessible(mw))
1359 {
1360 GenerateAccessStub(id, mw, true, true);
1361 if (!mw.IsStatic && !mw.IsFinal && !mw.IsAbstract && !wrapper.IsFinal)
1362 {
1363 GenerateAccessStub(id, mw, false, true);
1364 }
1365 id++;
1366 }
1367 }
1368 }
1369 }
1370
1371 void AddType2MethodAccessStubs(ref int id)
1372 {
1373 foreach (var mw in wrapper.GetMethods())
1374 {
1375 if (mw.HasNonPublicTypeInSignature && (mw.IsPublic || (mw.IsProtected && !wrapper.IsFinal)) && ParametersAreAccessible(mw))
1376 {
1377 GenerateAccessStub(id, mw, true, false);
1378 if (!mw.IsStatic && !mw.IsFinal && !mw.IsAbstract && mw.Name != StringConstants.INIT && !wrapper.IsFinal)
1379 GenerateAccessStub(id, mw, false, false);
1380
1381 id++;
1382 }
1383 }
1384 }
1385
1386 void GenerateAccessStub(int id, RuntimeJavaMethod mw, bool virt, bool type1)
1387 {
1388 Debug.Assert(!mw.HasCallerID);
1389
1390 var stubattribs = mw.IsPublic && virt ? MethodAttributes.Public : MethodAttributes.FamORAssem;
1391 stubattribs |= MethodAttributes.HideBySig;
1392 if (mw.IsStatic)
1393 stubattribs |= MethodAttributes.Static;
1394
1395 var parameters = mw.GetParameters();
1396 var realParameterTypes = new Type[parameters.Length];
1397 var parameterTypes = new Type[parameters.Length];
1398 var modopt = new Type[parameters.Length][];
1399 for (int i = 0; i < parameters.Length; i++)
1400 {
1401 realParameterTypes[i] = parameters[i].TypeAsSignatureType;
1402 parameterTypes[i] = parameters[i].TypeAsPublicSignatureType;
1403 modopt[i] = wrapper.GetModOpt(parameters[i], true);
1404 }
1405
1406 var returnType = mw.ReturnType.TypeAsPublicSignatureType;
1407 var modoptReturnType = ArrayUtil.Concat(wrapper.GetModOpt(mw.ReturnType, true), context.Resolver.ResolveRuntimeType(typeof(IKVM.Attributes.AccessStub).FullName).AsReflection());
1408
1409 string name;
1410 if (mw.Name == StringConstants.INIT)
1411 {
1412 name = ConstructorInfo.ConstructorName;
1413 stubattribs |= MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
1414 }
1415 else
1416 {
1417 name = virt ? (mw.Modifiers & Modifiers.Bridge) == 0 ? mw.Name : NamePrefix.Bridge + mw.Name : NamePrefix.NonVirtual + id;
1418 }
1419
1420 var mb = typeBuilder.DefineMethod(name, stubattribs, CallingConventions.Standard, returnType, null, modoptReturnType, parameterTypes, null, modopt);
1421 if (virt && type1)
1422 {
1423 context.AttributeHelper.HideFromReflection(mb);
1424 context.AttributeHelper.SetNameSig(mb, NamePrefix.AccessStub + id + "|" + mw.Name, mw.Signature);
1425 }
1426 else
1427 {
1428 context.AttributeHelper.HideFromJava(mb);
1429 if (!type1)
1430 {
1431 context.AttributeHelper.SetNameSig(mb, mw.Name, mw.Signature);
1432 }
1433 }
1434
1435 var ilgen = context.CodeEmitterFactory.Create(mb);
1436 int argpos = 0;
1437 if (!mw.IsStatic)
1438 ilgen.EmitLdarg(argpos++);
1439
1440 for (int i = 0; i < parameterTypes.Length; i++)
1441 {
1442 ilgen.EmitLdarg(argpos++);
1443
1444 // we don't need to do a DynamicCast if for unloadables, because the method itself will already do that
1445 if (parameterTypes[i] != realParameterTypes[i])
1446 ilgen.Emit(OpCodes.Castclass, realParameterTypes[i]);
1447 }
1448
1449 if (mw.IsStatic || !virt || mw.Name == StringConstants.INIT)
1450 mw.EmitCall(ilgen);
1451 else
1452 mw.EmitCallvirt(ilgen);
1453
1454 ilgen.Emit(OpCodes.Ret);
1455 ilgen.DoEmit();
1456 }
1457
1458 bool ParametersAreAccessible(RuntimeJavaMethod mw)
1459 {
1460 foreach (var tw in mw.GetParameters())
1461 if (!tw.IsAccessibleFrom(wrapper))
1462 return false;
1463
1464 return true;
1465 }
1466
1467#endif // IMPORTER
1468
1469 private void ImplementInterfaceMethodStubs(Dictionary<RuntimeJavaType, RuntimeJavaType> doneSet, RuntimeJavaType interfaceTypeWrapper, bool baseClassInterface)
1470 {
1471 Debug.Assert(interfaceTypeWrapper.IsInterface);
1472
1473 // make sure we don't do the same method twice
1474 if (doneSet.ContainsKey(interfaceTypeWrapper))
1475 {
1476 return;
1477 }
1478 doneSet.Add(interfaceTypeWrapper, interfaceTypeWrapper);
1479 foreach (RuntimeJavaMethod method in interfaceTypeWrapper.GetMethods())
1480 {
1481 if (!method.IsStatic && method.IsPublic && !method.IsDynamicOnly)
1482 {
1483 ImplementInterfaceMethodStubImpl(method, baseClassInterface);
1484 }
1485 }
1486 RuntimeJavaType[] interfaces = interfaceTypeWrapper.Interfaces;
1487 for (int i = 0; i < interfaces.Length; i++)
1488 {
1489 ImplementInterfaceMethodStubs(doneSet, interfaces[i], baseClassInterface);
1490 }
1491 }
1492
1493 void ImplementInterfaceMethodStubImpl(RuntimeJavaMethod ifmethod, bool baseClassInterface)
1494 {
1495 // we're mangling the name to prevent subclasses from accidentally overriding this method and to
1496 // prevent clashes with overloaded method stubs that are erased to the same signature (e.g. unloadable types and ghost arrays)
1497 // HACK the signature and name are the wrong way around to work around a C++/CLI bug (apparantely it looks looks at the last n
1498 // characters of the method name, or something bizarre like that)
1499 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=234167
1500 var mangledName = ifmethod.DeclaringType.Name + "/" + ifmethod.Signature + ifmethod.Name;
1501 RuntimeJavaMethod mce = null;
1502
1503 var lookup = (RuntimeJavaType)wrapper;
1504 while (lookup != null)
1505 {
1506 mce = lookup.GetMethod(ifmethod.Name, ifmethod.Signature, true);
1507 if (mce == null || !mce.IsStatic)
1508 break;
1509
1510 lookup = mce.DeclaringType.BaseTypeWrapper;
1511 }
1512
1513 if (mce != null)
1514 {
1515 Debug.Assert(!mce.HasCallerID);
1516 if (mce.DeclaringType != wrapper)
1517 {
1518 // check the loader constraints
1519 var error = false;
1520 if (mce.ReturnType != ifmethod.ReturnType && !mce.ReturnType.IsUnloadable && !ifmethod.ReturnType.IsUnloadable)
1521 error = true;
1522
1523 var mceparams = mce.GetParameters();
1524 var ifparams = ifmethod.GetParameters();
1525 for (int i = 0; i < mceparams.Length; i++)
1526 {
1527 if (mceparams[i] != ifparams[i] && !mceparams[i].IsUnloadable && !ifparams[i].IsUnloadable)
1528 {
1529 error = true;
1530 break;
1531 }
1532 }
1533
1534 if (error)
1535 {
1536 var mb = DefineInterfaceStubMethod(mangledName, ifmethod);
1537 context.AttributeHelper.HideFromJava(mb);
1538 var ilgen = context.CodeEmitterFactory.Create(mb);
1539 ilgen.EmitThrow("java.lang.LinkageError", wrapper.Name + "." + ifmethod.Name + ifmethod.Signature);
1540 ilgen.DoEmit();
1541 typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod.GetMethod());
1542 return;
1543 }
1544 }
1545
1546 if (!mce.IsPublic && !mce.IsInternal)
1547 {
1548 // NOTE according to the ECMA spec it isn't legal for a privatescope method to be virtual, but this works and
1549 // it makes sense, so I hope the spec is wrong
1550 // UPDATE unfortunately, according to Serge Lidin the spec is correct, and it is not allowed to have virtual privatescope
1551 // methods. Sigh! So I have to use private methods and mangle the name
1552
1553 var mb = DefineInterfaceStubMethod(NamePrefix.Incomplete + mangledName, ifmethod);
1554 context.AttributeHelper.HideFromJava(mb);
1555 var ilgen = context.CodeEmitterFactory.Create(mb);
1556 ilgen.EmitThrow("java.lang.IllegalAccessError", wrapper.Name + "." + ifmethod.Name + ifmethod.Signature);
1557 ilgen.DoEmit();
1558 typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod.GetMethod());
1559 wrapper.SetHasIncompleteInterfaceImplementation();
1560 }
1561 else if (mce.GetMethod() == null || mce.RealName != ifmethod.RealName || mce.IsInternal || !ReflectUtil.IsSameAssembly(mce.DeclaringType.TypeAsTBD, typeBuilder) || CheckRequireOverrideStub(mce, ifmethod))
1562 {
1563 // NOTE methods inherited from base classes in a different assembly do *not* automatically implement
1564 // interface methods, so we have to generate a stub here that doesn't do anything but call the base
1565 // implementation
1566 wrapper.GenerateOverrideStub(typeBuilder, ifmethod, null, mce);
1567 }
1568 else if (baseClassInterface && mce.DeclaringType == wrapper)
1569 {
1570 typeBuilder.DefineMethodOverride((MethodInfo)mce.GetMethod(), (MethodInfo)ifmethod.GetMethod());
1571 }
1572 }
1573 else
1574 {
1575 if (!wrapper.IsAbstract || (!baseClassInterface && wrapper.GetMethod(ifmethod.Name, ifmethod.Signature, false) != null))
1576 {
1577 // the type doesn't implement the interface method and isn't abstract either. The JVM allows this, but the CLR doesn't,
1578 // so we have to create a stub method that throws an AbstractMethodError
1579 var mb = DefineInterfaceStubMethod(NamePrefix.Incomplete + mangledName, ifmethod);
1580 context.AttributeHelper.HideFromJava(mb);
1581 var ilgen = context.CodeEmitterFactory.Create(mb);
1582 ilgen.EmitThrow("java.lang.AbstractMethodError", wrapper.Name + "." + ifmethod.Name + ifmethod.Signature);
1583 ilgen.DoEmit();
1584 typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod.GetMethod());
1585 wrapper.SetHasIncompleteInterfaceImplementation();
1586 wrapper.EmitLevel4Warning(HardError.AbstractMethodError, wrapper.Name + "." + ifmethod.Name + ifmethod.Signature);
1587 }
1588 }
1589 }
1590
1591 MethodBuilder DefineInterfaceStubMethod(string name, RuntimeJavaMethod mw)
1592 {
1593 return mw.GetDefineMethodHelper().DefineMethod(wrapper, typeBuilder, name, MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final);
1594 }
1595
1596#if FIRST_PASS == false && IMPORTER == false
1597
1598 internal static class JniProxyBuilder
1599 {
1600
1601 readonly static ModuleBuilder mod;
1602 static int count;
1603
1607 static JniProxyBuilder()
1608 {
1609 mod = DynamicClassLoader.CreateJniProxyModuleBuilder();
1610 var cab = new CustomAttributeBuilder(JVM.Context.Resolver.ResolveRuntimeType(typeof(JavaModuleAttribute).FullName).GetConstructor([]).AsReflection(), new object[0]);
1611 mod.SetCustomAttribute(cab);
1612 }
1613
1614 internal static void Generate(RuntimeByteCodeJavaType.FinishContext context, CodeEmitter ilGenerator, RuntimeByteCodeJavaType wrapper, RuntimeJavaMethod mw, TypeBuilder typeBuilder, ClassFile classFile, ClassFile.Method m, RuntimeJavaType[] args)
1615 {
1616 TypeBuilder tb = mod.DefineType("__<jni>" + System.Threading.Interlocked.Increment(ref count), TypeAttributes.Public | TypeAttributes.Class);
1617 int instance = m.IsStatic ? 0 : 1;
1618 Type[] argTypes = new Type[args.Length + instance + 1];
1619 if (instance != 0)
1620 {
1621 argTypes[0] = typeof(object);
1622 }
1623 for (int i = 0; i < args.Length; i++)
1624 {
1625 // NOTE we take a shortcut here by assuming that all "special" types (i.e. ghost or value types)
1626 // are public and so we can get away with replacing all other types with object.
1627 argTypes[i + instance] = !args[i].IsUnloadable && (args[i].IsPrimitive || args[i].IsGhost || args[i].IsNonPrimitiveValueType) ? args[i].TypeAsSignatureType : typeof(object);
1628 }
1629 argTypes[argTypes.Length - 1] = context.context.JavaBase.TypeOfIkvmInternalCallerID.TypeAsSignatureType;
1630 Type retType = !mw.ReturnType.IsUnloadable && (mw.ReturnType.IsPrimitive || mw.ReturnType.IsGhost || mw.ReturnType.IsNonPrimitiveValueType) ? mw.ReturnType.TypeAsSignatureType : typeof(object);
1631 MethodBuilder mb = tb.DefineMethod("method", MethodAttributes.Public | MethodAttributes.Static, retType, argTypes);
1632 context.context.AttributeHelper.HideFromJava(mb);
1633 CodeEmitter ilgen = context.context.CodeEmitterFactory.Create(mb);
1634 new JniBuilder(context.context).Generate(context, ilgen, wrapper, mw, tb, classFile, m, args, true);
1635 ilgen.DoEmit();
1636 tb.CreateType();
1637 for (int i = 0; i < argTypes.Length - 1; i++)
1638 {
1639 ilGenerator.EmitLdarg(i);
1640 }
1641 context.EmitCallerID(ilGenerator, m.IsLambdaFormCompiled);
1642 ilGenerator.Emit(OpCodes.Call, mb);
1643 if (!mw.ReturnType.IsUnloadable && !mw.ReturnType.IsPrimitive && !mw.ReturnType.IsGhost && !mw.ReturnType.IsNonPrimitiveValueType)
1644 {
1645 ilGenerator.Emit(OpCodes.Castclass, mw.ReturnType.TypeAsSignatureType);
1646 }
1647 ilGenerator.Emit(OpCodes.Ret);
1648 }
1649 }
1650#endif
1651
1652 class JniBuilder
1653 {
1654
1655 readonly RuntimeContext context;
1656
1661 public JniBuilder(RuntimeContext context)
1662 {
1663 this.context = context ?? throw new ArgumentNullException(nameof(context));
1664 }
1665
1666 Type LocalRefStructType => context.Resolver.ResolveRuntimeType("IKVM.Runtime.JNI.JNIFrame").AsReflection();
1667
1668 MethodInfo JniFuncPtrMethod => LocalRefStructType.GetMethod("GetFuncPtr");
1669
1670 MethodInfo EnterLocalRefStructMethod => LocalRefStructType.GetMethod("Enter");
1671
1672 MethodInfo LeaveLocalRefStructMethod => LocalRefStructType.GetMethod("Leave");
1673
1674 MethodInfo MakeLocalRefMethod => LocalRefStructType.GetMethod("MakeLocalRef");
1675
1676 MethodInfo UnwrapLocalRefMethod => LocalRefStructType.GetMethod("UnwrapLocalRef");
1677
1678 MethodInfo WriteLineMethod => context.Resolver.ResolveCoreType(typeof(Console).FullName).AsReflection().GetMethod("WriteLine", [context.Types.Object]);
1679
1680 MethodInfo MonitorEnterMethod => context.Resolver.ResolveCoreType(typeof(System.Threading.Monitor).FullName).AsReflection().GetMethod("Enter", [context.Types.Object]);
1681
1682 MethodInfo MonitorExitMethod => context.Resolver.ResolveCoreType(typeof(System.Threading.Monitor).FullName).AsReflection().GetMethod("Exit", [context.Types.Object]);
1683
1684 internal void Generate(RuntimeByteCodeJavaType.FinishContext context, CodeEmitter ilGenerator, RuntimeByteCodeJavaType wrapper, RuntimeJavaMethod mw, TypeBuilder typeBuilder, ClassFile classFile, ClassFile.Method m, RuntimeJavaType[] args, bool thruProxy)
1685 {
1686 CodeEmitterLocal syncObject = null;
1687 if (m.IsSynchronized && m.IsStatic)
1688 {
1689 wrapper.EmitClassLiteral(ilGenerator);
1690 ilGenerator.Emit(OpCodes.Dup);
1691 syncObject = ilGenerator.DeclareLocal(context.context.Types.Object);
1692 ilGenerator.Emit(OpCodes.Stloc, syncObject);
1693 ilGenerator.Emit(OpCodes.Call, MonitorEnterMethod);
1694 ilGenerator.BeginExceptionBlock();
1695 }
1696
1697 var sig = m.Signature.Replace('.', '/');
1698 // TODO use/unify JNI.METHOD_PTR_FIELD_PREFIX
1699 var methodPtr = typeBuilder.DefineField("__<jniptr>" + m.Name + sig, context.context.Types.IntPtr, FieldAttributes.Static | FieldAttributes.PrivateScope);
1700 var localRefStruct = ilGenerator.DeclareLocal(LocalRefStructType);
1701 ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
1702 ilGenerator.Emit(OpCodes.Initobj, LocalRefStructType);
1703 ilGenerator.Emit(OpCodes.Ldsfld, methodPtr);
1704 var oklabel = ilGenerator.DefineLabel();
1705 ilGenerator.EmitBrtrue(oklabel);
1706
1707 if (thruProxy)
1708 ilGenerator.EmitLdarg(args.Length + (mw.IsStatic ? 0 : 1));
1709 else
1710 context.EmitCallerID(ilGenerator, m.IsLambdaFormCompiled);
1711 ilGenerator.Emit(OpCodes.Ldstr, classFile.Name.Replace('.', '/'));
1712 ilGenerator.Emit(OpCodes.Ldstr, m.Name);
1713 ilGenerator.Emit(OpCodes.Ldstr, sig);
1714 ilGenerator.Emit(OpCodes.Call, JniFuncPtrMethod);
1715 ilGenerator.Emit(OpCodes.Stsfld, methodPtr);
1716 ilGenerator.MarkLabel(oklabel);
1717 ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
1718 if (thruProxy)
1719 ilGenerator.EmitLdarg(args.Length + (mw.IsStatic ? 0 : 1));
1720 else
1721 context.EmitCallerID(ilGenerator, m.IsLambdaFormCompiled);
1722 ilGenerator.Emit(OpCodes.Call, EnterLocalRefStructMethod);
1723
1724 var jnienv = ilGenerator.DeclareLocal(context.context.Types.IntPtr);
1725 ilGenerator.Emit(OpCodes.Stloc, jnienv);
1726
1727 ilGenerator.BeginExceptionBlock();
1728 var retTypeWrapper = mw.ReturnType;
1729 if (retTypeWrapper.IsUnloadable || !retTypeWrapper.IsPrimitive)
1730 {
1731 // this one is for use after we return from "calli"
1732 ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
1733 }
1734
1735 ilGenerator.Emit(OpCodes.Ldloc, jnienv);
1736
1737 var modargs = new Type[args.Length + 2];
1738 modargs[0] = context.context.Types.IntPtr;
1739 modargs[1] = context.context.Types.IntPtr;
1740 for (int i = 0; i < args.Length; i++)
1741 modargs[i + 2] = args[i].TypeAsSignatureType;
1742 int add = 0;
1743 if (!m.IsStatic)
1744 {
1745 ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
1746 ilGenerator.Emit(OpCodes.Ldarg_0);
1747 ilGenerator.Emit(OpCodes.Call, MakeLocalRefMethod);
1748 add = 1;
1749 }
1750 else
1751 {
1752 ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
1753 wrapper.EmitClassLiteral(ilGenerator);
1754 ilGenerator.Emit(OpCodes.Call, MakeLocalRefMethod);
1755 }
1756
1757 for (int j = 0; j < args.Length; j++)
1758 {
1759 if (args[j].IsUnloadable || !args[j].IsPrimitive)
1760 {
1761 ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
1762 if (!args[j].IsUnloadable && args[j].IsNonPrimitiveValueType)
1763 {
1764 ilGenerator.EmitLdarg(j + add);
1765 args[j].EmitBox(ilGenerator);
1766 }
1767 else if (!args[j].IsUnloadable && args[j].IsGhost)
1768 {
1769 ilGenerator.EmitLdarga(j + add);
1770 ilGenerator.Emit(OpCodes.Ldfld, args[j].GhostRefField);
1771 }
1772 else
1773 {
1774 ilGenerator.EmitLdarg(j + add);
1775 }
1776 ilGenerator.Emit(OpCodes.Call, MakeLocalRefMethod);
1777 modargs[j + 2] = context.context.Types.IntPtr;
1778 }
1779 else
1780 {
1781 ilGenerator.EmitLdarg(j + add);
1782 }
1783 }
1784
1785 ilGenerator.Emit(OpCodes.Ldsfld, methodPtr);
1786
1787 Type realRetType;
1788 if (retTypeWrapper == context.Context.PrimitiveJavaTypeFactory.BOOLEAN)
1789 realRetType = context.Context.Types.Byte;
1790 else if (retTypeWrapper.IsPrimitive)
1791 realRetType = retTypeWrapper.TypeAsSignatureType;
1792 else
1793 realRetType = context.Context.Types.IntPtr;
1794 ilGenerator.EmitCalli(OpCodes.Calli, System.Runtime.InteropServices.CallingConvention.StdCall, realRetType, modargs);
1795
1796 CodeEmitterLocal retValue = null;
1797 if (retTypeWrapper != context.Context.PrimitiveJavaTypeFactory.VOID)
1798 {
1799 if (retTypeWrapper.IsUnloadable)
1800 {
1801 ilGenerator.Emit(OpCodes.Call, UnwrapLocalRefMethod);
1802 }
1803 else if (!retTypeWrapper.IsPrimitive)
1804 {
1805 ilGenerator.Emit(OpCodes.Call, UnwrapLocalRefMethod);
1806 if (retTypeWrapper.IsNonPrimitiveValueType)
1807 {
1808 retTypeWrapper.EmitUnbox(ilGenerator);
1809 }
1810 else if (retTypeWrapper.IsGhost)
1811 {
1812 var ghost = ilGenerator.DeclareLocal(retTypeWrapper.TypeAsSignatureType);
1813 var obj = ilGenerator.DeclareLocal(context.Context.Types.Object);
1814 ilGenerator.Emit(OpCodes.Stloc, obj);
1815 ilGenerator.Emit(OpCodes.Ldloca, ghost);
1816 ilGenerator.Emit(OpCodes.Ldloc, obj);
1817 ilGenerator.Emit(OpCodes.Stfld, retTypeWrapper.GhostRefField);
1818 ilGenerator.Emit(OpCodes.Ldloc, ghost);
1819 }
1820 else
1821 {
1822 ilGenerator.Emit(OpCodes.Castclass, retTypeWrapper.TypeAsTBD);
1823 }
1824 }
1825
1826 retValue = ilGenerator.DeclareLocal(retTypeWrapper.TypeAsSignatureType);
1827 ilGenerator.Emit(OpCodes.Stloc, retValue);
1828 }
1829
1830 var retLabel = ilGenerator.DefineLabel();
1831 ilGenerator.EmitLeave(retLabel);
1832 ilGenerator.BeginCatchBlock(context.context.Types.Object);
1833 ilGenerator.Emit(OpCodes.Ldstr, "*** exception in native code ***");
1834 ilGenerator.Emit(OpCodes.Call, WriteLineMethod);
1835 ilGenerator.Emit(OpCodes.Call, WriteLineMethod);
1836 ilGenerator.Emit(OpCodes.Rethrow);
1837 ilGenerator.BeginFinallyBlock();
1838 ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
1839 ilGenerator.Emit(OpCodes.Call, LeaveLocalRefStructMethod);
1840 ilGenerator.Emit(OpCodes.Endfinally);
1841 ilGenerator.EndExceptionBlock();
1842 if (m.IsSynchronized && m.IsStatic)
1843 {
1844 ilGenerator.BeginFinallyBlock();
1845 ilGenerator.Emit(OpCodes.Ldloc, syncObject);
1846 ilGenerator.Emit(OpCodes.Call, MonitorExitMethod);
1847 ilGenerator.Emit(OpCodes.Endfinally);
1848 ilGenerator.EndExceptionBlock();
1849 }
1850 ilGenerator.MarkLabel(retLabel);
1851 if (retTypeWrapper != context.Context.PrimitiveJavaTypeFactory.VOID)
1852 ilGenerator.Emit(OpCodes.Ldloc, retValue);
1853
1854 ilGenerator.Emit(OpCodes.Ret);
1855 }
1856 }
1857
1858#if IMPORTER
1859
1860 void EmitCallerIDStub(RuntimeJavaMethod mw, string[] parameterNames)
1861 {
1862 // we don't need to support custom modifiers, because there aren't any callerid methods that have parameter types that require a custom modifier
1863 var parameters = mw.GetParameters();
1864 var parameterTypes = new Type[parameters.Length];
1865 for (int i = 0; i < parameterTypes.Length; i++)
1866 parameterTypes[i] = parameters[i].TypeAsSignatureType;
1867
1868 var attribs = MethodAttributes.HideBySig;
1869 int argcount = parameterTypes.Length;
1870 if (mw.IsStatic)
1871 {
1872 attribs |= MethodAttributes.Static;
1873 }
1874 else
1875 {
1876 argcount++;
1877 }
1878 if (mw.IsPublic)
1879 {
1880 attribs |= MethodAttributes.Public;
1881 }
1882 else if (mw.IsProtected)
1883 {
1884 attribs |= MethodAttributes.FamORAssem;
1885 }
1886 else if (mw.IsPrivate)
1887 {
1888 attribs |= MethodAttributes.Private;
1889 }
1890 else
1891 {
1892 attribs |= MethodAttributes.Assembly;
1893 }
1894
1895 var mb = typeBuilder.DefineMethod(mw.Name, attribs, mw.ReturnType.TypeAsSignatureType, parameterTypes);
1896 context.AttributeHelper.HideFromJava(mb);
1897 mb.SetImplementationFlags(MethodImplAttributes.NoInlining);
1898
1899 var ilgen = context.CodeEmitterFactory.Create(mb);
1900 for (int i = 0; i < argcount; i++)
1901 {
1902 if (parameterNames != null && (mw.IsStatic || i > 0))
1903 {
1904 var pb = mb.DefineParameter(mw.IsStatic ? i + 1 : i, ParameterAttributes.None, parameterNames[mw.IsStatic ? i : i - 1]);
1905 if (i == argcount - 1 && (mw.Modifiers & Modifiers.VarArgs) != 0)
1906 context.AttributeHelper.SetParamArrayAttribute(pb);
1907 }
1908
1909 ilgen.EmitLdarg(i);
1910 }
1911 ilgen.Emit(OpCodes.Ldc_I4_1);
1912 ilgen.Emit(OpCodes.Ldc_I4_0);
1913 ilgen.Emit(OpCodes.Newobj, context.Resolver.ResolveCoreType(typeof(StackFrame).FullName).AsReflection().GetConstructor(new Type[] { context.Types.Int32, context.Types.Boolean }));
1914 var callerID = context.JavaBase.TypeOfIkvmInternalCallerID.GetMethod("create", "(Lcli.System.Diagnostics.StackFrame;)Likvm.internal.CallerID;", false);
1915 callerID.Link();
1916 callerID.EmitCall(ilgen);
1917 if (mw.IsStatic)
1918 mw.EmitCall(ilgen);
1919 else
1920 mw.EmitCallvirt(ilgen);
1921 ilgen.Emit(OpCodes.Ret);
1922 ilgen.DoEmit();
1923 }
1924
1925#endif // IMPORTER
1926
1927 void ImplementInterfaces(RuntimeJavaType[] interfaces, List<RuntimeJavaType> interfaceList)
1928 {
1929 foreach (var iface in interfaces)
1930 {
1931 if (!interfaceList.Contains(iface))
1932 {
1933 interfaceList.Add(iface);
1934 if (!iface.IsAccessibleFrom(wrapper))
1935 {
1936 continue;
1937 }
1938 // NOTE we're using TypeAsBaseType for the interfaces!
1939 typeBuilder.AddInterfaceImplementation(iface.TypeAsBaseType);
1940#if IMPORTER
1941 if (!wrapper.IsInterface)
1942 {
1943 // look for "magic" interfaces that imply a .NET interface
1944 if (iface.ClassLoader == context.JavaBase.TypeOfJavaLangObject.ClassLoader)
1945 {
1946 if (iface.Name == "java.lang.Iterable" && !wrapper.ImplementsInterface(context.ClassLoaderFactory.GetJavaTypeFromType(context.Resolver.ResolveCoreType(typeof(System.Collections.IEnumerable).FullName).AsReflection())))
1947 {
1948 var enumeratorType = context.ClassLoaderFactory.GetBootstrapClassLoader().TryLoadClassByName("ikvm.lang.IterableEnumerator");
1949 if (enumeratorType != null)
1950 {
1951 typeBuilder.AddInterfaceImplementation(context.Resolver.ResolveCoreType(typeof(System.Collections.IEnumerable).FullName).AsReflection());
1952 // FXBUG we're using the same method name as the C# compiler here because both the .NET and Mono implementations of Xml serialization depend on this method name
1953 var mb = typeBuilder.DefineMethod("System.Collections.IEnumerable.GetEnumerator", MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.SpecialName, context.Resolver.ResolveCoreType(typeof(System.Collections.IEnumerator).FullName).AsReflection(), Type.EmptyTypes);
1954 context.AttributeHelper.HideFromJava(mb);
1955 typeBuilder.DefineMethodOverride(mb, context.Resolver.ResolveCoreType(typeof(System.Collections.IEnumerable).FullName).GetMethod("GetEnumerator").AsReflection());
1956 var ilgen = context.CodeEmitterFactory.Create(mb);
1957 ilgen.Emit(OpCodes.Ldarg_0);
1958 var mw = enumeratorType.GetMethod("<init>", "(Ljava.lang.Iterable;)V", false);
1959 mw.Link();
1960 mw.EmitNewobj(ilgen);
1961 ilgen.Emit(OpCodes.Ret);
1962 ilgen.DoEmit();
1963 }
1964 }
1965 }
1966 // if we implement a ghost interface, add an implicit conversion to the ghost reference value type
1967 if (iface.IsGhost && wrapper.IsPublic)
1968 {
1969 var mb = typeBuilder.DefineMethod("op_Implicit", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName, iface.TypeAsSignatureType, new Type[] { wrapper.TypeAsSignatureType });
1970 context.AttributeHelper.HideFromJava(mb);
1971 var ilgen = context.CodeEmitterFactory.Create(mb);
1972 var local = ilgen.DeclareLocal(iface.TypeAsSignatureType);
1973 ilgen.Emit(OpCodes.Ldloca, local);
1974 ilgen.Emit(OpCodes.Ldarg_0);
1975 ilgen.Emit(OpCodes.Stfld, iface.GhostRefField);
1976 ilgen.Emit(OpCodes.Ldloca, local);
1977 ilgen.Emit(OpCodes.Ldobj, iface.TypeAsSignatureType);
1978 ilgen.Emit(OpCodes.Ret);
1979 ilgen.DoEmit();
1980 }
1981 }
1982#endif // IMPORTER
1983 // NOTE we're recursively "implementing" all interfaces that we inherit from the interfaces we implement.
1984 // The C# compiler also does this and the Compact Framework requires it.
1985 ImplementInterfaces(iface.Interfaces, interfaceList);
1986 }
1987 }
1988 }
1989
1990 void AddUnsupportedAbstractMethods()
1991 {
1992 foreach (var mb in wrapper.BaseTypeWrapper.TypeAsBaseType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
1993 if (RuntimeManagedJavaType.IsUnsupportedAbstractMethod(mb))
1994 GenerateUnsupportedAbstractMethodStub(mb);
1995
1996 var h = new Dictionary<MethodBase, MethodBase>();
1997 var tw = (RuntimeJavaType)wrapper;
1998 while (tw != null)
1999 {
2000 foreach (var iface in tw.Interfaces)
2001 {
2002 foreach (var mb in iface.TypeAsBaseType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
2003 {
2004 if (!h.ContainsKey(mb))
2005 {
2006 h.Add(mb, mb);
2007 if (RuntimeManagedJavaType.IsUnsupportedAbstractMethod(mb))
2008 GenerateUnsupportedAbstractMethodStub(mb);
2009 }
2010 }
2011 }
2012
2013 tw = tw.BaseTypeWrapper;
2014 }
2015 }
2016
2017 void GenerateUnsupportedAbstractMethodStub(MethodBase mb)
2018 {
2019 var parameters = mb.GetParameters();
2020 var parameterTypes = new Type[parameters.Length];
2021 for (int i = 0; i < parameters.Length; i++)
2022 parameterTypes[i] = parameters[i].ParameterType;
2023
2024 var attr = MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Private;
2025 var m = typeBuilder.DefineMethod("__<unsupported>" + mb.DeclaringType.FullName + "/" + mb.Name, attr, ((MethodInfo)mb).ReturnType, parameterTypes);
2026 if (mb.IsGenericMethodDefinition)
2027 CopyGenericArguments(mb, m);
2028
2029 var ilgen = context.CodeEmitterFactory.Create(m);
2030 ilgen.EmitThrow("java.lang.AbstractMethodError", "Method " + mb.DeclaringType.FullName + "." + mb.Name + " is unsupported by IKVM.");
2031 ilgen.DoEmit();
2032 typeBuilder.DefineMethodOverride(m, (MethodInfo)mb);
2033 }
2034
2035 void CopyGenericArguments(MethodBase mi, MethodBuilder mb)
2036 {
2037 var genericParameters = mi.GetGenericArguments();
2038 var genParamNames = new string[genericParameters.Length];
2039 for (int i = 0; i < genParamNames.Length; i++)
2040 genParamNames[i] = genericParameters[i].Name;
2041
2042 var genParamBuilders = mb.DefineGenericParameters(genParamNames);
2043 for (int i = 0; i < genParamBuilders.Length; i++)
2044 {
2045 // NOTE apparently we don't need to set the interface constraints
2046 // (and if we do, it fails for some reason)
2047 if (genericParameters[i].BaseType != context.Types.Object)
2048 genParamBuilders[i].SetBaseTypeConstraint(genericParameters[i].BaseType);
2049
2050 genParamBuilders[i].SetGenericParameterAttributes(genericParameters[i].GenericParameterAttributes);
2051 }
2052 }
2053
2054 void CompileConstructorBody(FinishContext context, CodeEmitter ilGenerator, int methodIndex)
2055 {
2056 var methods = wrapper.GetMethods();
2057 var m = classFile.Methods[methodIndex];
2058
2059#if IMPORTER
2060 // do we have an implementation in map.xml?
2061 if (wrapper.EmitMapXmlMethodPrologueAndOrBody(ilGenerator, classFile, m))
2062 {
2063 ilGenerator.DoEmit();
2064 return;
2065 }
2066#endif
2067 var nonLeaf = false;
2068 Compiler.Compile(context, host, wrapper, methods[methodIndex], classFile, m, ilGenerator, ref nonLeaf);
2069 ilGenerator.DoEmit();
2070#if IMPORTER
2071 ilGenerator.EmitLineNumberTable((MethodBuilder)methods[methodIndex].GetMethod());
2072#else // IMPORTER
2073 var linenumbers = ilGenerator.GetLineNumberTable();
2074 if (linenumbers != null)
2075 {
2076 if (wrapper.lineNumberTables == null)
2077 wrapper.lineNumberTables = new byte[methods.Length][];
2078
2079 wrapper.lineNumberTables[methodIndex] = linenumbers;
2080 }
2081#endif // IMPORTER
2082 }
2083
2084 static bool IsCompatibleArgList(RuntimeJavaType[] caller, RuntimeJavaType[] callee)
2085 {
2086 if (caller.Length == callee.Length)
2087 {
2088 for (int i = 0; i < caller.Length; i++)
2089 {
2090 if (caller[i].IsUnloadable || callee[i].IsUnloadable)
2091 return false;
2092 if (!caller[i].IsAssignableTo(callee[i]))
2093 return false;
2094 }
2095
2096 return true;
2097 }
2098
2099 return false;
2100 }
2101
2102 void EmitCallerIDInitialization(CodeEmitter ilGenerator, FieldInfo callerIDField)
2103 {
2104 var tw = context.JavaBase.TypeOfIkvmInternalCallerID;
2105 if (tw.InternalsVisibleTo(wrapper))
2106 {
2107 var create = tw.GetMethod("create", "(Lcli.System.RuntimeTypeHandle;)Likvm.internal.CallerID;", false);
2108 ilGenerator.Emit(OpCodes.Ldtoken, this.typeBuilder);
2109 create.Link();
2110 create.EmitCall(ilGenerator);
2111 }
2112 else
2113 {
2114 RegisterNestedTypeBuilder(EmitCreateCallerID(context, typeBuilder, ilGenerator));
2115 }
2116
2117 ilGenerator.Emit(OpCodes.Stsfld, callerIDField);
2118 }
2119
2120 internal static TypeBuilder EmitCreateCallerID(RuntimeContext context, TypeBuilder typeBuilder, CodeEmitter ilGenerator)
2121 {
2122 var tw = context.JavaBase.TypeOfIkvmInternalCallerID;
2123 var typeCallerID = typeBuilder.DefineNestedType(NestedTypeName.CallerID, TypeAttributes.Sealed | TypeAttributes.NestedPrivate, tw.TypeAsBaseType);
2124 var cb = ReflectUtil.DefineConstructor(typeCallerID, MethodAttributes.Assembly, null);
2125 var ctorIlgen = context.CodeEmitterFactory.Create(cb);
2126 ctorIlgen.Emit(OpCodes.Ldarg_0);
2127 var mw = tw.GetMethod("<init>", "()V", false);
2128 mw.Link();
2129 mw.EmitCall(ctorIlgen);
2130 ctorIlgen.Emit(OpCodes.Ret);
2131 ctorIlgen.DoEmit();
2132 ilGenerator.Emit(OpCodes.Newobj, cb);
2133 return typeCallerID;
2134 }
2135
2136 void EmitConstantValueInitialization(RuntimeJavaField[] fields, CodeEmitter ilGenerator)
2137 {
2138 ClassFile.Field[] flds = classFile.Fields;
2139 for (int i = 0; i < flds.Length; i++)
2140 {
2141 ClassFile.Field f = flds[i];
2142 if (f.IsStatic && !f.IsFinal)
2143 {
2144 object constant = f.ConstantValue;
2145 if (constant != null)
2146 {
2147 if (constant is int)
2148 {
2149 ilGenerator.EmitLdc_I4((int)constant);
2150 }
2151 else if (constant is bool)
2152 {
2153 ilGenerator.EmitLdc_I4((bool)constant ? 1 : 0);
2154 }
2155 else if (constant is byte)
2156 {
2157 ilGenerator.EmitLdc_I4((byte)constant);
2158 }
2159 else if (constant is char)
2160 {
2161 ilGenerator.EmitLdc_I4((char)constant);
2162 }
2163 else if (constant is short)
2164 {
2165 ilGenerator.EmitLdc_I4((short)constant);
2166 }
2167 else if (constant is long)
2168 {
2169 ilGenerator.EmitLdc_I8((long)constant);
2170 }
2171 else if (constant is double)
2172 {
2173 ilGenerator.EmitLdc_R8((double)constant);
2174 }
2175 else if (constant is float)
2176 {
2177 ilGenerator.EmitLdc_R4((float)constant);
2178 }
2179 else if (constant is string)
2180 {
2181 ilGenerator.Emit(OpCodes.Ldstr, (string)constant);
2182 }
2183 else
2184 {
2185 throw new InvalidOperationException();
2186 }
2187 fields[i].EmitSet(ilGenerator);
2188 }
2189 }
2190 }
2191 }
2192
2193 internal MethodBuilder DefineThreadLocalType()
2194 {
2195 var threadLocal = context.ClassLoaderFactory.LoadClassCritical("ikvm.internal.IntrinsicThreadLocal");
2196 int id = nestedTypeBuilders == null ? 0 : nestedTypeBuilders.Count;
2197 var tb = typeBuilder.DefineNestedType(NestedTypeName.ThreadLocal + id, TypeAttributes.NestedPrivate | TypeAttributes.Sealed, threadLocal.TypeAsBaseType);
2198 var fb = tb.DefineField("field", context.Types.Object, FieldAttributes.Private | FieldAttributes.Static);
2199 fb.SetCustomAttribute(new CustomAttributeBuilder(context.Resolver.ResolveCoreType(typeof(ThreadStaticAttribute).FullName).GetConstructor([]).AsReflection(), new object[0]));
2200
2201 var mbGet = tb.DefineMethod("get", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, context.Types.Object, Type.EmptyTypes);
2202 var ilgen = mbGet.GetILGenerator();
2203 ilgen.Emit(OpCodes.Ldsfld, fb);
2204 ilgen.Emit(OpCodes.Ret);
2205
2206 var mbSet = tb.DefineMethod("set", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, null, [context.Types.Object]);
2207 ilgen = mbSet.GetILGenerator();
2208 ilgen.Emit(OpCodes.Ldarg_1);
2209 ilgen.Emit(OpCodes.Stsfld, fb);
2210 ilgen.Emit(OpCodes.Ret);
2211
2212 var cb = ReflectUtil.DefineConstructor(tb, MethodAttributes.Assembly, Type.EmptyTypes);
2213 var ctorilgen = context.CodeEmitterFactory.Create(cb);
2214 ctorilgen.Emit(OpCodes.Ldarg_0);
2215 var basector = threadLocal.GetMethod("<init>", "()V", false);
2216 basector.Link();
2217 basector.EmitCall(ctorilgen);
2218 ctorilgen.Emit(OpCodes.Ret);
2219 ctorilgen.DoEmit();
2220
2221 RegisterNestedTypeBuilder(tb);
2222 return cb;
2223 }
2224
2225 internal MethodBuilder GetAtomicReferenceFieldUpdater(RuntimeJavaField field)
2226 {
2227 arfuMap ??= new Dictionary<RuntimeJavaField, MethodBuilder>();
2228
2229 if (!arfuMap.TryGetValue(field, out var cb))
2230 {
2231 RuntimeJavaType arfuTypeWrapper = context.ClassLoaderFactory.LoadClassCritical("ikvm.internal.IntrinsicAtomicReferenceFieldUpdater");
2232 TypeBuilder tb = typeBuilder.DefineNestedType(NestedTypeName.AtomicReferenceFieldUpdater + arfuMap.Count, TypeAttributes.NestedPrivate | TypeAttributes.Sealed, arfuTypeWrapper.TypeAsBaseType);
2233 AtomicReferenceFieldUpdaterEmitter.EmitImpl(context, tb, field.GetField());
2234 cb = ReflectUtil.DefineConstructor(tb, MethodAttributes.Assembly, Type.EmptyTypes);
2235 arfuMap.Add(field, cb);
2236 CodeEmitter ctorilgen = context.CodeEmitterFactory.Create(cb);
2237 ctorilgen.Emit(OpCodes.Ldarg_0);
2238 RuntimeJavaMethod basector = arfuTypeWrapper.GetMethod("<init>", "()V", false);
2239 basector.Link();
2240 basector.EmitCall(ctorilgen);
2241 ctorilgen.Emit(OpCodes.Ret);
2242 ctorilgen.DoEmit();
2243 RegisterNestedTypeBuilder(tb);
2244 }
2245 return cb;
2246 }
2247
2248 internal TypeBuilder DefineIndyCallSiteType()
2249 {
2250 int id = nestedTypeBuilders == null ? 0 : nestedTypeBuilders.Count;
2251 var tb = typeBuilder.DefineNestedType(NestedTypeName.IndyCallSite + id, TypeAttributes.NestedPrivate | TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);
2252 RegisterNestedTypeBuilder(tb);
2253 return tb;
2254 }
2255
2256 internal TypeBuilder DefineMethodHandleConstantType(MethodHandleConstantHandle handle)
2257 {
2258 var tb = typeBuilder.DefineNestedType(NestedTypeName.MethodHandleConstant + handle.Slot, TypeAttributes.NestedPrivate | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit); ;
2259 RegisterNestedTypeBuilder(tb);
2260 return tb;
2261 }
2262
2263 internal TypeBuilder DefineMethodTypeConstantType(MethodTypeConstantHandle handle)
2264 {
2265 var tb = typeBuilder.DefineNestedType(NestedTypeName.MethodTypeConstant + handle.Slot, TypeAttributes.NestedPrivate | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit);
2266 RegisterNestedTypeBuilder(tb);
2267 return tb;
2268 }
2269
2270 // this is used to define intrinsified anonymous classes (in the Unsafe.defineAnonymousClass() sense)
2271 internal TypeBuilder DefineAnonymousClass()
2272 {
2273 int id = nestedTypeBuilders == null ? 0 : nestedTypeBuilders.Count;
2274 var tb = typeBuilder.DefineNestedType(NestedTypeName.IntrinsifiedAnonymousClass + id, TypeAttributes.NestedPrivate | TypeAttributes.Sealed | TypeAttributes.SpecialName | TypeAttributes.BeforeFieldInit);
2275 RegisterNestedTypeBuilder(tb);
2276 return tb;
2277 }
2278
2279 MethodBuilder DefineHelperMethod(string name, Type returnType, Type[] parameterTypes)
2280 {
2281 return typeBuilder.DefineMethod(name, MethodAttributes.PrivateScope | MethodAttributes.Static, returnType, parameterTypes);
2282 }
2283
2284 internal MethodBuilder DefineMethodHandleDispatchStub(Type returnType, Type[] parameterTypes)
2285 {
2286 return DefineHelperMethod("__<>MHC", returnType, parameterTypes);
2287 }
2288
2289 internal FieldBuilder DefineMethodHandleInvokeCacheField(Type fieldType)
2290 {
2291 return typeBuilder.DefineField("__<>invokeCache", fieldType, FieldAttributes.Static | FieldAttributes.PrivateScope);
2292 }
2293
2294 internal FieldBuilder DefineDynamicMethodHandleCacheField()
2295 {
2296 return typeBuilder.DefineField("__<>dynamicMethodHandleCache", context.JavaBase.TypeOfJavaLangInvokeMethodHandle.TypeAsSignatureType, FieldAttributes.Static | FieldAttributes.PrivateScope);
2297 }
2298
2299 internal FieldBuilder DefineDynamicMethodTypeCacheField()
2300 {
2301 return typeBuilder.DefineField("__<>dynamicMethodTypeCache", context.JavaBase.TypeOfJavaLangInvokeMethodType.TypeAsSignatureType, FieldAttributes.Static | FieldAttributes.PrivateScope);
2302 }
2303
2304 internal MethodBuilder DefineDelegateInvokeErrorStub(Type returnType, Type[] parameterTypes)
2305 {
2306 return DefineHelperMethod("__<>", returnType, parameterTypes);
2307 }
2308
2309 internal MethodInfo GetInvokeSpecialStub(RuntimeJavaMethod method)
2310 {
2311 invokespecialstubcache ??= new Dictionary<MethodKey, MethodInfo>();
2312
2313 var key = new MethodKey(method.DeclaringType.Name, method.Name, method.Signature);
2314
2315 if (!invokespecialstubcache.TryGetValue(key, out var mi))
2316 {
2317 var dmh = method.GetDefineMethodHelper();
2318 var stub = dmh.DefineMethod(wrapper, typeBuilder, "__<>", MethodAttributes.PrivateScope);
2319 var ilgen = context.CodeEmitterFactory.Create(stub);
2320 ilgen.Emit(OpCodes.Ldarg_0);
2321 for (int i = 1; i <= dmh.ParameterCount; i++)
2322 ilgen.EmitLdarg(i);
2323 method.EmitCall(ilgen);
2324 ilgen.Emit(OpCodes.Ret);
2325 ilgen.DoEmit();
2326 invokespecialstubcache[key] = stub;
2327 mi = stub;
2328 }
2329
2330 return mi;
2331 }
2332
2333#if !IMPORTER
2334
2335 internal void EmitLiveObjectLoad(CodeEmitter ilgen, object value)
2336 {
2337 liveObjects ??= new List<object>();
2338 var fi = TypeBuilder.GetField(typeof(IKVM.Runtime.LiveObjectHolder<>).MakeGenericType(typeBuilder), typeof(IKVM.Runtime.LiveObjectHolder<>).GetField("values", BindingFlags.Static | BindingFlags.Public));
2339 ilgen.Emit(OpCodes.Ldsfld, fi);
2340 ilgen.EmitLdc_I4(liveObjects.Count);
2341 ilgen.Emit(OpCodes.Ldelem_Ref);
2342 liveObjects.Add(value);
2343 }
2344
2345#endif
2346 }
2347 }
2348
2349}
IKVM.Reflection.Type Type
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.FieldInfo FieldInfo
IKVM.Reflection.MethodInfo MethodInfo
IKVM.Reflection.MethodBase MethodBase
global::java.lang.Class Class
global::java.lang.invoke.LambdaForm.Name Name
IKVM.Runtime.RuntimeByteCodeJavaType DynamicOrAotTypeWrapper
static ParameterBuilder[] GetParameterBuilders(MethodBuilder mb, int parameterCount, string[] parameterNames)
static void GetParameterNamesFromSig(string sig, string[] parameterNames)
static void GetParameterNamesFromLVT(ClassFile.Method m, string[] parameterNames)
Implementation of RuntimeClassLoader that emits loaded Java types to an AssemblyBuilder.
Implementation of RuntimeByteCodeJavaType that customizes output for the importer.
record struct MethodKey(string ClassName, string MethodName, string MethodSig)