26using System.Diagnostics;
27using System.Reflection;
28using System.Reflection.Emit;
34 partial class MethodHandleUtil
37 internal Type GetMemberWrapperDelegateType(global::java.lang.invoke.MethodType type)
40 throw new NotImplementedException();
42 return GetDelegateTypeForInvokeExact(type.basicType());
46#if FIRST_PASS == false
48 Type CreateMethodHandleDelegateType(
java.
lang.invoke.MethodType type)
50 var args =
new RuntimeJavaType[type.parameterCount()];
51 for (
int i = 0; i < args.Length; i++)
53 args[i] = RuntimeJavaType.FromClass(type.parameterType(i));
56 var ret = RuntimeJavaType.FromClass(type.returnType());
58 return CreateMethodHandleDelegateType(args, ret);
63 var pi = mb.GetParameters();
64 var args =
new Type[pi.Length];
65 for (
int i = 0; i < args.Length; i++)
66 args[i] = pi[i].ParameterType;
73 var pi = mb.GetParameters();
74 var args =
new Type[pi.Length + 1];
76 for (
int i = 1; i < args.Length; i++)
77 args[i] = pi[i - 1].ParameterType;
82 internal java.lang.invoke.MethodType GetDelegateMethodType(
Type type)
85 var mi = GetDelegateInvokeMethod(type);
86 var pi = mi.GetParameters();
87 if (pi.Length > 0 && IsPackedArgsContainer(pi[pi.Length - 1].ParameterType))
90 for (
int i = 0; i < pi.Length - 1; i++)
91 list.Add(context.
ClassLoaderFactory.GetJavaTypeFromType(pi[i].ParameterType).ClassObject);
93 var args = pi[pi.Length - 1].ParameterType.GetGenericArguments();
94 while (IsPackedArgsContainer(args[args.Length - 1]))
96 for (
int i = 0; i < args.Length - 1; i++)
99 args = args[args.Length - 1].GetGenericArguments();
102 for (
int i = 0; i < args.Length; i++)
105 types = list.ToArray();
109 types =
new java.
lang.Class[pi.Length];
110 for (
int i = 0; i < types.Length; i++)
111 types[i] = context.
ClassLoaderFactory.GetJavaTypeFromType(pi[i].ParameterType).ClassObject;
114 return java.
lang.invoke.MethodType.methodType(context.
ClassLoaderFactory.GetJavaTypeFromType(mi.ReturnType).ClassObject, types);
117 internal sealed class DynamicMethodBuilder
120 const string METHOD_HANDLE_FORM_FIELD =
"form";
121 const string LAMBDA_FORM_VMENTRY_FIELD =
"vmentry";
122 const string MEMBER_NAME_VMTARGET_FIELD =
"vmtarget";
124 readonly RuntimeContext context;
125 readonly java.lang.invoke.MethodType type;
126 readonly
int firstArg;
127 readonly
Type delegateType;
128 readonly
object firstBoundValue;
129 readonly
object secondBoundValue;
130 readonly
Type container;
131 readonly DynamicMethod dm;
132 readonly CodeEmitter ilgen;
133 readonly
Type packedArgType;
134 readonly
int packedArgPos;
136 sealed class Container<T1, T2>
142 public Container(T1 target, T2 value)
144 this.target = target;
162 DynamicMethodBuilder(RuntimeContext context,
string name,
java.
lang.invoke.MethodType type,
Type container,
object target,
object value,
Type owner,
bool useBasicTypes)
164 this.context = context ??
throw new ArgumentNullException(nameof(context));
166 this.container = container;
168 delegateType = useBasicTypes ? context.MethodHandleUtil.GetMemberWrapperDelegateType(type) : context.MethodHandleUtil.GetDelegateTypeForInvokeExact(type);
169 firstBoundValue = target;
170 secondBoundValue = value;
172 var mi = context.MethodHandleUtil.GetDelegateInvokeMethod(delegateType);
175 if (container !=
null)
178 paramTypes = GetParameterTypes(container, mi);
180 else if (target !=
null)
183 paramTypes = GetParameterTypes(target.GetType(), mi);
187 paramTypes = GetParameterTypes(mi);
190 if (!ReflectUtil.CanOwnDynamicMethod(owner))
191 owner = typeof(DynamicMethodBuilder);
193 dm =
new DynamicMethod(name, mi.ReturnType, paramTypes, owner,
true);
194 ilgen = context.CodeEmitterFactory.Create(dm);
196 if (type.parameterCount() > MaxArity)
198 var pi = mi.GetParameters();
199 packedArgType = pi[pi.Length - 1].ParameterType;
200 packedArgPos = pi.Length - 1 + firstArg;
204 packedArgPos =
int.MaxValue;
208 internal static Delegate CreateVoidAdapter(RuntimeContext context, global::java.lang.invoke.MethodType type)
210 var dm =
new DynamicMethodBuilder(context,
"VoidAdapter", type.changeReturnType(global::java.lang.Void.TYPE),
null,
null,
null,
null,
true);
211 var targetDelegateType = context.MethodHandleUtil.GetMemberWrapperDelegateType(type);
213 dm.EmitCheckcast(context.JavaBase.TypeOfJavaLangInvokeMethodHandle);
214 dm.ilgen.Emit(OpCodes.Ldfld, typeof(global::java.lang.invoke.MethodHandle).GetField(METHOD_HANDLE_FORM_FIELD, BindingFlags.Instance | BindingFlags.NonPublic));
215 dm.ilgen.Emit(OpCodes.Ldfld, typeof(global::java.lang.invoke.LambdaForm).GetField(LAMBDA_FORM_VMENTRY_FIELD, BindingFlags.Instance | BindingFlags.NonPublic));
216 dm.ilgen.Emit(OpCodes.Ldfld, typeof(global::java.lang.invoke.MemberName).GetField(MEMBER_NAME_VMTARGET_FIELD, BindingFlags.Instance | BindingFlags.NonPublic));
217 dm.ilgen.Emit(OpCodes.Castclass, targetDelegateType);
218 for (
int i = 0; i < type.parameterCount(); i++)
221 dm.CallDelegate(targetDelegateType);
222 dm.ilgen.Emit(OpCodes.Pop);
225 return dm.CreateDelegate();
228 internal static DynamicMethod CreateInvokeExact(RuntimeContext context, global::java.lang.invoke.MethodType type)
232 var dm =
new DynamicMethodBuilder(context,
"InvokeExact", type, typeof(
java.
lang.invoke.MethodHandle),
null,
null,
null,
false);
233 var targetDelegateType = context.MethodHandleUtil.GetMemberWrapperDelegateType(type.insertParameterTypes(0, context.JavaBase.TypeOfJavaLangInvokeMethodHandle.ClassObject));
234 dm.ilgen.Emit(OpCodes.Ldarg_0);
235 dm.ilgen.Emit(OpCodes.Ldfld, typeof(global::java.lang.invoke.MethodHandle).GetField(METHOD_HANDLE_FORM_FIELD, BindingFlags.Instance | BindingFlags.NonPublic));
236 dm.ilgen.Emit(OpCodes.Ldfld, typeof(global::java.lang.invoke.LambdaForm).GetField(LAMBDA_FORM_VMENTRY_FIELD, BindingFlags.Instance | BindingFlags.NonPublic));
237 if (type.returnType() ==
java.
lang.Void.TYPE)
238 dm.ilgen.Emit(OpCodes.Call, typeof(
MethodHandleUtil).GetMethod(nameof(GetVoidAdapter), BindingFlags.Static | BindingFlags.NonPublic));
240 dm.ilgen.Emit(OpCodes.Ldfld, typeof(
java.
lang.invoke.MemberName).GetField(MEMBER_NAME_VMTARGET_FIELD, BindingFlags.Instance | BindingFlags.NonPublic));
242 dm.ilgen.Emit(OpCodes.Castclass, targetDelegateType);
243 dm.ilgen.Emit(OpCodes.Ldarg_0);
244 for (
int i = 0; i < type.parameterCount(); i++)
247 var tw = RuntimeJavaType.FromClass(type.parameterType(i));
248 if (tw.IsNonPrimitiveValueType)
249 tw.EmitBox(dm.ilgen);
251 tw.EmitConvSignatureTypeToStackType(dm.ilgen);
252 else if (tw == context.PrimitiveJavaTypeFactory.BYTE)
253 dm.ilgen.Emit(OpCodes.Conv_I1);
255 dm.CallDelegate(targetDelegateType);
257 var retType = RuntimeJavaType.FromClass(type.returnType());
258 if (retType.IsNonPrimitiveValueType)
259 retType.EmitUnbox(dm.ilgen);
260 else if (retType.IsGhost)
261 retType.EmitConvStackTypeToSignatureType(dm.ilgen,
null);
262 else if (!retType.IsPrimitive && retType != context.JavaBase.TypeOfJavaLangObject)
263 dm.EmitCheckcast(retType);
270 internal static Delegate CreateMethodHandleLinkTo(RuntimeContext context,
java.
lang.invoke.MemberName mn)
272 var type = mn.getMethodType();
273 var delegateType = context.MethodHandleUtil.GetMemberWrapperDelegateType(type.dropParameterTypes(type.parameterCount() - 1, type.parameterCount()));
274 var dm =
new DynamicMethodBuilder(context,
"DirectMethodHandle." + mn.getName() + type, type,
null,
null,
null,
null,
true);
275 dm.Ldarg(type.parameterCount() - 1);
276 dm.ilgen.EmitCastclass(typeof(
java.
lang.invoke.MemberName));
277 dm.ilgen.Emit(OpCodes.Ldfld, typeof(
java.
lang.invoke.MemberName).GetField(MEMBER_NAME_VMTARGET_FIELD, BindingFlags.Instance | BindingFlags.NonPublic));
278 dm.ilgen.Emit(OpCodes.Castclass, delegateType);
279 for (
int i = 0, count = type.parameterCount() - 1; i < count; i++)
281 dm.CallDelegate(delegateType);
284 return dm.CreateDelegate();
287 internal static Delegate CreateMethodHandleInvoke(RuntimeContext context,
java.
lang.invoke.MemberName mn)
289 var type = mn.getMethodType().insertParameterTypes(0, mn.getDeclaringClass());
290 var targetDelegateType = context.MethodHandleUtil.GetMemberWrapperDelegateType(type);
291 var dm =
new DynamicMethodBuilder(context,
"DirectMethodHandle." + mn.getName() + type, type, typeof(Container<,>).MakeGenericType(typeof(
object), typeof(
IKVM.
Runtime.
InvokeCache<>).MakeGenericType(targetDelegateType)),
null,
null,
null,
true);
293 dm.EmitCheckcast(context.JavaBase.TypeOfJavaLangInvokeMethodHandle);
294 switch (mn.getName())
297 dm.Call(context.ByteCodeHelperMethods.GetDelegateForInvokeExact.MakeGenericMethod(targetDelegateType));
300 dm.LoadValueAddress();
301 dm.Call(context.ByteCodeHelperMethods.GetDelegateForInvoke.MakeGenericMethod(targetDelegateType));
304 dm.Call(context.ByteCodeHelperMethods.GetDelegateForInvokeBasic.MakeGenericMethod(targetDelegateType));
307 throw new InvalidOperationException();
311 for (
int i = 1, count = type.parameterCount(); i < count; i++)
313 dm.CallDelegate(targetDelegateType);
316 return dm.CreateDelegate();
319 internal static Delegate CreateDynamicOnly(RuntimeContext context, RuntimeJavaMethod mw,
java.
lang.invoke.MethodType type)
323 var dm =
new DynamicMethodBuilder(context,
"CustomInvoke:" + mw.Name, type,
null, mw,
null,
null,
true);
324 dm.ilgen.Emit(OpCodes.Ldarg_0);
335 dm.Callvirt(typeof(RuntimeJavaMethod).GetMethod(
"Invoke", BindingFlags.Instance | BindingFlags.NonPublic));
336 dm.UnboxReturnValue();
339 return dm.CreateDelegate();
342 internal static Delegate CreateMemberName(RuntimeContext context, RuntimeJavaMethod mw, global::java.lang.invoke.MethodType type,
bool doDispatch)
346 var tw = mw.DeclaringType;
347 var owner = tw.TypeAsBaseType;
348 var dm =
new DynamicMethodBuilder(context,
"MemberName:" + mw.DeclaringType.Name +
"::" + mw.Name + mw.Signature, type,
null, mw.HasCallerID ? DynamicCallerIDProvider.Instance :
null,
null, owner,
true);
349 for (
int i = 0, count = type.parameterCount(); i < count; i++)
351 if (i == 0 && !mw.IsStatic && (tw.IsGhost || tw.IsNonPrimitiveValueType || tw.IsRemapped) && (!mw.IsConstructor || tw != context.JavaBase.TypeOfJavaLangString))
353 if (tw.IsGhost || tw.IsNonPrimitiveValueType)
355 dm.LoadFirstArgAddress(tw);
359 Debug.Assert(tw.IsRemapped);
363 if (mw.IsConstructor)
364 dm.EmitCastclass(tw.TypeAsBaseType);
365 else if (tw != context.JavaBase.TypeOfCliSystemObject)
366 dm.EmitCheckcast(tw);
372 var argType = RuntimeJavaType.FromClass(type.parameterType(i));
373 if (!argType.IsPrimitive)
375 if (argType.IsUnloadable)
379 else if (argType.IsNonPrimitiveValueType)
383 else if (argType.IsGhost)
385 dm.UnboxGhost(argType);
389 dm.EmitCheckcast(argType);
399 if (mw.IsFinalizeOrClone)
403 mw.EmitCallvirtReflect(dm.ilgen);
408 context.JavaBase.TypeOfCliSystemObject.GetMethod(mw.Name, mw.Signature,
false).EmitCall(dm.ilgen);
411 else if (doDispatch && !mw.IsStatic)
420 var retType = RuntimeJavaType.FromClass(type.returnType());
421 if (retType.IsUnloadable)
425 else if (retType.IsNonPrimitiveValueType)
429 else if (retType.IsGhost)
431 dm.BoxGhost(retType);
433 else if (retType == context.PrimitiveJavaTypeFactory.BYTE)
439 return dm.CreateDelegate();
444 ilgen.Emit(OpCodes.Call, method);
449 ilgen.Emit(OpCodes.Callvirt, method);
452 internal void Call(RuntimeJavaMethod mw)
457 internal void Callvirt(RuntimeJavaMethod mw)
459 mw.EmitCallvirt(ilgen);
462 internal void CallDelegate(
Type delegateType)
464 context.MethodHandleUtil.EmitCallDelegateInvokeMethod(ilgen, delegateType);
467 internal void LoadFirstArgAddress(RuntimeJavaType tw)
472 tw.EmitConvStackTypeToSignatureType(ilgen,
null);
473 var local = ilgen.DeclareLocal(tw.TypeAsSignatureType);
474 ilgen.Emit(OpCodes.Stloc, local);
475 ilgen.Emit(OpCodes.Ldloca, local);
477 else if (tw.IsNonPrimitiveValueType)
479 ilgen.Emit(OpCodes.Unbox, tw.TypeAsSignatureType);
483 throw new InvalidOperationException();
487 internal void Ldarg(
int i)
489 context.MethodHandleUtil.LoadPackedArg(ilgen, i, firstArg, packedArgPos, packedArgType);
492 internal void LoadCallerID()
494 ilgen.Emit(OpCodes.Ldarg_0);
495 ilgen.Emit(OpCodes.Call, context.ByteCodeHelperMethods.DynamicCallerID);
498 internal void LoadValueAddress()
500 ilgen.Emit(OpCodes.Ldarg_0);
501 ilgen.Emit(OpCodes.Ldflda, container.GetField(
"value"));
506 ilgen.Emit(OpCodes.Ret);
509 internal Delegate CreateDelegate()
514 return ValidateDelegate(firstArg == 0
515 ? dm.CreateDelegate(delegateType)
516 : dm.CreateDelegate(delegateType, container ==
null ? firstBoundValue : Activator.CreateInstance(container, firstBoundValue, secondBoundValue)));
519 internal void BoxArgs(
int start)
521 int paramCount = type.parameterCount();
522 ilgen.EmitLdc_I4(paramCount - start);
523 ilgen.Emit(OpCodes.Newarr, context.Types.Object);
524 for (
int i = start; i < paramCount; i++)
526 ilgen.Emit(OpCodes.Dup);
527 ilgen.EmitLdc_I4(i - start);
529 var tw = RuntimeJavaType.FromClass(type.parameterType(i));
531 ilgen.Emit(OpCodes.Box, tw.TypeAsSignatureType);
533 ilgen.Emit(OpCodes.Stelem_Ref);
537 internal void UnboxReturnValue()
539 var tw = RuntimeJavaType.FromClass(type.returnType());
540 if (tw == context.PrimitiveJavaTypeFactory.VOID)
542 ilgen.Emit(OpCodes.Pop);
544 else if (tw.IsPrimitive)
546 ilgen.Emit(OpCodes.Unbox, tw.TypeAsSignatureType);
547 ilgen.Emit(OpCodes.Ldobj, tw.TypeAsSignatureType);
551 internal void LoadNull()
553 ilgen.Emit(OpCodes.Ldnull);
556 internal void Unbox(RuntimeJavaType tw)
561 internal void Box(RuntimeJavaType tw)
566 internal void UnboxGhost(RuntimeJavaType tw)
568 tw.EmitConvStackTypeToSignatureType(ilgen,
null);
571 internal void BoxGhost(RuntimeJavaType tw)
573 tw.EmitConvSignatureTypeToStackType(ilgen);
576 internal void EmitCheckcast(RuntimeJavaType tw)
578 tw.EmitCheckcast(ilgen);
581 internal void EmitCastclass(
Type type)
583 ilgen.EmitCastclass(type);
586 internal void EmitWriteLine()
588 ilgen.Emit(OpCodes.Call, typeof(Console).GetMethod(
"WriteLine",
new Type[] { typeof(
object) }));
591 internal void CastByte()
593 ilgen.Emit(OpCodes.Conv_I1);
596 internal void DumpMethod()
598 Console.WriteLine(dm.Name +
", type = " + delegateType);
602 private static void FinishTypes(global::java.lang.invoke.MethodType type)
606 RuntimeJavaType.FromClass(type.returnType()).Finish();
607 for (
int i = 0; i < type.parameterCount(); i++)
608 RuntimeJavaType.FromClass(type.parameterType(i)).Finish();
613 [
System.Security.SecuritySafeCritical]
615 static Delegate ValidateDelegate(Delegate d)
624 throw new InternalException(
"Delegate failed to JIT", e);
630 internal Type GetDelegateTypeForInvokeExact(global::java.lang.invoke.MethodType type)
632 type._invokeExactDelegateType ??= CreateMethodHandleDelegateType(type);
633 return type._invokeExactDelegateType;
636 internal T GetDelegateForInvokeExact<T>(global::java.lang.invoke.MethodHandle mh)
637 where T :
class, Delegate
639 var type = mh.type();
640 if (mh._invokeExactDelegate ==
null)
642 type._invokeExactDynamicMethod ??= DynamicMethodBuilder.CreateInvokeExact(context, type);
643 mh._invokeExactDelegate = type._invokeExactDynamicMethod.CreateDelegate(GetDelegateTypeForInvokeExact(type), mh);
644 var del = mh._invokeExactDelegate as T;
649 throw java.
lang.invoke.Invokers.newWrongMethodTypeException(GetDelegateMethodType(typeof(T)), type);
657 internal static object GetVoidAdapter(
java.
lang.invoke.MemberName mn)
659 var type = mn.getMethodType();
660 if (type.voidAdapter ==
null)
662 if (type.returnType() == global::java.lang.Void.TYPE)
665 type.voidAdapter = DynamicMethodBuilder.CreateVoidAdapter(JVM.Context, type);
668 return type.voidAdapter;
671 internal void LoadPackedArg(CodeEmitter ilgen,
int index,
int firstArg,
int packedArgPos,
Type packedArgType)
674 if (index >= packedArgPos)
676 ilgen.EmitLdarga(packedArgPos);
677 var fieldPos = index - packedArgPos;
678 var type = packedArgType;
679 while (fieldPos >= MaxArity || (fieldPos == MaxArity - 1 && IsPackedArgsContainer(type.GetField(
"t8").FieldType)))
681 var field = type.GetField(
"t8");
682 type = field.FieldType;
683 ilgen.Emit(OpCodes.Ldflda, field);
684 fieldPos -= MaxArity - 1;
686 ilgen.Emit(OpCodes.Ldfld, type.GetField(
"t" + (1 + fieldPos)));
690 ilgen.EmitLdarg(index);
IKVM.Reflection.Type Type
IKVM.Reflection.MethodInfo MethodInfo
IKVM.Reflection.MethodBase MethodBase
MethodHandleUtil(RuntimeContext context)
Initializes a new instance.
RuntimeClassLoaderFactory ClassLoaderFactory
Gets the RuntimeClassLoaderFactory associated with this instance of the runtime.