IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
RuntimeJavaMethod.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2014 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25using System.Diagnostics;
26
27using IKVM.Attributes;
28
29using System.Linq;
31using System.Threading;
32
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
45namespace IKVM.Runtime
46{
47
49 {
50
51 MethodBase method;
52 string[] declaredExceptions;
53 RuntimeJavaType returnTypeWrapper;
54 RuntimeJavaType[] parameterTypeWrappers;
55
56#if !IMPORTER && !FIRST_PASS && !EXPORTER
57 volatile java.lang.reflect.Executable reflectionMethod;
58#endif
59
60#if EMITTERS
61
62 internal virtual void EmitCall(CodeEmitter ilgen)
63 {
64 throw new InvalidOperationException();
65 }
66
67 internal virtual void EmitCallvirt(CodeEmitter ilgen)
68 {
69 throw new InvalidOperationException();
70 }
71
72 internal virtual void EmitCallvirtReflect(CodeEmitter ilgen)
73 {
74 EmitCallvirt(ilgen);
75 }
76
77 internal virtual void EmitNewobj(CodeEmitter ilgen)
78 {
79 throw new InvalidOperationException();
80 }
81
82 internal virtual bool EmitIntrinsic(EmitIntrinsicContext context)
83 {
84 return Intrinsics.Emit(context);
85 }
86
87#endif // EMITTERS
88
89 internal virtual bool IsDynamicOnly => false;
90
102 internal RuntimeJavaMethod(RuntimeJavaType declaringType, string name, string sig, MethodBase method, RuntimeJavaType returnType, RuntimeJavaType[] parameterTypes, Modifiers modifiers, MemberFlags flags) :
103 base(declaringType, name, sig, modifiers, flags)
104 {
105 Profiler.Count("MethodWrapper");
106
107 this.method = method;
108 Debug.Assert(((returnType == null) == (parameterTypes == null)) || (returnType == declaringType.Context.PrimitiveJavaTypeFactory.VOID));
109 this.returnTypeWrapper = returnType;
110 this.parameterTypeWrappers = parameterTypes;
111 if (Intrinsics.IsIntrinsic(this))
113
114 UpdateNonPublicTypeInSignatureFlag();
115 }
116
117 void UpdateNonPublicTypeInSignatureFlag()
118 {
119 if ((IsPublic || IsProtected) && (returnTypeWrapper != null && parameterTypeWrappers != null) && !(this is RuntimeAccessStubJavaMethod) && !(this is RuntimeConstructorAccessStubJavaMethod))
120 {
121 if (!returnTypeWrapper.IsPublic && !returnTypeWrapper.IsUnloadable)
122 {
124 }
125 else
126 {
127 foreach (RuntimeJavaType tw in parameterTypeWrappers)
128 {
129 if (!tw.IsPublic && !tw.IsUnloadable)
130 {
132 break;
133 }
134 }
135 }
136 }
137 }
138
143 internal void SetDeclaredExceptions(string[] exceptions)
144 {
145 declaredExceptions = exceptions != null && exceptions.Length > 0 ? (string[])exceptions.Clone() : Array.Empty<string>();
146 }
147
152 internal string[] GetDeclaredExceptions()
153 {
154 return declaredExceptions;
155 }
156
157#if !IMPORTER && !EXPORTER
158
159 internal java.lang.reflect.Executable ToMethodOrConstructor(bool copy)
160 {
161#if FIRST_PASS
162 throw new NotImplementedException();
163#else
164 var method = reflectionMethod;
165 if (method == null)
166 {
167 Link();
168
169 var loader = DeclaringType.ClassLoader;
170 var argTypes = GetParameters();
171 var parameterTypes = new java.lang.Class[argTypes.Length];
172 for (int i = 0; i < argTypes.Length; i++)
173 parameterTypes[i] = argTypes[i].EnsureLoadable(loader).ClassObject;
174
175 var checkedExceptions = GetExceptions();
176 if (IsConstructor)
177 {
178 method = new java.lang.reflect.Constructor(
179 DeclaringType.ClassObject,
180 parameterTypes,
181 checkedExceptions,
182 (int)Modifiers | (IsInternal ? 0x40000000 : 0),
183 Array.IndexOf(DeclaringType.GetMethods(), this),
184 DeclaringType.GetGenericMethodSignature(this),
185 null,
186 null
187 );
188 }
189 else
190 {
191 method = new java.lang.reflect.Method(
192 DeclaringType.ClassObject,
193 Name,
194 parameterTypes,
195 ReturnType.EnsureLoadable(loader).ClassObject,
196 checkedExceptions,
197 (int)Modifiers | (IsInternal ? 0x40000000 : 0),
198 Array.IndexOf(DeclaringType.GetMethods(), this),
199 DeclaringType.GetGenericMethodSignature(this),
200 null,
201 null,
202 null
203 );
204 }
205
206 Interlocked.CompareExchange(ref reflectionMethod, method, null);
207 method = reflectionMethod;
208 }
209
210 if (copy)
211 {
212 if (method is java.lang.reflect.Constructor ctor)
213 return ctor.copy();
214 else
215 return ((java.lang.reflect.Method)method).copy();
216 }
217
218 return method;
219#endif
220 }
221
222
223#if !FIRST_PASS
224
225 java.lang.Class[] GetExceptions()
226 {
227 var classes = declaredExceptions;
228 var types = Type.EmptyTypes;
229 if (classes == null)
230 {
231 // NOTE if method is a MethodBuilder, GetCustomAttributes doesn't work (and if
232 // the method had any declared exceptions, the declaredExceptions field would have
233 // been set)
234 if (method != null && method is not MethodBuilder)
235 {
236 var attr = DeclaringType.Context.AttributeHelper.GetThrows(method);
237 if (attr != null)
238 {
239 classes = attr.classes;
240 types = attr.types;
241 }
242 }
243 }
244
245 if (classes != null)
246 {
247 var array = new java.lang.Class[classes.Length];
248 for (int i = 0; i < classes.Length; i++)
249 array[i] = DeclaringType.ClassLoader.LoadClassByName(classes[i]).ClassObject;
250
251 return array;
252 }
253 else
254 {
255 var array = new java.lang.Class[types.Length];
256 for (int i = 0; i < types.Length; i++)
257 array[i] = types[i];
258
259 return array;
260 }
261 }
262
263#endif // !FIRST_PASS
264
265 internal static RuntimeJavaMethod FromExecutable(java.lang.reflect.Executable executable)
266 {
267#if FIRST_PASS
268 throw new NotImplementedException();
269#else
270 return RuntimeJavaType.FromClass(executable.getDeclaringClass()).GetMethods()[executable._slot()];
271#endif
272 }
273
274#endif // !IMPORTER && !EXPORTER
275
281 [System.Security.SecurityCritical]
282 internal static RuntimeJavaMethod FromCookie(IntPtr cookie)
283 {
284 return (RuntimeJavaMethod)FromCookieImpl(cookie);
285 }
286
287 internal bool IsLinked
288 {
289 get
290 {
291 return parameterTypeWrappers != null;
292 }
293 }
294
295 internal void Link()
296 {
297 Link(LoadMode.Link);
298 }
299
300 internal void Link(LoadMode mode)
301 {
302 lock (this)
303 if (parameterTypeWrappers != null)
304 return;
305
306 var loader = this.DeclaringType.ClassLoader;
307 var ret = loader.RetTypeWrapperFromSig(Signature, mode);
308 var parameters = loader.ArgJavaTypeListFromSig(Signature, mode);
309
310 lock (this)
311 {
312 try
313 {
314 // critical code in the finally block to avoid Thread.Abort interrupting the thread
315 }
316 finally
317 {
318 if (parameterTypeWrappers == null)
319 {
320 Debug.Assert(returnTypeWrapper == null || returnTypeWrapper == DeclaringType.Context.PrimitiveJavaTypeFactory.VOID);
321
322 returnTypeWrapper = ret;
323 parameterTypeWrappers = parameters;
324 UpdateNonPublicTypeInSignatureFlag();
325 if (method == null)
326 {
327 try
328 {
329 DoLinkMethod();
330 }
331 catch
332 {
333 // HACK if linking fails, we unlink to make sure
334 // that the next link attempt will fail again
335 returnTypeWrapper = null;
336 parameterTypeWrappers = null;
337 throw;
338 }
339 }
340 }
341 }
342 }
343 }
344
345 protected virtual void DoLinkMethod()
346 {
347 method = DeclaringType.LinkMethod(this);
348 }
349
350 [Conditional("DEBUG")]
351 internal void AssertLinked()
352 {
353 if (!(parameterTypeWrappers != null && returnTypeWrapper != null))
354 DeclaringType.ClassLoader.Diagnostics.GenericRuntimeError($"AssertLinked failed: {DeclaringType.Name}::{Name}{Signature}");
355
356 Debug.Assert(parameterTypeWrappers != null && returnTypeWrapper != null, DeclaringType.Name + "::" + Name + Signature);
357 }
358
359 internal RuntimeJavaType ReturnType
360 {
361 get
362 {
363 AssertLinked();
364 return returnTypeWrapper;
365 }
366 }
367
368 internal RuntimeJavaType[] GetParameters()
369 {
370 AssertLinked();
371 return parameterTypeWrappers;
372 }
373
374#if !EXPORTER
375 internal DefineMethodHelper GetDefineMethodHelper()
376 {
377 return new DefineMethodHelper(this);
378 }
379#endif
380
381 internal Type ReturnTypeForDefineMethod
382 {
383 get
384 {
385 return ReturnType.TypeAsSignatureType;
386 }
387 }
388
389 internal Type[] GetParametersForDefineMethod()
390 {
391 RuntimeJavaType[] wrappers = GetParameters();
392 int len = wrappers.Length;
393 if (HasCallerID)
394 {
395 len++;
396 }
397 Type[] temp = new Type[len];
398 for (int i = 0; i < wrappers.Length; i++)
399 {
400 temp[i] = wrappers[i].TypeAsSignatureType;
401 }
402 if (HasCallerID)
403 {
404 temp[len - 1] = DeclaringType.Context.JavaBase.TypeOfIkvmInternalCallerID.TypeAsSignatureType;
405 }
406 return temp;
407 }
408
409 // we expose the underlying MethodBase object,
410 // for Java types, this is the method that contains the compiled Java bytecode
411 // for remapped types, this is the mbCore method (not the helper)
412 // Note that for some artificial methods (notably wrap() in enums), method is null
413 internal MethodBase GetMethod()
414 {
415 AssertLinked();
416 return method;
417 }
418
419 internal string RealName
420 {
421 get
422 {
423 AssertLinked();
424 return method.Name;
425 }
426 }
427
428 internal bool IsAbstract
429 {
430 get
431 {
432 return (Modifiers & Modifiers.Abstract) != 0;
433 }
434 }
435
436 internal bool RequiresNonVirtualDispatcher
437 {
438 get
439 {
440 return !IsConstructor
441 && !IsStatic
442 && !IsPrivate
443 && !IsAbstract
444 && !IsFinal
445 && !DeclaringType.IsFinal;
446 }
447 }
448
449#if !IMPORTER && !EXPORTER
450
451 internal Type GetDelegateType()
452 {
453 var paramTypes = GetParameters();
454 if (paramTypes.Length > MethodHandleUtil.MaxArity)
455 {
456 var type = DeclaringType.TypeAsBaseType.Assembly.GetType(ReturnType == DeclaringType.Context.PrimitiveJavaTypeFactory.VOID ? "__<>NVIV`" + paramTypes.Length : "__<>NVI`" + (paramTypes.Length + 1));
457 if (type == null)
458 type = DeclaringType.ClassLoader.GetTypeWrapperFactory().DefineDelegate(paramTypes.Length, ReturnType == DeclaringType.Context.PrimitiveJavaTypeFactory.VOID);
459
460 var types = new Type[paramTypes.Length + (ReturnType == DeclaringType.Context.PrimitiveJavaTypeFactory.VOID ? 0 : 1)];
461 for (int i = 0; i < paramTypes.Length; i++)
462 types[i] = paramTypes[i].TypeAsSignatureType;
463
464 if (ReturnType != DeclaringType.Context.PrimitiveJavaTypeFactory.VOID)
465 types[types.Length - 1] = ReturnType.TypeAsSignatureType;
466
467 return type.MakeGenericType(types);
468 }
469
470 return DeclaringType.Context.MethodHandleUtil.CreateMemberWrapperDelegateType(paramTypes, ReturnType);
471 }
472
476 internal void ResolveMethod()
477 {
478#if FIRST_PASS
479 throw new NotImplementedException();
480#else
481 // if we've still got the builder object, we need to replace it with the real thing before we can call it
482 var mb = method as MethodBuilder;
483 if (mb != null)
484 {
485#if NETFRAMEWORK
486 method = mb.Module.ResolveMethod(mb.GetToken().Token);
487#else
488 // though ResolveMethod exists, Core 3.1 does not provide a stable way to obtain the resulting metadata token
489 // instead we have to scan the methods for the one that matches the signature using the runtime type instances
490 // FIXME .NET 6
491
492 var parameters = GetParameters();
493 var typeLength = parameters.Length;
494 if (HasCallerID)
495 typeLength++;
496
497 var types = new Type[typeLength];
498 for (int i = 0; i < parameters.Length; i++)
499 {
500 parameters[i].Finish();
501 types[i] = parameters[i].TypeAsSignatureType;
502 }
503
504 if (HasCallerID)
505 types[typeLength - 1] = DeclaringType.Context.JavaBase.TypeOfIkvmInternalCallerID.TypeAsSignatureType;
506
507 if (ReturnType != null)
508 ReturnType.Finish();
509
510 var flags = BindingFlags.DeclaredOnly;
511 flags |= mb.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
512 flags |= mb.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
513 method = DeclaringType.TypeAsTBD.GetMethods(flags).FirstOrDefault(i => i.Name == mb.Name && i.GetParameters().Select(j => j.ParameterType).SequenceEqual(types) && i.ReturnType.Equals(ReturnType.TypeAsSignatureType));
514 if (method == null)
515 method = DeclaringType.TypeAsTBD.GetConstructor(flags, null, types, null);
516 if (method == null)
517 throw new InternalException("Could not resolve method against runtime type.");
518#endif
519 }
520#endif
521 }
522
523 [HideFromJava]
524 internal virtual object InvokeNonvirtualRemapped(object obj, object[] args)
525 {
526 throw new InvalidOperationException();
527 }
528
536 [HideFromJava]
537 protected static object InvokeAndUnwrapException(MethodBase mb, object obj, object[] args)
538 {
539#if FIRST_PASS
540 throw new NotImplementedException();
541#else
542 try
543 {
544 return mb.Invoke(obj, args);
545 }
546 catch (TargetInvocationException e)
547 {
548 throw ikvm.runtime.Util.mapException(e.InnerException);
549 }
550#endif
551 }
552
559 [HideFromJava]
560 internal virtual object Invoke(object obj, object[] args)
561 {
562 return InvokeAndUnwrapException(method, obj, args);
563 }
564
565 [HideFromJava]
566 internal virtual object CreateInstance(object[] args)
567 {
568#if FIRST_PASS
569 throw new NotImplementedException();
570#else
571 try
572 {
573 return ((ConstructorInfo)method).Invoke(args);
574 }
575 catch (TargetInvocationException x)
576 {
577 throw ikvm.runtime.Util.mapException(x.InnerException);
578 }
579#endif
580 }
581
582#endif // !IMPORTER && !EXPORTER
583
584 internal static OpCode SimpleOpCodeToOpCode(SimpleOpCode opc) => opc switch
585 {
586 SimpleOpCode.Call => OpCodes.Call,
587 SimpleOpCode.Callvirt => OpCodes.Callvirt,
588 SimpleOpCode.Newobj => OpCodes.Newobj,
589 _ => throw new InvalidOperationException(),
590 };
591
592 internal virtual bool IsOptionalAttributeAnnotationValue => false;
593
594 internal bool IsConstructor => Name == (object)StringConstants.INIT;
595
596 internal bool IsClassInitializer => Name == (object)StringConstants.CLINIT;
597
598 internal bool IsVirtual => (modifiers & (Modifiers.Static | Modifiers.Private)) == 0 && !IsConstructor;
599
600 internal bool IsFinalizeOrClone
601 {
602 get
603 {
604 return IsProtected && (DeclaringType == DeclaringType.Context.JavaBase.TypeOfJavaLangObject || DeclaringType == DeclaringType.Context.JavaBase.TypeOfjavaLangThrowable) && (Name == StringConstants.CLONE || Name == StringConstants.FINALIZE);
605 }
606 }
607 }
608
609}
System.Threading.Interlocked Interlocked
IKVM.Reflection.Type Type
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.MethodBase MethodBase
global::java.lang.invoke.LambdaForm.Name Name
virtual IDiagnosticHandler Diagnostics
Gets the IDiagnosticHandler events originated by this class loader should be sent to.
AttributeHelper AttributeHelper
Gets the AttributeHelper associated with this instance of the runtime.
MethodHandleUtil MethodHandleUtil
Gets the MethodHandleUtil associated with this instance of the runtime.
RuntimePrimitiveJavaTypeFactory PrimitiveJavaTypeFactory
Gets the RuntimePrimitiveJavaTypeFactory associated with this instance of the runtime.
CoreClasses JavaBase
Gets the CoreClasses associated with this instance of the runtime.
static object InvokeAndUnwrapException(MethodBase mb, object obj, object[] args)
Dynamically invokes the method and potentially unwraps any exceptions.
void GenericRuntimeError(string arg0)
The 'GenericRuntimeError' diagnostic.
MemberFlags
Describes various options applied to a member.