Пример #1
0
        /// <summary>
        /// Emits a call that obtains the hash code for the current service instance.
        /// </summary>
        /// <param name="il">The <see cref="ILProcessor"/> that points to the method body.</param>
        /// <param name="module">The target module.</param>
        /// <param name="serviceInstance">The local variable that contains the service instance.</param>
        private void GetServiceHash(ILProcessor il, ModuleDefinition module, VariableDefinition serviceInstance)
        {
            il.Emit(OpCodes.Ldloc, serviceInstance);

            var getHashCodeMethod = module.ImportMethod<object>("GetHashCode");
            il.Emit(OpCodes.Callvirt, getHashCodeMethod);
        }
Пример #2
0
		private static void TestSequence1(ILProcessor il)
		{
			TypeReference type = new TypeReference("", "Test", null, null);
			FieldDefinition blank = new FieldDefinition("Test", FieldAttributes.Public, type);
			il.Emit(OpCodes.Nop);
			il.Emit(OpCodes.Ldsfld, blank);
			il.Emit(OpCodes.Stsfld, blank);
			il.Emit(OpCodes.Ret);
		}
Пример #3
0
        /// <summary>
        /// Emit a reference to an arbitrary object. Note that the references "leak."
        /// </summary>
        public static int EmitGetReference <T>(this CIL.ILProcessor il, int id)
        {
            Type t = typeof(T);

            il.Emit(CIL.OpCodes.Ldc_I4, id);
            il.Emit(CIL.OpCodes.Call, _GetReference);
            if (t.GetTypeInfo().IsValueType)
            {
                il.Emit(CIL.OpCodes.Unbox_Any, t);
            }
            return(id);
        }
Пример #4
0
            protected override void ImplementProceed(MethodDefinition methodInfo, MethodBody methodBody, ILProcessor il, FieldReference methodInfoField, MethodReference proceed, Action<ILProcessor> emitProceedTarget, MethodReference proceedTargetMethod, OpCode proceedOpCode)
            {
                // If T is an interface, then we want to check if target is null; if so, we want to just return the default value
                var targetNotNull = il.Create(OpCodes.Nop);
                EmitProxyFromProceed(il);
                il.Emit(OpCodes.Ldfld, ClassWeaver.Target);  // Load "target" from "this"
                il.Emit(OpCodes.Brtrue, targetNotNull);      // If target is not null, jump below
                CecilExtensions.CreateDefaultMethodImplementation(methodBody.Method, il);

                il.Append(targetNotNull);                    // Mark where the previous branch instruction should jump to                        

                base.ImplementProceed(methodInfo, methodBody, il, methodInfoField, proceed, emitProceedTarget, proceedTargetMethod, proceedOpCode);
            }
        /// <summary>
        /// Emit a reference to an arbitrary object. Note that the references "leak."
        /// </summary>
        public static int EmitGetReference <T>(this CIL.ILProcessor il, int id)
        {
            ModuleDefinition ilModule = il.Body.Method.Module;
            Type             t        = typeof(T);

            il.Emit(CIL.OpCodes.Ldc_I4, id);
            il.Emit(CIL.OpCodes.Call, ilModule.ImportReference(_GetReference));
            if (t.IsValueType)
            {
                il.Emit(CIL.OpCodes.Unbox_Any, ilModule.ImportReference(t));
            }
            return(id);
        }
Пример #6
0
        public static void CompileTarget(ILProcessor processor, IAstExpression target, IAstMethodReference function, CilCompilationContext context)
        {
            context.Compile(target);
            if (function.Location == MethodLocation.Extension)
                return;

            var targetType = context.ConvertReference(target.ExpressionType);
            if (!targetType.IsValueType)
                return;

            var variable = context.DefineVariable("x", targetType);
            processor.Emit(OpCodes.Stloc, variable);
            processor.Emit(OpCodes.Ldloca_S, variable);
        }
Пример #7
0
 private void AddFieldConstructorArgument(MethodDefinition constructor, FieldDefinition field, int argumentId, ILProcessor processor)
 {
     constructor.Parameters.Add(new ParameterDefinition(field.Name, ParameterAttributes.None, field.FieldType));
       processor.Emit(OpCodes.Ldarg_0);
       if (argumentId == 1) {
      processor.Emit(OpCodes.Ldarg_1);
       } else if (argumentId == 2) {
      processor.Emit(OpCodes.Ldarg_2);
       } else if (argumentId == 3) {
      processor.Emit(OpCodes.Ldarg_3);
       } else {
      processor.Emit(OpCodes.Ldarg, argumentId);
       }
       processor.Emit(OpCodes.Stfld, field);
 }
 public override void EmitAddress(ILProcessor ilProcessor)
 {
     if (Previous.Type.Resolve().IsValueType)
         Previous.EmitAddress(ilProcessor);
     else
         Previous.Emit(ilProcessor);
     ilProcessor.Emit(OpCodes.Ldflda, Field);
 }
Пример #9
0
 private static void HandleInterceptReturnValue(MethodDefinition method, ILProcessor processor)
 {
     if (method.ReturnType.IsValueType)
     {
         // unbox
         processor.Emit(OpCodes.Unbox_Any, method.ReturnType);
     }
     else if (method.ReturnType == WeavingInformation.ModuleDefinition.TypeSystem.Void)
     {
         // remove return value of intercept method from stack
         processor.Emit(OpCodes.Pop);
     }
     else
     {
         // cast to reference type
         processor.Emit(OpCodes.Castclass, method.ReturnType);
     }
 }
