/// <summary> /// Builds an implementation method for the specified trampoline. /// </summary> /// <param name="trampoline">The trampoline.</param> /// <param name="typeBuilder">The type builder for the type that will contain the method.</param> static void BuildTrampolineMethod(Trampoline trampoline, TypeBuilder typeBuilder) { if (!trampoline.IsInstanceCall) { BuildFreeCall(trampoline, typeBuilder); return; } var methodName = string.Format("CallInstance{0}", trampoline.ReturnType == typeof(void) ? string.Empty : trampoline.ReturnType.Name); var methodBuilder = typeBuilder.DefineMethod(methodName, trampolineMethodAttributes); var il = methodBuilder.GetILGenerator(); methodBuilder.SetSignature(trampoline.ReturnType, null, null, ExtractTypes(trampoline.ManagedParameterTypes), null, null); methodBuilder.DefineParameter(1, ParameterAttributes.None, offsetParameterName); methodBuilder.DefineParameter(2, ParameterAttributes.None, thisParameterName); // Push the arguments to the native method on the stack. for (int parameterIndex = 0; parameterIndex < trampoline.NativeParameterTypes.Count; ++parameterIndex) { // We use ldarg.1, ldarg.2 and ldarg.3 if possible; these opcodes are much smaller because // they don't require an int8 parameter token (and the JIT won't inline methods over a // certain number of bytes) if (parameterIndex == 0) { il.Emit(OpCodes.Ldarg_1); } else if (parameterIndex == 1) { il.Emit(OpCodes.Ldarg_2); } else if (parameterIndex == 2) { il.Emit(OpCodes.Ldarg_3); } else { il.Emit(OpCodes.Ldarg_S, parameterIndex + 1); } } // Load the instance pointer, and dereference it to leave the base address of // the virtual table on the stack. il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldind_I); // Load the byte offset from the start of the table and add them to yeild // the pointer to the slot containing the desired method's address. il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Add); // Read the table slot, leaving the address of the target method on the stack. il.Emit(OpCodes.Ldind_I); // Finally, call the method. il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, trampoline.ReturnType, ExtractTypes(trampoline.NativeParameterTypes)); il.Emit(OpCodes.Ret); }
static void BuildFreeCall(Trampoline trampoline, TypeBuilder typeBuilder) { var methodName = string.Format("CallFree{0}", trampoline.ReturnType == typeof(void) ? string.Empty : trampoline.ReturnType.Name); var methodBuilder = typeBuilder.DefineMethod(methodName, trampolineMethodAttributes); var il = methodBuilder.GetILGenerator(); methodBuilder.SetSignature(trampoline.ReturnType, null, null, ExtractTypes(trampoline.ManagedParameterTypes), null, null); methodBuilder.DefineParameter(1, ParameterAttributes.None, offsetParameterName); methodBuilder.DefineParameter(2, ParameterAttributes.None, thisParameterName); // Push the arguments to the native method on the stack. for (int parameterIndex = 0; parameterIndex < trampoline.NativeParameterTypes.Count; ++parameterIndex) { // We use ldarg.1, ldarg.2 and ldarg.3 if possible; these opcodes are much smaller because // they don't require an int8 parameter token (and the JIT won't inline methods over a // certain number of bytes) if (parameterIndex == 0) il.Emit(OpCodes.Ldarg_1); else if (parameterIndex == 1) il.Emit(OpCodes.Ldarg_2); else if (parameterIndex == 2) il.Emit(OpCodes.Ldarg_3); else il.Emit(OpCodes.Ldarg_S, parameterIndex + 1); } // Load the instance pointer, and dereference it to leave the base address of // the virtual table on the stack. //il.Emit(OpCodes.Ldarg_1); //il.Emit(OpCodes.Ldind_I); //// Load the byte offset from the start of the table and add them to yeild //// the pointer to the slot containing the desired method's address. // For free functions, the offset is the actual entry point. il.Emit(OpCodes.Ldarg_0); //il.Emit(OpCodes.Add); // Read the table slot, leaving the address of the target method on the stack. //il.Emit(OpCodes.Ldind_I); // Finally, call the method. il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, trampoline.ReturnType, ExtractTypes(trampoline.NativeParameterTypes)); il.Emit(OpCodes.Ret); }
/// <summary> /// Adds a trampoline to the builder. /// </summary> /// <param name="trampoline">The trampoline to add.</param> public void Add(Trampoline trampoline) { trampolines.Add(trampoline); }
/// <summary> /// Adds a trampoline to the builder. /// </summary> /// <param name="trampoline">The trampoline to add.</param> public void Add(Trampoline trampoline) { trampolines.Add(trampoline); }