MSDN Magazine - February 2008 - (Page 72) Figure 15 Bridging a Callsite to an LCG Method // delegate used to call the LCG bridge method delegate object callsite(object[] args); // dictionary used to map the callsite to the bridge method static Dictionary callsiteCache = new Dictionary (); // call method used in compiler runtime library public static void Call(object obj, string methodName, object[] args) { if (!callsiteCache.ContainsKey(“methodName”)) { // first time we’ve seen the callsite MethodInfo method = obj.GetType().GetMethod(methodName); int parameterLength = method.GetParameters().Length; DynamicMethod dm = new DynamicMethod(“wrapper”, typeof(object), new Type[] { typeof(object[]) }, typeof(callsite), true); ILGenerator il = dm.GetILGenerator(); Label l1 = il.DefineLabel(); LocalBuilder returnLocal = il.DeclareLocal(typeof(object)); // calling convention for the wrapper is // [0] == instance object // [1..n] == args // pull out the instance object il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ldelem_Ref); // cast the instance to the type il.Emit(OpCodes.Castclass, obj.GetType()); } // pull out the parameters to the instance method call // and push them on to the IL stack for (int i = 0; i < parameterLength; i++) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, i + 1); il.Emit(OpCodes.Ldelem_Ref); } // call the wrapped method il.Emit(OpCodes.Call, method); // return what the method invocation returned il.Emit(OpCodes.Stloc, returnLocal); il.Emit(OpCodes.Ldloc, returnLocal); il.Emit(OpCodes.Ret); // create a delegate for the MyMethodWrapper DynamicMethod callsite callsiteDelegate = (callsite)dm.CreateDelegate(typeof(callsite)); callsiteCache.Add(methodName, callsiteDelegate); } // invoke it callsite site = callsiteCache[methodName]; object[] callargs = new object[args.Length+1]; // stash the instance object callargs[0] = obj; for (int i=0;i<args.Length;i++) callargs[i+1] = args[i]; // invoke via a delegate site(callargs); provide you with a foundation to the mysterious world of compiler construction. While you’ll find valuable information online, there are some books you should also check out. I recommend picking up copies of: Compiling for the .NET Common Language Runtime by John Gough (Prentice Hall, 2001), Inside Microsoft IL Assembler by Serge Lidin (Microsoft Press®, 2002), Programming Language Pragmatics by Michael L. Scott (Morgan Kaufmann, 2000), and Compilers: Principles, Techniques, and Tools by Alfred V. Oho, Monica S. Lam, Ravi Sethi, and Jeffrey Ullman (Addison Method calls are the Wesley, 2006). cornerstone of any computer That pretty well covers the core of what you need language, but there’s to understand for writing a spectrum of calls you your own language comcan make. piler; however, I’m not quite finished with this discussion. For the seriously hardcore, I’d like to look at some advanced topics for taking your efforts even further. even Visual Basic, all share this pattern. In order for a compiler to emit code to perform a method invocation, the compiler must treat the method name as a symbol, passing it to a runtime library that will perform the binding and invocation operations as per the language semantics. Suppose you turn off Option Strict in the Visual Basic 8.0 compiler. Method calls become late bound and the Visual Basic runtime will perform the binding and invocation at run time. Rather than the Visual Basic compiler emitting an IL call instruction to the Method1 method, it instead emits a call instruction to the Visual Basic runtime method called CompilerServices.NewLateBinding.LateCall. In doing so, it passes in an object (obj) and the symbolic name of the method (Method1), along with any method arguments. The Visual Basic LateCall method then looks up the Method1 method on the object using Reflection and, if it is found, performs a Reflection-based method invocation: Option Strict Off Dim obj obj.Method1() IL_0001: ldloc.0 IL_0003: ldstr “Method1” IL_0012: call object CompilerServices.NewLateBinding:: LateCall(object, , string, ) Dynamic Method Invocation Method calls are the cornerstone of any computer language, but there’s a spectrum of calls you can make. Newer languages, such as Python, delay the binding of a method and the invocation until the absolute last minute—this is called dynamic invocation. Popular dynamic languages, such as Ruby, JavaScript, Lua, and 72 msdnmagazine .NET Compiler Using LCG to Perform Quick Late-Binding Reflection-based method invocation can be notoriously slow (see my article “Reflection: Dodge Common Performance Pitfalls to
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.