Пример #10
0
        /// <summary>
        /// Emits the instructions that will obtain the <see cref="IMicroContainer"/> instance.
        /// </summary>
        /// <param name="module">The target module.</param>
        /// <param name="microContainerType">The type reference that points to the <see cref="IMicroContainer"/> type.</param>
        /// <param name="worker">The <see cref="CilWorker"/> that points to the <see cref="IMicroContainer.GetInstance"/> method body.</param>
        /// <param name="skipCreate">The skip label that will be used if the service cannot be instantiated.</param>
        protected override void EmitGetContainerInstance(ModuleDefinition module, TypeReference microContainerType, ILProcessor il, Instruction skipCreate)
        {
            var getNextContainer = module.ImportMethod<IMicroContainer>("get_NextContainer");
            EmitGetNextContainerCall(il, microContainerType, getNextContainer);
            il.Emit(OpCodes.Brfalse, skipCreate);

            // var result = NextContainer.GeService(serviceType, serviceName);
            EmitGetNextContainerCall(il, microContainerType, getNextContainer);
        }
Пример #11
0
 /// <summary>
 /// Fill the DynamicMethod with a stub.
 /// </summary>
 public static DynamicMethodDefinition Stub(this DynamicMethodDefinition dmd)
 {
     CIL.ILProcessor il = dmd.GetILProcessor();
     for (int i = 0; i < 32; i++)
     {
         // Prevent mono from inlining the DynamicMethod.
         il.Emit(CIL.OpCodes.Nop);
     }
     if (dmd.Definition.ReturnType != dmd.Definition.Module.TypeSystem.Void)
     {
         il.Body.Variables.Add(new CIL.VariableDefinition(dmd.Definition.ReturnType));
         il.Emit(CIL.OpCodes.Ldloca_S, (sbyte)0);
         il.Emit(CIL.OpCodes.Initobj, dmd.Definition.ReturnType);
         il.Emit(CIL.OpCodes.Ldloc_0);
     }
     il.Emit(CIL.OpCodes.Ret);
     return(dmd);
 }
Пример #12
0
            protected override void ImplementProceed(MethodDefinition methodInfo, MethodBody methodBody, ILProcessor il, FieldReference methodInfoField, MethodReference proceed, Action<ILProcessor> emitProceedTarget, MethodReference proceedTargetMethod, OpCode proceedOpCode)
            {
                if (methodInfo.IsAbstract)
                {
                    CecilExtensions.CreateDefaultMethodImplementation(methodInfo, il);
                }
                else
                {
                    var targetNotNull = il.Create(OpCodes.Nop);
                    EmitProxyFromProceed(il);
                    il.Emit(OpCodes.Ldfld, target);              // Load "target" from "this"
                    il.Emit(OpCodes.Brtrue, targetNotNull);      // If target is not null, jump below

                    base.ImplementProceed(methodInfo, methodBody, il, methodInfoField, proceed, _ => EmitProxyFromProceed(il), callBaseMethod, OpCodes.Call);

                    il.Append(targetNotNull);                    // Mark where the previous branch instruction should jump to                        
                
                    base.ImplementProceed(methodInfo, methodBody, il, methodInfoField, proceed, emitProceedTarget, proceedTargetMethod, proceedOpCode);
                }
            }
        private static void Emit(ILProcessor ip, ModuleDefinition mod, VariableDefinition arrayVar, VariableDefinition indexVar, Dictionary<int, Instruction> braces, OpValue[] ops, int i)
        {
            OpValue op = ops[i];
            switch (op.OpCode)
            {
                case BFOpCode.Increment:
                    ip.Emit(OpCodes.Ldloc, arrayVar);
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldloc, arrayVar);
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldelem_I4);
                    ip.Emit(OpCodes.Ldc_I4, op.Data);
                    ip.Emit(OpCodes.Add);
                    ip.Emit(OpCodes.Stelem_I4);
                    break;

                case BFOpCode.Decrement:
                    ip.Emit(OpCodes.Ldloc, arrayVar);
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldloc, arrayVar);
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldelem_I4);
                    ip.Emit(OpCodes.Ldc_I4, op.Data);
                    ip.Emit(OpCodes.Sub);
                    ip.Emit(OpCodes.Stelem_I4);
                    break;

                case BFOpCode.ShiftRight:
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldc_I4, op.Data);
                    ip.Emit(OpCodes.Add);
                    ip.Emit(OpCodes.Stloc, indexVar);
                    break;

                case BFOpCode.ShiftLeft:
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldc_I4, op.Data);
                    ip.Emit(OpCodes.Sub);
                    ip.Emit(OpCodes.Stloc, indexVar);
                    break;

                case BFOpCode.Output:
                    ip.Emit(OpCodes.Ldloc, arrayVar);
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldelem_I4);
                    ip.Emit(OpCodes.Conv_I1);
                    ip.Emit(OpCodes.Call, mod.Import(typeof(Console).GetMethod("Write", new[] { typeof(char) })));
                    break;

                case BFOpCode.Input:
                    ip.Emit(OpCodes.Call, mod.Import(typeof(Console).GetMethod("Read", new Type[0])));
                    ip.Emit(OpCodes.Ldloc, arrayVar);
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldelem_I4);
                    ip.Emit(OpCodes.Conv_I1);
                    break;

                case BFOpCode.CondLeft:
                    var leftB = ip.Create(OpCodes.Ldloc, arrayVar);
                    var rightB = ip.Create(OpCodes.Nop);
                    ip.Append(leftB);
                    braces[i] = leftB;
                    braces[op.Data] = rightB;
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldelem_I4);
                    ip.Emit(OpCodes.Brfalse, rightB);
                    ip.Emit(OpCodes.Nop);
                    break;

                case BFOpCode.CondRight:
                    ip.Emit(OpCodes.Br, braces[op.Data]);
                    ip.Append(braces[i]);
                    break;

                case BFOpCode.Assign:
                    ip.Emit(OpCodes.Ldloc, arrayVar);
                    ip.Emit(OpCodes.Ldloc, indexVar);
                    ip.Emit(OpCodes.Ldc_I4, op.Data);
                    ip.Emit(OpCodes.Stelem_I4);
                    break;
            }
        }
