Пример #1
0
        /// <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);
        }
Пример #2
0
        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);
        }
Пример #3
0
 /// <summary>
 /// Adds a trampoline to the builder.
 /// </summary>
 /// <param name="trampoline">The trampoline to add.</param>
 public void Add(Trampoline trampoline)
 {
     trampolines.Add(trampoline);
 }
Пример #4
0
 /// <summary>
 /// Adds a trampoline to the builder.
 /// </summary>
 /// <param name="trampoline">The trampoline to add.</param>
 public void Add(Trampoline trampoline)
 {
     trampolines.Add(trampoline);
 }