/* Copyright (C) 2008 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jeroen Frijters jeroen@frijters.net */ using System; using System.Reflection; public interface MethodHandle { MethodType type(); } public sealed class MethodHandleImpl : MethodHandle { public readonly T d; public MethodHandleImpl(T d) { this.d = d; } public MethodType type() { throw new NotImplementedException(); } } public sealed class MethodType { } public interface StaticContext { java.lang.Class getCallerClass(); string getName(); MethodType getType(); bool equals(); int hashCode(); } public sealed class StaticContextImpl : StaticContext { private readonly Type caller; private readonly string name; public StaticContextImpl(Type caller, string name) { this.caller = caller; this.name = name; } public java.lang.Class getCallerClass() { return caller; } public string getName() { return name; } public MethodType getType() { throw new NotImplementedException(); } public bool equals() { throw new NotImplementedException(); } public int hashCode() { throw new NotImplementedException(); } } public interface CallSite { MethodHandle getTarget(); void setTarget(MethodHandle target); StaticContext getStaticContext(); } public sealed class CallSiteImpl : CallSite { public volatile MethodHandleImpl mh; private readonly StaticContext context; public CallSiteImpl(StaticContext context) { this.context = context; } public MethodHandle getTarget() { return mh; } public void setTarget(MethodHandle target) { mh = (MethodHandleImpl)target; } public StaticContext getStaticContext() { return context; } } public class MethodHandles { public static MethodHandle unreflect(java.lang.reflect.Method m) { // In the real implementation this would use IKVM internals to convert the Method into a MethodInfo, // but here we use a simplistic name look up. MethodInfo mi = ikvm.runtime.Util.getInstanceTypeFromClass(m.getDeclaringClass()).GetMethod(m.getName(), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (mi.ReturnType == typeof(void)) { ParameterInfo[] pi = mi.GetParameters(); Type[] typeArgs = new Type[pi.Length]; for (int i = 0; i < typeArgs.Length; i++) { typeArgs[i] = pi[i].ParameterType; } Type delegateType = Type.GetType("InvokeDynamicVoid`" + typeArgs.Length).MakeGenericType(typeArgs); Delegate del = Delegate.CreateDelegate(delegateType, mi); Type methodHandleType = typeof(MethodHandleImpl<>).MakeGenericType(delegateType); return (MethodHandle)Activator.CreateInstance(methodHandleType, del); } else { throw new NotImplementedException(); } } } public delegate void InvokeDynamicVoid(T1 t1, T2 t2); public delegate void InvokeDynamicVoid(T1 t1, T2 t2, T3 t3); public delegate T0 InvokeDynamic(T1 t1, T2 t2, T3 t3); class InvokeDynamicPoC { private static InvokeDynamic __bootstrapMethod = bootstrapInvokeDynamic; private static CallSiteImpl> __site1 = new CallSiteImpl>(new StaticContextImpl(typeof(InvokeDynamicPoC), "printSubstring")); private static void Main() { for (int j = 0; j < 2; j++) { int start = Environment.TickCount; for (int i = 0; i < 10/*0000000/**/; i++) { string obj = "invokedynamic"; int arg1 = 3; int arg2 = 2; MethodHandleImpl> mh = __site1.mh; if (mh == null) { __bootstrapMethod(__site1, obj, new object[] { java.lang.Integer.valueOf(arg1), java.lang.Integer.valueOf(arg2) }); } else { mh.d(obj, arg1, arg2); } } int end = Environment.TickCount; Console.WriteLine(end - start); } } private static void printSubstring(string s, int startIndex, int length) { Console.WriteLine(s.Substring(startIndex, length)); } private static object bootstrapInvokeDynamic(CallSite cs, object receiver, object[] arguments) { java.lang.Class c = typeof(InvokeDynamicPoC); java.lang.reflect.Method m = c.getDeclaredMethod(cs.getStaticContext().getName(), typeof(string), typeof(int), typeof(int)); MethodHandle mh = MethodHandles.unreflect(m); cs.setTarget(mh); return m.invoke(null, receiver, arguments[0], arguments[1]); } }