Пример #14
0
 static void EmitCall(ILProcessor il, MethodReference reference)
 {
     il.Emit(OpCodes.Call, reference);
 }
Пример #15
0
        static void EmitCalli(ILProcessor il, MethodReference reference)
        {
            var signature = new CallSite(reference.ReturnType)
            {
                CallingConvention = MethodCallingConvention.StdCall,
            };

            foreach (var p in reference.Parameters)
            {
                signature.Parameters.Add(p);
            }

            // Since the last parameter is always the entry point address,
            // we do not need any special preparation before emiting calli.
            il.Emit(OpCodes.Calli, signature);
        }
Пример #16
0
 static void EmitEntryPoint(FieldDefinition entry_points, ILProcessor il, int slot)
 {
     il.Emit(OpCodes.Ldsfld, entry_points);
     il.Emit(OpCodes.Ldc_I4, slot);
     il.Emit(OpCodes.Ldelem_I);
 }
Пример #17
0
		private void LoadActivatorField(ILProcessor cil)
		{
			cil.Emit(OpCodes.Ldarg_0);
			cil.Emit(OpCodes.Ldfld, _activatorField);
		}
Пример #18
0
        /// <summary>
        /// Emits the instructions that will instantiate each property value and assign it to the target property.
        /// </summary>
        /// <param name="serviceMap">The service map that contains the application dependencies.</param>
        /// <param name="targetMethod">The target method.</param>
        /// <param name="module">The module that hosts the container type.</param>
        /// <param name="il">The <see cref="ILProcessor"/> that points to the target method body.</param>
        /// <param name="property">The target property.</param>
        /// <param name="curentDependency">The <see cref="IDependency"/> that describes the service instance that will be assigned to the target property.</param>
        private static void EmitPropertySetter(IDictionary<IDependency, IImplementation> serviceMap, MethodDefinition targetMethod, ModuleDefinition module, ILProcessor il, PropertyInfo property, IDependency curentDependency)
        {
            // Push the target onto the stack
            il.Emit(OpCodes.Dup);

            // Get the code that will instantiate the property value
            var propertyValueImplementation = serviceMap[curentDependency];
            propertyValueImplementation.Emit(curentDependency, serviceMap, targetMethod);

            // Call the setter
            var setterMethod = property.GetSetMethod();
            var setter = module.Import(setterMethod);

            var callInstruction = setterMethod.IsVirtual ? il.Create(OpCodes.Callvirt, setter) : il.Create(OpCodes.Call, setter);
            il.Append(callInstruction);
        }
Пример #19
0
        static void EmitStringEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il)
        {
            var p = parameter.ParameterType;
            var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringPtr"));

            // FreeStringPtr(ptr)
            var variable_name = parameter.Name + "_string_ptr";
            var v = body.Variables.First(m => m.Name == variable_name);
            il.Emit(OpCodes.Ldloc, v.Index);
            il.Emit(OpCodes.Call, free);
        }
Пример #20
0
        static void EmitStringArrayParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il)
        {
            var p = parameter.ParameterType;

            // string[] masrhaling:
            // IntPtr ptr = MarshalStringArrayToPtr(strings);
            // try { calli }
            // finally { FreeStringArrayPtr(ptr); }
            var marshal_str_array_to_ptr = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringArrayToPtr"));

            // IntPtr ptr;
            var variable_name = parameter.Name + "_string_array_ptr";
            body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
            int index = body.Variables.Count - 1;

            // ptr = MarshalStringArrayToPtr(strings);
            il.Emit(OpCodes.Call, marshal_str_array_to_ptr);
            il.Emit(OpCodes.Stloc, index);
            il.Emit(OpCodes.Ldloc, index);

            // The finally block will be emitted in the function epilogue
        }
