Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2013-02-24 19:29:06 +0400
committerjfrijters <jfrijters>2013-02-24 19:29:06 +0400
commitf57522835372ad726e3ce3b6b58efbb155af154c (patch)
tree053c97c1c49ce6950f946a38f86dd2849689db00
parentb1b5fee0342725a1fe7cc28f138292448922916a (diff)
Reimplemented dynamic binding on top of MethodHandles. This avoids having to instantiate a java.lang.reflect.Method which might fail if it declares a checked exception that is not loadable. It also has the potential of being faster, but no perf work has been done yet.
-rw-r--r--runtime/ByteCodeHelper.cs149
-rw-r--r--runtime/compiler.cs181
2 files changed, 143 insertions, 187 deletions
diff --git a/runtime/ByteCodeHelper.cs b/runtime/ByteCodeHelper.cs
index c6f50770..64769463 100644
--- a/runtime/ByteCodeHelper.cs
+++ b/runtime/ByteCodeHelper.cs
@@ -342,123 +342,6 @@ namespace IKVM.Runtime
return wrapper.IsInstance(obj);
}
- private static MethodWrapper GetMethodWrapper(object thisObj, string clazz, string name, string sig, bool isStatic, ikvm.@internal.CallerID callerId)
- {
- TypeWrapper caller = TypeWrapper.FromClass(callerId.getCallerClass());
- TypeWrapper wrapper = LoadTypeWrapper(clazz, callerId);
- MethodWrapper mw = wrapper.GetMethodWrapper(name, sig, name != StringConstants.INIT);
- if(mw == null)
- {
- throw new java.lang.NoSuchMethodError(clazz + "." + name + sig);
- }
- // TODO check loader constraints
- if(mw.IsStatic != isStatic)
- {
- throw new java.lang.IncompatibleClassChangeError(clazz + "." + name);
- }
- TypeWrapper objType = null;
- if(thisObj != null)
- {
- if(!wrapper.IsInstance(thisObj))
- {
- throw new java.lang.IncompatibleClassChangeError(clazz + "." + name);
- }
- objType = ClassLoaderWrapper.GetWrapperFromType(thisObj.GetType());
- }
- if(mw.IsAccessibleFrom(wrapper, caller, objType))
- {
- return mw;
- }
- throw new java.lang.IllegalAccessError(clazz + "." + name + sig);
- }
-
- [DebuggerStepThroughAttribute]
- public static object DynamicInvokeSpecialNew(string clazz, string name, string sig, object[] args, ikvm.@internal.CallerID callerID)
- {
-#if FIRST_PASS
- return null;
-#else
- Profiler.Count("DynamicInvokeSpecialNew");
- MethodWrapper mw = GetMethodWrapper(null, clazz, name, sig, false, callerID);
- if (mw.DeclaringType.IsAbstract)
- {
- throw new java.lang.InstantiationError(mw.DeclaringType.Name);
- }
- try
- {
- java.lang.reflect.Constructor cons = (java.lang.reflect.Constructor)mw.ToMethodOrConstructor(false);
- return cons.newInstance(BoxArgs(mw, args), callerID);
- }
- catch (java.lang.reflect.InvocationTargetException x)
- {
- throw x.getCause();
- }
-#endif
- }
-
- [DebuggerStepThroughAttribute]
- public static object DynamicInvokestatic(string clazz, string name, string sig, object[] args, ikvm.@internal.CallerID callerID)
- {
-#if FIRST_PASS
- return null;
-#else
- Profiler.Count("DynamicInvokestatic");
- MethodWrapper mw = GetMethodWrapper(null, clazz, name, sig, true, callerID);
- java.lang.reflect.Method m = (java.lang.reflect.Method)mw.ToMethodOrConstructor(false);
- try
- {
- object val = m.invoke(null, BoxArgs(mw, args), callerID);
- if (mw.ReturnType.IsPrimitive && mw.ReturnType != PrimitiveTypeWrapper.VOID)
- {
- val = JVM.Unbox(val);
- }
- return val;
- }
- catch (java.lang.reflect.InvocationTargetException x)
- {
- throw x.getCause();
- }
-#endif
- }
-
- [DebuggerStepThroughAttribute]
- public static object DynamicInvokevirtual(object obj, string clazz, string name, string sig, object[] args, ikvm.@internal.CallerID callerID)
- {
-#if FIRST_PASS
- return null;
-#else
- Profiler.Count("DynamicInvokevirtual");
- MethodWrapper mw = GetMethodWrapper(obj, clazz, name, sig, false, callerID);
- java.lang.reflect.Method m = (java.lang.reflect.Method)mw.ToMethodOrConstructor(false);
- try
- {
- object val = m.invoke(obj, BoxArgs(mw, args), callerID);
- if (mw.ReturnType.IsPrimitive && mw.ReturnType != PrimitiveTypeWrapper.VOID)
- {
- val = JVM.Unbox(val);
- }
- return val;
- }
- catch (java.lang.reflect.InvocationTargetException x)
- {
- throw x.getCause();
- }
-#endif
- }
-
- private static object[] BoxArgs(MethodWrapper mw, object[] args)
- {
- TypeWrapper[] paramTypes = mw.GetParameters();
- for (int i = 0; i < paramTypes.Length; i++)
- {
- if (paramTypes[i].IsPrimitive)
- {
- args[i] = JVM.Box(args[i]);
- }
- }
- return args;
- }
-
[DebuggerStepThrough]
public static java.lang.invoke.MethodType DynamicLoadMethodType(ref java.lang.invoke.MethodType cache, string sig, ikvm.@internal.CallerID callerID)
{
@@ -566,6 +449,38 @@ namespace IKVM.Runtime
}
[DebuggerStepThrough]
+ public static T DynamicBinderMemberLookup<T>(int kind, string clazz, string name, string sig, ikvm.@internal.CallerID callerID)
+ where T : class /* delegate */
+ {
+#if FIRST_PASS
+ return null;
+#else
+ try
+ {
+ java.lang.invoke.MethodHandle mh = DynamicLoadMethodHandleImpl(kind, clazz, name, sig, callerID);
+ return mh.vmtarget as T
+ ?? (T)mh.asType(MethodHandleUtil.GetDelegateMethodType(typeof(T))).vmtarget;
+ }
+ catch (java.lang.IncompatibleClassChangeError x)
+ {
+ if (x.getCause() is java.lang.NoSuchMethodException)
+ {
+ throw new java.lang.NoSuchMethodError(x.getCause().Message);
+ }
+ if (x.getCause() is java.lang.NoSuchFieldException)
+ {
+ throw new java.lang.NoSuchFieldError(x.getCause().Message);
+ }
+ if (x.getCause() is java.lang.IllegalAccessException)
+ {
+ throw new java.lang.IllegalAccessError(x.getCause().Message);
+ }
+ throw;
+ }
+#endif
+ }
+
+ [DebuggerStepThrough]
public static Delegate DynamicCreateDelegate(object obj, Type delegateType, string name, string sig)
{
TypeWrapper tw = TypeWrapper.FromClass(ikvm.runtime.Util.getClassFromObject(obj));
diff --git a/runtime/compiler.cs b/runtime/compiler.cs
index 7a61aede..8b8a30e4 100644
--- a/runtime/compiler.cs
+++ b/runtime/compiler.cs
@@ -62,9 +62,6 @@ static class ByteCodeHelperMethods
internal static readonly MethodInfo DynamicClassLiteral;
internal static readonly MethodInfo DynamicGetfield;
internal static readonly MethodInfo DynamicGetstatic;
- internal static readonly MethodInfo DynamicInvokeSpecialNew;
- internal static readonly MethodInfo DynamicInvokestatic;
- internal static readonly MethodInfo DynamicInvokevirtual;
internal static readonly MethodInfo DynamicMultianewarray;
internal static readonly MethodInfo DynamicNewarray;
internal static readonly MethodInfo DynamicNewCheckOnly;
@@ -73,6 +70,7 @@ static class ByteCodeHelperMethods
internal static readonly MethodInfo DynamicCreateDelegate;
internal static readonly MethodInfo DynamicLoadMethodType;
internal static readonly MethodInfo DynamicLoadMethodHandle;
+ internal static readonly MethodInfo DynamicBinderMemberLookup;
internal static readonly MethodInfo VerboseCastFailure;
internal static readonly MethodInfo SkipFinalizer;
internal static readonly MethodInfo DynamicInstanceOf;
@@ -113,9 +111,6 @@ static class ByteCodeHelperMethods
DynamicClassLiteral = typeofByteCodeHelper.GetMethod("DynamicClassLiteral");
DynamicGetfield = typeofByteCodeHelper.GetMethod("DynamicGetfield");
DynamicGetstatic = typeofByteCodeHelper.GetMethod("DynamicGetstatic");
- DynamicInvokeSpecialNew = typeofByteCodeHelper.GetMethod("DynamicInvokeSpecialNew");
- DynamicInvokestatic = typeofByteCodeHelper.GetMethod("DynamicInvokestatic");
- DynamicInvokevirtual = typeofByteCodeHelper.GetMethod("DynamicInvokevirtual");
DynamicMultianewarray = typeofByteCodeHelper.GetMethod("DynamicMultianewarray");
DynamicNewarray = typeofByteCodeHelper.GetMethod("DynamicNewarray");
DynamicNewCheckOnly = typeofByteCodeHelper.GetMethod("DynamicNewCheckOnly");
@@ -124,6 +119,7 @@ static class ByteCodeHelperMethods
DynamicCreateDelegate = typeofByteCodeHelper.GetMethod("DynamicCreateDelegate");
DynamicLoadMethodType = typeofByteCodeHelper.GetMethod("DynamicLoadMethodType");
DynamicLoadMethodHandle = typeofByteCodeHelper.GetMethod("DynamicLoadMethodHandle");
+ DynamicBinderMemberLookup = typeofByteCodeHelper.GetMethod("DynamicBinderMemberLookup");
VerboseCastFailure = typeofByteCodeHelper.GetMethod("VerboseCastFailure");
SkipFinalizer = typeofByteCodeHelper.GetMethod("SkipFinalizer");
DynamicInstanceOf = typeofByteCodeHelper.GetMethod("DynamicInstanceOf");
@@ -1547,8 +1543,7 @@ sealed class Compiler
case NormalizedByteCode.__dynamic_invokestatic:
case NormalizedByteCode.__invokestatic:
{
- ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(instr.Arg1);
- MethodWrapper method = GetMethodCallEmitter(cpi, instr.NormalizedOpCode);
+ MethodWrapper method = GetMethodCallEmitter(instr.NormalizedOpCode, instr.Arg1);
if(method.IsIntrinsic && method.EmitIntrinsic(new EmitIntrinsicContext(method, context, ilGenerator, ma, i, mw, classFile, code, flags)))
{
break;
@@ -1575,7 +1570,7 @@ sealed class Compiler
case NormalizedByteCode.__methodhandle_invokeexact:
{
bool isinvokespecial = instr.NormalizedOpCode == NormalizedByteCode.__invokespecial || instr.NormalizedOpCode == NormalizedByteCode.__dynamic_invokespecial;
- MethodWrapper method = GetMethodCallEmitter(classFile.GetMethodref(instr.Arg1), instr.NormalizedOpCode);
+ MethodWrapper method = GetMethodCallEmitter(instr.NormalizedOpCode, instr.Arg1);
int argcount = method.GetParameters().Length;
TypeWrapper type = ma.GetRawStackTypeWrapper(i, argcount);
TypeWrapper thisType = SigTypeToClassName(type, method.DeclaringType);
@@ -1589,6 +1584,7 @@ sealed class Compiler
nonleaf = true;
+ // HACK this code is duplicated in java.lang.invoke.cs
if(method.IsProtected && (method.DeclaringType == java_lang_Object || method.DeclaringType == java_lang_Throwable))
{
// HACK we may need to redirect finalize or clone from java.lang.Object/Throwable
@@ -3098,7 +3094,7 @@ sealed class Compiler
ClassFile.ConstantPoolItemMI cpiMI;
if (mw == null && (cpiMI = mh.MemberConstantPoolItem as ClassFile.ConstantPoolItemMI) != null)
{
- mw = new DynamicMethodWrapper(compiler.context, cpiMI, Modifiers.Public | Modifiers.Static);
+ mw = new DynamicBinder().Get(compiler.context, ClassFile.RefKind.invokeStatic, cpiMI);
}
if (mw == null || !mw.IsStatic)
{
@@ -3556,19 +3552,6 @@ sealed class Compiler
private void CastInterfaceArgs(TypeWrapper declaringType, TypeWrapper[] args, int instructionIndex, bool instanceMethod)
{
bool needsCast = false;
- bool dynamic;
- switch(m.Instructions[instructionIndex].NormalizedOpCode)
- {
- case NormalizedByteCode.__dynamic_invokeinterface:
- case NormalizedByteCode.__dynamic_invokestatic:
- case NormalizedByteCode.__dynamic_invokevirtual:
- dynamic = true;
- break;
- default:
- dynamic = false;
- break;
- }
-
int firstCastArg = -1;
if(!needsCast)
@@ -3648,13 +3631,24 @@ sealed class Compiler
dh.Store(i);
}
}
+ if(instanceMethod && args[0].IsUnloadable && !declaringType.IsUnloadable)
+ {
+ if(declaringType.IsInterface)
+ {
+ ilGenerator.EmitAssertType(declaringType.TypeAsTBD);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Castclass, declaringType.TypeAsSignatureType);
+ }
+ }
for(int i = firstCastArg; i < args.Length; i++)
{
if(i != firstCastArg)
{
dh.Load(i);
}
- if(!args[i].IsUnloadable && args[i].IsGhost && !dynamic)
+ if(!args[i].IsUnloadable && args[i].IsGhost)
{
if(i == 0 && instanceMethod && !declaringType.IsInterface)
{
@@ -3681,7 +3675,7 @@ sealed class Compiler
}
else
{
- if(!args[i].IsUnloadable && !dynamic)
+ if(!args[i].IsUnloadable)
{
if(args[i].IsNonPrimitiveValueType)
{
@@ -3864,66 +3858,98 @@ sealed class Compiler
}
}
- private sealed class DynamicMethodWrapper : MethodWrapper
+ private sealed class DynamicBinder
{
- private readonly DynamicTypeWrapper.FinishContext context;
- private readonly ClassFile.ConstantPoolItemMI cpi;
+ private MethodWrapper mw;
- internal DynamicMethodWrapper(DynamicTypeWrapper.FinishContext context, ClassFile.ConstantPoolItemMI cpi, Modifiers modifiers)
- : base(cpi.GetClassType(), cpi.Name, cpi.Signature, null, cpi.GetRetType(), cpi.GetArgTypes(), modifiers, MemberFlags.None)
+ internal MethodWrapper Get(DynamicTypeWrapper.FinishContext context, ClassFile.RefKind kind, ClassFile.ConstantPoolItemMI cpi)
{
- this.context = context;
- this.cpi = cpi;
+ return mw ?? (mw = new DynamicBinderMethodWrapper(cpi, Emit(context, kind, cpi), kind));
}
- internal override void EmitCall(CodeEmitter ilgen)
+ private static MethodInfo Emit(DynamicTypeWrapper.FinishContext context, ClassFile.RefKind kind, ClassFile.ConstantPoolItemMI cpi)
{
- Emit(ByteCodeHelperMethods.DynamicInvokestatic, ilgen, cpi.GetRetType());
+ TypeWrapper ret;
+ TypeWrapper[] args;
+ if (kind == ClassFile.RefKind.invokeStatic)
+ {
+ ret = cpi.GetRetType();
+ args = cpi.GetArgTypes();
+ }
+ else if (kind == ClassFile.RefKind.newInvokeSpecial)
+ {
+ ret = cpi.GetClassType();
+ args = cpi.GetArgTypes();
+ }
+ else
+ {
+ ret = cpi.GetRetType();
+ args = new TypeWrapper[cpi.GetArgTypes().Length + 1];
+ Array.Copy(cpi.GetArgTypes(), 0, args, 1, args.Length - 1);
+ args[0] = cpi.GetClassType();
+ }
+ Type delegateType = MethodHandleUtil.CreateDelegateType(args, ret);
+ FieldBuilder fb = context.DefineMethodHandleInvokeCacheField(delegateType);
+ Type[] types = new Type[args.Length];
+ for (int i = 0; i < types.Length; i++)
+ {
+ types[i] = args[i].TypeAsSignatureType;
+ }
+ MethodBuilder mb = context.DefineMethodHandleDispatchStub(ret.TypeAsSignatureType, types);
+ CodeEmitter ilgen = CodeEmitter.Create(mb);
+ ilgen.Emit(OpCodes.Ldsfld, fb);
+ CodeEmitterLabel label = ilgen.DefineLabel();
+ ilgen.EmitBrtrue(label);
+ ilgen.EmitLdc_I4((int)kind);
+ ilgen.Emit(OpCodes.Ldstr, cpi.Class);
+ ilgen.Emit(OpCodes.Ldstr, cpi.Name);
+ ilgen.Emit(OpCodes.Ldstr, cpi.Signature);
+ context.EmitCallerID(ilgen);
+ ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.DynamicBinderMemberLookup.MakeGenericMethod(delegateType));
+ ilgen.Emit(OpCodes.Volatile);
+ ilgen.Emit(OpCodes.Stsfld, fb);
+ ilgen.MarkLabel(label);
+ ilgen.Emit(OpCodes.Ldsfld, fb);
+ for (int i = 0; i < args.Length; i++)
+ {
+ ilgen.EmitLdarg(i);
+ }
+ MethodHandleUtil.EmitCallDelegateInvokeMethod(ilgen, delegateType);
+ ilgen.Emit(OpCodes.Ret);
+ ilgen.DoEmit();
+ return mb;
}
- internal override void EmitCallvirt(CodeEmitter ilgen)
+ private sealed class DynamicBinderMethodWrapper : MethodWrapper
{
- Emit(ByteCodeHelperMethods.DynamicInvokevirtual, ilgen, cpi.GetRetType());
- }
+ private readonly MethodInfo method;
- internal override void EmitNewobj(CodeEmitter ilgen)
- {
- Emit(ByteCodeHelperMethods.DynamicInvokeSpecialNew, ilgen, cpi.GetClassType());
- }
+ internal DynamicBinderMethodWrapper(ClassFile.ConstantPoolItemMI cpi, MethodInfo method, ClassFile.RefKind kind)
+ : base(cpi.GetClassType(), cpi.Name, cpi.Signature, null, cpi.GetRetType(), cpi.GetArgTypes(), kind == ClassFile.RefKind.invokeStatic ? Modifiers.Public | Modifiers.Static : Modifiers.Public, MemberFlags.None)
+ {
+ this.method = method;
+ }
- private void Emit(MethodInfo helperMethod, CodeEmitter ilGenerator, TypeWrapper retTypeWrapper)
- {
- Profiler.Count("EmitDynamicInvokeEmitter");
- TypeWrapper[] args = cpi.GetArgTypes();
- CodeEmitterLocal argarray = ilGenerator.DeclareLocal(JVM.Import(typeof(object[])));
- CodeEmitterLocal val = ilGenerator.DeclareLocal(Types.Object);
- ilGenerator.EmitLdc_I4(args.Length);
- ilGenerator.Emit(OpCodes.Newarr, Types.Object);
- ilGenerator.Emit(OpCodes.Stloc, argarray);
- for(int i = args.Length - 1; i >= 0; i--)
+ internal override void EmitCall(CodeEmitter ilgen)
{
- if(args[i].IsPrimitive)
- {
- ilGenerator.Emit(OpCodes.Box, args[i].TypeAsTBD);
- }
- ilGenerator.Emit(OpCodes.Stloc, val);
- ilGenerator.Emit(OpCodes.Ldloc, argarray);
- ilGenerator.EmitLdc_I4(i);
- ilGenerator.Emit(OpCodes.Ldloc, val);
- ilGenerator.Emit(OpCodes.Stelem_Ref);
+ ilgen.Emit(OpCodes.Call, method);
+ }
+
+ internal override void EmitCallvirt(CodeEmitter ilgen)
+ {
+ ilgen.Emit(OpCodes.Call, method);
+ }
+
+ internal override void EmitNewobj(CodeEmitter ilgen)
+ {
+ ilgen.Emit(OpCodes.Call, method);
}
- ilGenerator.Emit(OpCodes.Ldstr, cpi.Class);
- ilGenerator.Emit(OpCodes.Ldstr, cpi.Name);
- ilGenerator.Emit(OpCodes.Ldstr, cpi.Signature);
- ilGenerator.Emit(OpCodes.Ldloc, argarray);
- context.EmitCallerID(ilGenerator);
- ilGenerator.Emit(OpCodes.Call, helperMethod);
- EmitReturnTypeConversion(ilGenerator, retTypeWrapper);
}
}
- private MethodWrapper GetMethodCallEmitter(ClassFile.ConstantPoolItemMI cpi, NormalizedByteCode invoke)
+ private MethodWrapper GetMethodCallEmitter(NormalizedByteCode invoke, int constantPoolIndex)
{
+ ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(constantPoolIndex);
#if STATIC_COMPILER
if(replacedMethodWrappers != null)
{
@@ -3954,10 +3980,13 @@ sealed class Compiler
mw = cpi.GetMethod();
break;
case NormalizedByteCode.__dynamic_invokeinterface:
+ return context.GetValue<DynamicBinder>(constantPoolIndex).Get(context, ClassFile.RefKind.invokeInterface, cpi);
case NormalizedByteCode.__dynamic_invokestatic:
+ return context.GetValue<DynamicBinder>(constantPoolIndex).Get(context, ClassFile.RefKind.invokeStatic, cpi);
case NormalizedByteCode.__dynamic_invokevirtual:
+ return context.GetValue<DynamicBinder>(constantPoolIndex).Get(context, ClassFile.RefKind.invokeVirtual, cpi);
case NormalizedByteCode.__dynamic_invokespecial:
- return new DynamicMethodWrapper(context, cpi, Modifiers.Public);
+ return context.GetValue<DynamicBinder>(constantPoolIndex).Get(context, ClassFile.RefKind.newInvokeSpecial, cpi);
case NormalizedByteCode.__methodhandle_invoke:
return new MethodHandleMethodWrapper(context, clazz, cpi, false);
case NormalizedByteCode.__methodhandle_invokeexact:
@@ -3967,7 +3996,19 @@ sealed class Compiler
}
if(mw.IsDynamicOnly)
{
- return new DynamicMethodWrapper(context, cpi, mw.Modifiers);
+ switch (invoke)
+ {
+ case NormalizedByteCode.__invokespecial:
+ return context.GetValue<DynamicBinder>(constantPoolIndex).Get(context, ClassFile.RefKind.invokeSpecial, cpi);
+ case NormalizedByteCode.__invokeinterface:
+ return context.GetValue<DynamicBinder>(constantPoolIndex).Get(context, ClassFile.RefKind.invokeInterface, cpi);
+ case NormalizedByteCode.__invokestatic:
+ return context.GetValue<DynamicBinder>(constantPoolIndex).Get(context, ClassFile.RefKind.invokeStatic, cpi);
+ case NormalizedByteCode.__invokevirtual:
+ return context.GetValue<DynamicBinder>(constantPoolIndex).Get(context, ClassFile.RefKind.invokeVirtual, cpi);
+ default:
+ throw new InvalidOperationException();
+ }
}
return mw;
}