Пример #21
0
            protected override void ImplementBody(ILProcessor il, FieldReference methodInfoField, FieldReference propertyInfoField, MethodReference proceed, MethodReference proceedTargetMethod)
            {
                // If it's abstract, then the method is entirely implemented by the InvocationHandler
                if (Method.IsAbstract)
                {
                    base.ImplementBody(il, methodInfoField, propertyInfoField, proceed, proceedTargetMethod);
                }
                // Otherwise, it is implemented by the class itself, and calling this.Invocation().Proceed() calls the InvocationHandler
                else
                {
                    Method.Body.InitLocals = true;

                    // First declare the invocation in a private local variable
                    var invocation = new VariableDefinition(ClassWeaver.Context.InvocationType);
                    var instructions = Method.Body.Instructions.ToList();
                    Method.Body.Instructions.Clear();                   // Wipe out the existing instructions for the method
                    Method.Body.Variables.Add(invocation);              // Add a variable to store the invocation
                    EmitInvocation(il, methodInfoField, propertyInfoField, proceed);       // Put the invocation on the stack
                    il.Emit(OpCodes.Dup);                               // Duplicate invocation for below
                    il.Emit(OpCodes.Stloc, invocation);                 // Store the invocation in the variable declared (just) earlier

                    // Add the invocation to the end of the array
                    il.Emit(OpCodes.Call, ClassWeaver.Context.InvocationGetArguments);  // Array now on the stack with the invocation above it
                    il.Emit(OpCodes.Ldc_I4, Method.Parameters.Count);       // Array index
                    il.Emit(OpCodes.Ldloc, invocation);                     // Element value
                    il.Emit(OpCodes.Stelem_Any, ClassWeaver.Context.ModuleDefinition.TypeSystem.Object);  // Set array at index to element value

                    // Special instrumentation for async methods
                    var returnType = Method.ReturnType;
                    if (ClassWeaver.Context.TaskType.IsAssignableFrom(returnType))
                    {
                        // If the return type is Task<T>
                        if (returnType.IsTaskT())
                        {
                            var actualReturnType = returnType.GetTaskType();
                            var expectedAsyncBuilder = ClassWeaver.Context.AsyncTaskMethodBuilder.MakeGenericInstanceType(actualReturnType);

                            // Now find the call to .Start() (only will be found if we're async)
                            var startInstructionMethod = (GenericInstanceMethod)instructions
                                .Where(x => x.OpCode == OpCodes.Call)
                                .Select(x => (MethodReference)x.Operand)
                                .Where(x => x.IsGenericInstance && x.Name == "Start" && x.DeclaringType.CompareTo(expectedAsyncBuilder))
                                .SingleOrDefault();
                            if (startInstructionMethod != null)
                            {
                                var asyncType = startInstructionMethod.GenericArguments[0];
                                var invocationField = InstrumentAsyncType(asyncType);

                                // Find the first instruction that is setting a field on the async type.  We can just assume it's a three instruction 
                                // set (it always is in this context)  And we add our instructions to set the invocation field.
                                var nextSetFieldIndex = instructions.IndexOf(x => x.OpCode == OpCodes.Stfld && x.Operand is FieldDefinition && ((FieldDefinition)x.Operand).DeclaringType.CompareTo(asyncType));
                                if (nextSetFieldIndex == -1)
                                    throw new Exception($"Could not find expected stfld of async type: {asyncType}");
                                var setFieldLoadInstance = instructions[nextSetFieldIndex - 2];
                                instructions.Insert(nextSetFieldIndex - 2, il.Clone(setFieldLoadInstance));
                                instructions.Insert(nextSetFieldIndex - 1, il.Create(OpCodes.Ldloc, invocation));
                                instructions.Insert(nextSetFieldIndex, il.Create(OpCodes.Stfld, invocationField));
                            }
                        }
                    }

                    InstrumentInstructions(il, instructions, 2, x => x.Emit(OpCodes.Ldloc, invocation));
                }
            }
Пример #22
0
        static void EmitStringBuilderEpilogue(MethodDefinition wrapper, MethodDefinition native, ParameterDefinition parameter, MethodBody body, ILProcessor il)
        {
            var p = parameter.ParameterType;
            if (p.Name == "StringBuilder")
            {
                // void GetShaderInfoLog(..., StringBuilder foo)
                // try {
                //  foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1); -- already emitted
                //  glGetShaderInfoLog(..., foo_sb_ptr); -- already emitted
                //  MarshalPtrToStringBuilder(foo_sb_ptr, foo);
                // }
                // finally {
                //  Marshal.FreeHGlobal(foo_sb_ptr);
                // }

                // Make sure we have imported BindingsBase::MasrhalPtrToStringBuilder and Marshal::FreeHGlobal
                var ptr_to_sb = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalPtrToStringBuilder"));
                var free_hglobal = wrapper.Module.Import(TypeMarshal.Methods.First(m => m.Name == "FreeHGlobal"));

                var block = new ExceptionHandler(ExceptionHandlerType.Finally);
                block.TryStart = body.Instructions[0];

                var variable_name = parameter.Name + " _sb_ptr";
                var v = body.Variables.First(m => m.Name == variable_name);
                il.Emit(OpCodes.Ldloc, v.Index);
                il.Emit(OpCodes.Ldarg, parameter.Index);
                il.Emit(OpCodes.Call, ptr_to_sb);

                block.TryEnd = body.Instructions.Last();
                block.HandlerStart = body.Instructions.Last();

                il.Emit(OpCodes.Ldloc, v.Index);
                il.Emit(OpCodes.Call, free_hglobal);

                block.HandlerEnd = body.Instructions.Last();
            }
        }
Пример #23
0
        private static void EmitReturnTypeWrapper(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il)
        {
            if (wrapper.Parameters.Count < native.Parameters.Count)
            {
                // Convenience wrapper. The result is stored in the last local variable
                il.Emit(OpCodes.Ldloc, body.Variables.Count - 1);
            }
            else if (wrapper.ReturnType != native.ReturnType)
            {
                if (wrapper.ReturnType.Name == "String")
                {
                    // String return-type wrapper
                    // return new string((sbyte*)((void*)GetString()));

                    var intptr_to_voidpointer = wrapper.Module.Import(mscorlib.MainModule.GetType("System.IntPtr").GetMethods()
                        .First(m =>
                    {
                        return
                                m.Name == "op_Explicit" &&
                        m.ReturnType.Name == "Void*";
                    }));

                    var string_constructor = wrapper.Module.Import(mscorlib.MainModule.GetType("System.String").GetConstructors()
                        .First(m =>
                    {
                        var p = m.Parameters;
                        return p.Count > 0 && p[0].ParameterType.Name == "SByte*";
                    }));

                    il.Emit(OpCodes.Call, intptr_to_voidpointer);
                    il.Emit(OpCodes.Newobj, string_constructor);
                }
                else if (wrapper.ReturnType.Resolve().IsEnum)
                {
                    // Nothing to do
                }
                else if (wrapper.ReturnType.Name == "Boolean" && native.ReturnType.Name == "Byte")
                {
                    // Nothing to do
                    // It appears that a byte with 1 = true (GL_TRUE) and 0 = false (GL_FALSE)
                    // can be reinterpreted as a bool without a problem.
                    // Todo: maybe we should return (value == 0 ? false : true) just to be
                    // on the safe side?
                }
                else
                {
                    Console.Error.WriteLine("Return wrapper for '{1}' not implemented yet ({0})", native.Name, wrapper.ReturnType.Name);
                }
            }
            else
            {
                // nothing to do, the native call leaves the return value
                // on the stack and we return that unmodified to the caller.
            }
        }
Пример #24
0
        static void EmitDebugEpilogue(MethodDefinition wrapper, ILProcessor il, DebugVariables vars)
        {
            if (vars != null)
            {
                var disposeMethod = vars.ErrorHelperType.Methods.First(
                    method => method.Name == "Dispose");

                // Store then reload the result from the call
                var resultLocal = new VariableDefinition(wrapper.ReturnType);
                if (resultLocal.VariableType.FullName != Program.TypeVoid.FullName)
                {
                    il.Body.Variables.Add(resultLocal);
                    il.Emit(OpCodes.Stloc, resultLocal);
                }

                // Special case End to turn on error checking.
                if (il.Body.Method.Name == "End")
                {
                    il.Emit(OpCodes.Call, vars.Get_CurrentContext);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Conv_I1);
                    il.Emit(OpCodes.Call, vars.Set_ErrorChecking);
                }

                // We need a NOP to set up the finally handler range correctly.
                var nopInstruction = Instruction.Create(OpCodes.Nop);
                var loadInstruction = Instruction.Create(OpCodes.Ldloca, vars.ErrorHelperLocal);
                var disposeInstruction = Instruction.Create(OpCodes.Call, disposeMethod);
                var endFinallyInstruction = Instruction.Create(OpCodes.Endfinally);
                var endTryInstruction = Instruction.Create(OpCodes.Leave, nopInstruction);

                il.Append(endTryInstruction);
                il.Append(loadInstruction);
                il.Append(disposeInstruction);
                il.Append(endFinallyInstruction);
                il.Append(nopInstruction);

                var finallyHandler = new ExceptionHandler(ExceptionHandlerType.Finally);
                finallyHandler.TryStart = vars.BeginTry;
                finallyHandler.TryEnd = loadInstruction;
                finallyHandler.HandlerStart = loadInstruction;
                finallyHandler.HandlerEnd = nopInstruction;

                il.Body.ExceptionHandlers.Add(finallyHandler);

                if (resultLocal.VariableType.FullName != Program.TypeVoid.FullName)
                {
                    il.Emit(OpCodes.Ldloc, resultLocal);
                }
            }
        }
Пример #25
0
        static DebugVariables EmitDebugPrologue(MethodDefinition wrapper, ILProcessor il)
        {

            DebugVariables vars = null;
            if (il.Body.Method.Name != "GetError")
            {
                // Pull out the namespace name, method fullname will look 
                // something like "type namespace.class::method(type arg)"
                var module = il.Body.Method.FullName;
                module = module.Substring(module.IndexOf(' ') + 1);
                module = module.Substring(0, module.IndexOf("::"));
                module = module.Substring(0, module.LastIndexOf('.'));

                // Only works for Graphics modules due to hardcoded use of
                // OpenTK.Graphics.GraphicsContext
                if (module == "OpenTK.Graphics.OpenGL4" ||
                    module == "OpenTK.Graphics.OpenGL" ||
                    module == "OpenTK.Graphics.ES10" ||
                    module == "OpenTK.Graphics.ES11" ||
                    module == "OpenTK.Graphics.ES20" ||
                    module == "OpenTK.Graphics.ES30")
                {
                    var errorHelperType = wrapper.Module.GetType(module, "ErrorHelper");

                    if (errorHelperType != null)
                    {
                        vars = new DebugVariables();
                        vars.ErrorHelperType = errorHelperType;

                        // GraphicsContext type
                        var graphicsContext = wrapper.Module.Types.First(
                            type => type.FullName == "OpenTK.Graphics.GraphicsContext");

                        // IGraphicsContext type
                        var iGraphicsContext = wrapper.Module.Types.First(
                            type => type.FullName == "OpenTK.Graphics.IGraphicsContext");

                        // Get the constructor that takes a GraphicsContext parameter
                        var ctor = vars.ErrorHelperType.GetConstructors().FirstOrDefault(
                            c => c.Parameters.Count == 1 &&
                            c.Parameters[0].ParameterType.FullName == iGraphicsContext.FullName);

                        if (ctor == null)
                        {
                            throw new InvalidOperationException(
                                String.Format(
                                    "{0} does needs a constructor taking {1}",
                                    errorHelperType,
                                    graphicsContext));
                        }

                        // GraphicsContext.CurrentContext property getter
                        vars.Get_CurrentContext = graphicsContext.Methods.First(
                            method => method.Name == "get_CurrentContext");

                        vars.Set_ErrorChecking = graphicsContext.Methods.First(
                            method => method.Name == "set_ErrorChecking");

                        vars.ErrorHelperLocal = new VariableDefinition(vars.ErrorHelperType);

                        // using (new ErrorHelper(GraphicsContext.CurrentContext)) { ...
                        il.Body.Variables.Add(vars.ErrorHelperLocal);
                        il.Emit(OpCodes.Ldloca, vars.ErrorHelperLocal);
                        il.Emit(OpCodes.Call, vars.Get_CurrentContext);
                        il.Emit(OpCodes.Call, ctor);

                        vars.BeginTry = Instruction.Create(OpCodes.Nop);
                        il.Append(vars.BeginTry);

                        // Special case Begin to turn off error checking.
                        if (il.Body.Method.Name == "Begin")
                        {
                            il.Emit(OpCodes.Call, vars.Get_CurrentContext);
                            il.Emit(OpCodes.Ldc_I4_0);
                            il.Emit(OpCodes.Conv_I1);
                            il.Emit(OpCodes.Call, vars.Set_ErrorChecking);
                        }
                    }
                }
            }

            return vars;
        }
Пример #26
0
        /// <summary>
        /// Emits the IL that calculates a hash code from a given service type.
        /// </summary>
        /// <param name="module">The module that holds the target type.</param>
        /// <param name="body">The body of the GetServiceHashCode method.</param>
        /// <param name="il">The <see cref="ILProcessor"/> that will be used to emit the instructions.</param>
        /// <param name="getHashCodeMethod">The <see cref="Object.GetHashCode"/> method.</param>
        /// <returns>The variable that holds the hash code.</returns>
        private static VariableDefinition EmitGetServiceTypeHashCode(ModuleDefinition module, Mono.Cecil.Cil.MethodBody body, ILProcessor il, MethodReference getHashCodeMethod)
        {
            // Get the hash code for the service type
            var hashVariable = AddLocals(module, body);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, getHashCodeMethod);
            il.Emit(OpCodes.Stloc, hashVariable);

            return hashVariable;
        }
Пример #27
0
        static void EmitStringArrayEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il)
        {
            // Note: only works for string vectors (1d arrays).
            // We do not (and will probably never) support 2d or higher string arrays
            var p = parameter.ParameterType;
            var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringArrayPtr"));

            // FreeStringArrayPtr(string_array_ptr, string_array.Length)
            var variable_name = parameter.Name + "_string_array_ptr";
            var v = body.Variables.First(m => m.Name == variable_name);

            // load string_array_ptr
            il.Emit(OpCodes.Ldloc, v.Index);

            // load string_array.Length
            il.Emit(OpCodes.Ldarg, parameter.Index);
            il.Emit(OpCodes.Ldlen);
            il.Emit(OpCodes.Conv_I4);

            // call FreeStringArrayPtr
            il.Emit(OpCodes.Call, free);
        }
Пример #28
0
 /// <summary>
 /// Emits the IL that calculates a hash code from a given service name.
 /// </summary>
 /// <param name="il">The <see cref="ILProcessor"/> that will be used to emit the instructions.</param>
 /// <param name="getHashCodeMethod">The <see cref="Object.GetHashCode"/> method.</param>
 /// <param name="hashVariable">The local variable that will store the hash code.</param>
 private static void EmitGetServiceNameHashCode(ILProcessor il, MethodReference getHashCodeMethod, VariableDefinition hashVariable)
 {
     il.Emit(OpCodes.Ldloc, hashVariable);
     il.Emit(OpCodes.Ldarg_1);
     il.Emit(OpCodes.Callvirt, getHashCodeMethod);
     il.Emit(OpCodes.Xor);
     il.Emit(OpCodes.Stloc, hashVariable);
 }
Пример #29
0
        static void EmitConvenienceWrapper(MethodDefinition wrapper,
            MethodDefinition native, int difference, MethodBody body, ILProcessor il)
        {
            if (wrapper.Parameters.Count > 2)
            {
                // Todo: emit all parameters bar the last two
                throw new NotImplementedException();
            }

            if (wrapper.ReturnType.Name != "Void")
            {
                if (difference == 2)
                {
                    // Convert sized out-array/reference to return value, for example:
                    // void GenTextures(int n, int[] textures) -> int GenTexture()
                    // {
                    //  const int n = 1;
                    //  int buffers;
                    //  calli GenTextures(n, &textures);
                    //  return result;
                    // }
                    body.Variables.Add(new VariableDefinition(wrapper.ReturnType));
                    il.Emit(OpCodes.Ldc_I4, 1); // const int n = 1
                    il.Emit(OpCodes.Ldloca, body.Variables.Count - 1); // &buffers
                }
                else if (difference == 1)
                {
                    // Convert unsized out-array/reference to return value, for example:
                    // void GetBoolean(GetPName pname, out bool data) -> bool GetBoolean(GetPName pname)
                    // {
                    //   bool result;
                    //   GetBooleanv(pname, &result);
                    //   return result;
                    // }
                    body.Variables.Add(new VariableDefinition(wrapper.ReturnType));
                    EmitParameters(wrapper, native, body, il);
                    il.Emit(OpCodes.Ldloca, body.Variables.Count - 1);
                }
                else
                {
                    Console.Error.WriteLine("Unknown wrapper type for ({0})", native.Name);
                }
            }
            else
            {
                if (difference == 1)
                {
                    // Convert in-array/reference to single element, for example:
                    // void DeleteTextures(int n, ref int textures) -> void DeleteTexture(int texture)
                    // {
                    //   const int n = 1;
                    //   calli DeleteTextures(n, &textures);
                    // }
                    il.Emit(OpCodes.Ldc_I4, 1); // const int n = 1
                    il.Emit(OpCodes.Ldarga, wrapper.Parameters.Last()); // &textures
                }
                else
                {
                    Console.Error.WriteLine("Unknown wrapper type for ({0})", native.Name);
                }
            }
        }
Пример #30
0
 protected override void EmitOptOutTarget(ILProcessor il)
 {
     il.Emit(OpCodes.Ldarg_0);
 }
Пример #31
0
        static int EmitParameters(MethodDefinition method, MethodDefinition native, MethodBody body, ILProcessor il)
        {
            int i;
            for (i = 0; i < method.Parameters.Count; i++)
            {
                var parameter = method.Parameters[i];
                var p = method.Module.Import(method.Parameters[i].ParameterType);
                il.Emit(OpCodes.Ldarg, i);

                if (p.Name.Contains("Int32") && native.Parameters[i].ParameterType.Name.Contains("IntPtr"))
                {
                    // This is a convenience Int32 overload for an IntPtr (size_t) parameter.
                    // We need to convert the loaded argument to IntPtr.
                    il.Emit(OpCodes.Conv_I);
                }
                else if (p.Name == "StringBuilder")
                {
                    EmitStringBuilderParameter(method, parameter, body, il);
                }
                else if (p.Name == "String" && !p.IsArray)
                {
                    EmitStringParameter(method, parameter, body, il);
                }
                else if (p.IsByReference)
                {
                    body.Variables.Add(new VariableDefinition(new PinnedType(p)));
                    var index = body.Variables.Count - 1;
                    il.Emit(OpCodes.Stloc, index);
                    il.Emit(OpCodes.Ldloc, index);
                    il.Emit(OpCodes.Conv_I);
                }
                else if (p.IsArray)
                {
                    if (p.Name != method.Module.Import(typeof(string[])).Name)
                    {
                        // .Net treats 1d arrays differently than higher rank arrays.
                        // 1d arrays are directly supported by instructions such as ldlen and ldelema.
                        // Higher rank arrays must be accessed through System.Array methods such as get_Length.
                        // 1d array:
                        //    check array is not null
                        //    check ldlen array > 0
                        //    ldc.i4.0
                        //    ldelema
                        // 2d array:
                        //    check array is not null
                        //    check array.get_Length() > 0
                        //    ldc.i4.0
                        //    ldc.i4.0
                        //    call instance T& T[0..., 0...]::Address(int32, int32)
                        // Mono treats everything as a 1d array.
                        // Interestingly, the .Net approach works on both Mono and .Net.
                        // The Mono approach fails when using high-rank arrays on .Net.
                        // We should report a bug to http://bugzilla.xamarin.com

                        // Pin the array and pass the address
                        // of its first element.
                        var array = (ArrayType)p;
                        var element_type = p.GetElementType();
                        body.Variables.Add(new VariableDefinition(new PinnedType(new ByReferenceType(element_type))));
                        int pinned_index = body.Variables.Count - 1;

                        var empty = il.Create(OpCodes.Ldc_I4, 0);
                        var pin = il.Create(OpCodes.Ldarg, i);
                        var end = il.Create(OpCodes.Stloc, pinned_index);

                        // if (array == null) goto empty
                        il.Emit(OpCodes.Brfalse, empty);

                        // else if (array.Length != 0) goto pin
                        il.Emit(OpCodes.Ldarg, i);
                        if (array.Rank == 1)
                        {
                            il.Emit(OpCodes.Ldlen);
                            il.Emit(OpCodes.Conv_I4);
                        }
                        else
                        {
                            var get_length = method.Module.Import(
                                mscorlib.MainModule.GetType("System.Array").Methods.First(m => m.Name == "get_Length"));
                            il.Emit(OpCodes.Callvirt, get_length);
                        }
                        il.Emit(OpCodes.Brtrue, pin);

                        // empty: IntPtr ptr = IntPtr.Zero
                        il.Append(empty);
                        il.Emit(OpCodes.Conv_U);
                        il.Emit(OpCodes.Br, end);

                        // pin: &array[0]
                        il.Append(pin);
                        if (array.Rank == 1)
                        {
                            // 1d array (vector), address is taken by ldelema
                            il.Emit(OpCodes.Ldc_I4, 0);
                            il.Emit(OpCodes.Ldelema, element_type);
                        }
                        else
                        {
                            // 2d-3d array, address must be taken as follows:
                            // call instance T& T[0..., 0..., 0...]::Address(int, int, int)
                            ByReferenceType t_ref = array.ElementType.MakeByReferenceType();
                            MethodReference get_address = new MethodReference("Address", t_ref, array);
                            for (int r = 0; r < array.Rank; r++)
                            {
                                get_address.Parameters.Add(new ParameterDefinition(TypeInt32));
                            }
                            get_address.HasThis = true;

                            // emit the get_address call
                            for (int r = 0; r < array.Rank; r++)
                            {
                                il.Emit(OpCodes.Ldc_I4, 0);
                            }
                            il.Emit(OpCodes.Call, get_address);
                        }

                        // end: fixed (IntPtr ptr = &array[0])
                        il.Append(end);
                        il.Emit(OpCodes.Ldloc, pinned_index);
                        il.Emit(OpCodes.Conv_I);
                    }
                    else
                    {
                        EmitStringArrayParameter(method, parameter, body, il);
                    }
                }
            }
            return i;
        }
Пример #32
0
        static void EmitStringBuilderParameter(MethodDefinition method, ParameterDefinition parameter, MethodBody body, ILProcessor il)
        {
            var p = parameter.ParameterType;

            // void GetShaderInfoLog(..., StringBuilder foo)
            // IntPtr foo_sb_ptr;
            // try {
            //  foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1);
            //  glGetShaderInfoLog(..., foo_sb_ptr);
            //  MarshalPtrToStringBuilder(foo_sb_ptr, sb);
            // }
            // finally {
            //  Marshal.FreeHGlobal(sb_ptr);
            // }
            // Make sure we have imported StringBuilder::Capacity and Marshal::AllocHGlobal
            var sb_get_capacity = method.Module.Import(TypeStringBuilder.Methods.First(m => m.Name == "get_Capacity"));
            var alloc_hglobal = method.Module.Import(TypeMarshal.Methods.First(m => m.Name == "AllocHGlobal"));

            // IntPtr ptr;
            var variable_name = parameter.Name + " _sb_ptr";
            body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
            int index = body.Variables.Count - 1;

            // ptr = Marshal.AllocHGlobal(sb.Capacity + 1);
            il.Emit(OpCodes.Callvirt, sb_get_capacity);
            il.Emit(OpCodes.Call, alloc_hglobal);
            il.Emit(OpCodes.Stloc, index);
            il.Emit(OpCodes.Ldloc, index);

            // We'll emit the try-finally block in the epilogue implementation,
            // because we haven't yet emitted all necessary instructions here.
        }
Пример #33
0
        /// <summary>
        /// Emits the instructions that call <see cref="IInitialize.Initialize"/> on a given service instance.
        /// </summary>
        /// <param name="il"></param>
        /// <param name="module">The host module.</param>
        /// <param name="serviceInstance">The local variable that points to the current service instance.</param>
        public void Initialize(ILProcessor il, ModuleDefinition module, VariableDefinition serviceInstance)
        {
            var body = il.Body;
            var method = body.Method;
            var declaringType = method.DeclaringType;

            var targetField = GetTargetField(declaringType);
            if (targetField == null)
                return;

            var initializeType = module.ImportType<IInitialize>();

            il.Emit(OpCodes.Ldloc, serviceInstance);
            il.Emit(OpCodes.Isinst, initializeType);

            var initializeMethod = module.ImportMethod<IInitialize>("Initialize");
            var skipInitializationCall = il.Create(OpCodes.Nop);
            il.Emit(OpCodes.Brfalse, skipInitializationCall);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, targetField);
            GetServiceHash(il, module, serviceInstance);

            var containsMethod = module.ImportMethod<Dictionary<int, int>>("ContainsKey");
            il.Emit(OpCodes.Callvirt, containsMethod);
            il.Emit(OpCodes.Brtrue, skipInitializationCall);

            // if (!__initializedServices.ContainsKey(currentService.GetHashCode()) {
            il.Emit(OpCodes.Ldloc, serviceInstance);
            il.Emit(OpCodes.Isinst, initializeType);
            il.Emit(OpCodes.Ldarg_0);

            il.Emit(OpCodes.Callvirt, initializeMethod);

            // __initializedServices.Add(hashCode, 0);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, targetField);
            GetServiceHash(il, module, serviceInstance);
            il.Emit(OpCodes.Ldc_I4_1);

            var addMethod = module.ImportMethod<Dictionary<int, int>>("Add");
            il.Emit(OpCodes.Callvirt, addMethod);

            il.Append(skipInitializationCall);
        }