Ejemplo n.º 1
0
        /// <summary>
        /// Ends the execution of the current method.
        ///
        /// If the current method does not return void, pops a value from the stack and returns it to the calling method.
        ///
        /// Return should leave the stack empty.
        /// </summary>
        public Emit <DelegateType> Return()
        {
            if (ReturnType == TypeOnStack.Get(typeof(void)))
            {
                UpdateState(Wrap(new[] { new StackTransition(0) }, "Return"));

                UpdateState(OpCodes.Ret, Wrap(StackTransition.None(), "Return"));

                Returns.Add(IL.Index);
                MustMark = true;

                return(this);
            }

            UpdateState(OpCodes.Ret, Wrap(StackTransition.Pop(ReturnType), "Return"));

            Returns.Add(IL.Index);

            UpdateState(Wrap(new[] { new StackTransition(0) }, "Return"));
            MustMark = true;

            var verify = CurrentVerifiers.Return();

            if (!verify.Success)
            {
                throw new SigilVerificationException("Return", verify, IL.Instructions(AllLocals));
            }

            return(this);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Transfers control to another method.
        ///
        /// The parameters and calling convention of method must match the current one's.
        ///
        /// The stack must be empty to jump.
        ///
        /// Like the branching instructions, Jump cannot leave exception blocks.
        /// </summary>
        public Emit <DelegateType> Jump(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (method.CallingConvention != CallingConventions)
            {
                throw new ArgumentException("Jump expected a calling convention of " + CallingConventions + ", found " + method.CallingConvention);
            }

            var paras = method.GetParameters();

            if (paras.Length != ParameterTypes.Length)
            {
                throw new ArgumentException("Jump expected a method with " + ParameterTypes.Length + " parameters, found " + paras.Length);
            }

            if (!AllowsUnverifiableCIL)
            {
                FailUnverifiable("Jump");
            }

            if (CatchBlocks.Any(t => t.Value.Item2 == -1))
            {
                throw new InvalidOperationException("Jump cannot transfer control from a catch block");
            }

            if (FinallyBlocks.Any(t => t.Value.Item2 == -1))
            {
                throw new InvalidOperationException("Jump cannot transfer control from a finally block");
            }

            if (TryBlocks.Any(t => t.Value.Item2 == -1))
            {
                throw new InvalidOperationException("Jump cannot transfer control from an exception block");
            }

            UpdateState(Wrap(new[] { new StackTransition(0) }, "Jump"));

            for (var i = 0; i < paras.Length; i++)
            {
                var shouldBe   = paras[i].ParameterType;
                var actuallyIs = ParameterTypes[i];

                if (!shouldBe.IsAssignableFrom(actuallyIs))
                {
                    throw new SigilVerificationException("Jump expected the #" + i + " parameter to be assignable from " + actuallyIs + ", but found " + shouldBe, IL.Instructions(AllLocals));
                }
            }

            UpdateState(OpCodes.Jmp, method, TypeHelpers.EmptyTypes, Wrap(StackTransition.None(), "Jump"));

            return(this);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// <para>Expects a destination pointer, a source pointer, and a length on the stack.  Pops all three values.</para>
        /// <para>Copies length bytes from destination to the source.</para>
        /// </summary>
        public Emit <DelegateType> CopyBlock(bool isVolatile = false, int?unaligned = null)
        {
            if (unaligned.HasValue && (unaligned != 1 && unaligned != 2 && unaligned != 4))
            {
                throw new ArgumentException("unaligned must be null, 1, 2, or 4", "unaligned");
            }

            if (!AllowsUnverifiableCIL)
            {
                FailUnverifiable("CopyBlock");
            }

            if (isVolatile)
            {
                UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "CopyBlock"));
            }

            if (unaligned.HasValue)
            {
                UpdateState(OpCodes.Unaligned, (byte)unaligned.Value, Wrap(StackTransition.None(), "CopyBlock"));
            }

            var transition =
                new[]
            {
                new StackTransition(new[] { typeof(int), typeof(NativeIntType), typeof(NativeIntType) }, TypeHelpers.EmptyTypes),
                new StackTransition(new[] { typeof(int), typeof(byte *), typeof(NativeIntType) }, TypeHelpers.EmptyTypes),
                new StackTransition(new[] { typeof(int), typeof(byte).MakeByRefType(), typeof(NativeIntType) }, TypeHelpers.EmptyTypes),
                new StackTransition(new[] { typeof(int), typeof(NativeIntType), typeof(byte *) }, TypeHelpers.EmptyTypes),
                new StackTransition(new[] { typeof(int), typeof(byte *), typeof(byte *) }, TypeHelpers.EmptyTypes),
                new StackTransition(new[] { typeof(int), typeof(byte).MakeByRefType(), typeof(byte *) }, TypeHelpers.EmptyTypes),
                new StackTransition(new[] { typeof(int), typeof(NativeIntType), typeof(byte).MakeByRefType() }, TypeHelpers.EmptyTypes),
                new StackTransition(new[] { typeof(int), typeof(byte *), typeof(byte).MakeByRefType() }, TypeHelpers.EmptyTypes),
                new StackTransition(new[] { typeof(int), typeof(byte).MakeByRefType(), typeof(byte).MakeByRefType() }, TypeHelpers.EmptyTypes)
            };

            UpdateState(OpCodes.Cpblk, Wrap(transition, "CopyBlock"));

            return(this);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// <para>Pops a pointer from the stack, and pushes the given value type it points to onto the stack.</para>
        /// <para>For primitive and reference types, use LoadIndirect().</para>
        /// </summary>
        public Emit <DelegateType> LoadObject(Type valueType, bool isVolatile = false, int?unaligned = null)
        {
            if (valueType == null)
            {
                throw new ArgumentNullException("valueType");
            }

            if (!TypeHelpers.IsValueType(valueType))
            {
                throw new ArgumentException("valueType must be a ValueType");
            }

            if (unaligned.HasValue && (unaligned != 1 && unaligned != 2 && unaligned != 4))
            {
                throw new ArgumentException("unaligned must be null, 1, 2, or 4");
            }

            if (isVolatile)
            {
                UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "LoadObject"));
            }

            if (unaligned.HasValue)
            {
                UpdateState(OpCodes.Unaligned, (byte)unaligned.Value, Wrap(StackTransition.None(), "LoadObject"));
            }

            var transitions =
                new[]
            {
                new StackTransition(new [] { typeof(NativeIntType) }, new [] { valueType }),
                new StackTransition(new [] { valueType.MakePointerType() }, new [] { valueType }),
                new StackTransition(new [] { valueType.MakeByRefType() }, new [] { valueType })
            };

            UpdateState(OpCodes.Ldobj, valueType, Wrap(transitions, "LoadObject"));

            return(this);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Unconditionally branches to the given label.
        /// </summary>
        public Emit <DelegateType> Branch(Label label)
        {
            if (label == null)
            {
                throw new ArgumentNullException("label");
            }

            if (((IOwned)label).Owner != this)
            {
                if (((IOwned)label).Owner is DisassembledOperations <DelegateType> )
                {
                    return(Branch(label.Name));
                }

                FailOwnership(label);
            }

            UnusedLabels.Remove(label);

            UpdateOpCodeDelegate update;

            UpdateState(OpCodes.Br, label, Wrap(StackTransition.None(), "Branch"), out update);

            var valid = CurrentVerifiers.UnconditionalBranch(label);

            if (!valid.Success)
            {
                throw new SigilVerificationException("Branch", valid, IL.Instructions(AllLocals));
            }

            Branches.Add(SigilTuple.Create(OpCodes.Br, label, IL.Index));

            BranchPatches[IL.Index] = SigilTuple.Create(label, update, OpCodes.Br);

            MustMark = true;

            return(this);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// From within a catch block, rethrows the exception that caused the catch block to be entered.
        /// </summary>
        public Emit <DelegateType> ReThrow()
        {
            if (!CatchBlocks.Any(c => c.Value.Item2 == -1))
            {
                throw new InvalidOperationException("ReThrow is only legal in a catch block");
            }

            UpdateState(OpCodes.Rethrow, Wrap(StackTransition.None(), "ReThrow"));
            UpdateState(Wrap(new[] { new StackTransition(new[] { typeof(PopAllType) }, Type.EmptyTypes) }, "ReThrow"));

            Throws.Add(IL.Index);

            MustMark = true;

            var verify = CurrentVerifiers.ReThrow();

            if (!verify.Success)
            {
                throw new SigilVerificationException("ReThrow", verify, IL.Instructions(AllLocals));
            }

            return(this);
        }
        /// <summary>
        /// Pops a value of the given type and a pointer off the stack, and stores the value at the address in the pointer.
        /// </summary>
        public Emit <DelegateType> StoreIndirect(Type type, bool isVolatile = false, int?unaligned = null)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (unaligned.HasValue && (unaligned != 1 && unaligned != 2 && unaligned != 4))
            {
                throw new ArgumentException("unaligned must be null, 1, 2, or 4");
            }

            if (isVolatile)
            {
                UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "StoreIndirect"));
            }

            if (unaligned.HasValue)
            {
                UpdateState(OpCodes.Unaligned, (byte)unaligned.Value, Wrap(StackTransition.None(), "StoreIndirect"));
            }

            if (type.IsPointer)
            {
                var transition = new[] { new StackTransition(new[] { typeof(NativeIntType), typeof(NativeIntType) }, Type.EmptyTypes) };

                UpdateState(OpCodes.Stind_I, Wrap(transition, "StoreIndirect"));
                return(this);
            }

            if (!type.IsValueType)
            {
                var transition =
                    new[]
                {
                    new StackTransition(new[] { type, type.MakePointerType() }, Type.EmptyTypes),
                    new StackTransition(new[] { type, type.MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { type, typeof(NativeIntType) }, Type.EmptyTypes),
                };

                UpdateState(OpCodes.Stind_Ref, Wrap(transition, "StoreIndirect"));
                return(this);
            }

            if (type == typeof(sbyte) || type == typeof(byte))
            {
                var transition =
                    new[]
                {
                    new StackTransition(new[] { typeof(int), typeof(byte *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(byte).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(sbyte *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(sbyte).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(NativeIntType) }, Type.EmptyTypes)
                };

                UpdateState(OpCodes.Stind_I1, Wrap(transition, "StoreIndirect"));
                return(this);
            }

            if (type == typeof(short) || type == typeof(ushort))
            {
                var transition =
                    new[]
                {
                    new StackTransition(new[] { typeof(int), typeof(short *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(short).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(ushort *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(ushort).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(NativeIntType) }, Type.EmptyTypes)
                };

                UpdateState(OpCodes.Stind_I2, Wrap(transition, "StoreIndirect"));
                return(this);
            }

            if (type == typeof(int) || type == typeof(uint))
            {
                var transition =
                    new[]
                {
                    new StackTransition(new[] { typeof(int), typeof(int *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(int).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(uint *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(uint).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(int), typeof(NativeIntType) }, Type.EmptyTypes)
                };

                UpdateState(OpCodes.Stind_I4, Wrap(transition, "StoreIndirect"));
                return(this);
            }

            if (type == typeof(long) || type == typeof(ulong))
            {
                var transition =
                    new[]
                {
                    new StackTransition(new[] { typeof(long), typeof(long *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(long), typeof(long).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(long), typeof(ulong *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(long), typeof(ulong).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(long), typeof(NativeIntType) }, Type.EmptyTypes)
                };

                UpdateState(OpCodes.Stind_I8, Wrap(transition, "StoreIndirect"));
                return(this);
            }

            if (type == typeof(float))
            {
                var transition =
                    new[]
                {
                    new StackTransition(new[] { typeof(float), typeof(float *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(float), typeof(float).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(float), typeof(NativeIntType) }, Type.EmptyTypes)
                };

                UpdateState(OpCodes.Stind_R4, Wrap(transition, "StoreIndirect"));
                return(this);
            }

            if (type == typeof(double))
            {
                var transition =
                    new[]
                {
                    new StackTransition(new[] { typeof(double), typeof(double *) }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(double), typeof(double).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new[] { typeof(double), typeof(NativeIntType) }, Type.EmptyTypes)
                };

                UpdateState(OpCodes.Stind_R8, Wrap(transition, "StoreIndirect"));
                return(this);
            }

            throw new InvalidOperationException("StoreIndirect cannot be used with " + type + ", StoreObject may be more appropriate");
        }
Ejemplo n.º 8
0
        /// <summary>
        /// <para>Calls the given method virtually.  Pops its arguments in reverse order (left-most deepest in the stack), and pushes the return value if it is non-void.</para>
        /// <para>The `this` reference should appear before any arguments (deepest in the stack).</para>
        /// <para>The method invoked at runtime is determined by the type of the `this` reference.</para>
        /// <para>If the method invoked shouldn't vary (or if the method is static), use Call instead.</para>
        /// </summary>
        public Emit <DelegateType> CallVirtual(MethodInfo method, Type constrained = null, Type[] arglist = null)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (method.IsStatic)
            {
                throw new ArgumentException("Only non-static methods can be called using CallVirtual, found " + method);
            }

            if (HasFlag(method.CallingConvention, CallingConventions.VarArgs) && !HasFlag(method.CallingConvention, CallingConventions.Standard))
            {
                if (arglist == null)
                {
                    throw new InvalidOperationException("When calling a VarArgs method, arglist must be set");
                }
            }

            var expectedParams = ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => TypeOnStack.Get(s.ParameterType)).ToList();

            var declaring = method.DeclaringType;

            if (TypeHelpers.IsValueType(declaring))
            {
                declaring = declaring.MakePointerType();
            }

            // "this" parameter
            expectedParams.Insert(0, TypeOnStack.Get(declaring));

            if (arglist != null)
            {
                expectedParams.AddRange(LinqAlternative.Select(arglist, t => TypeOnStack.Get(t)));
            }

            var resultType = method.ReturnType == typeof(void) ? null : TypeOnStack.Get(method.ReturnType);

            // Shove the constrained prefix in if it's supplied
            if (constrained != null)
            {
                UpdateState(OpCodes.Constrained, constrained, Wrap(StackTransition.None(), "CallVirtual"));
            }

            IEnumerable <StackTransition> transitions;

            if (resultType != null)
            {
                transitions =
                    new[]
                {
                    new StackTransition(expectedParams.Reverse().AsEnumerable(), new [] { resultType })
                };
            }
            else
            {
                transitions =
                    new[]
                {
                    new StackTransition(expectedParams.Reverse().AsEnumerable(), new TypeOnStack[0])
                };
            }

            UpdateState(OpCodes.Callvirt, method, ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => s.ParameterType).AsEnumerable(), Wrap(transitions, "CallVirtual"), arglist: arglist);

            return(this);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Pops a pointer from the stack and pushes the value (of the given type) at that address onto the stack.
        /// </summary>
        public Emit <DelegateType> LoadIndirect(Type type, bool isVolatile = false, int?unaligned = null)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (unaligned.HasValue && (unaligned != 1 && unaligned != 2 && unaligned != 4))
            {
                throw new ArgumentException("unaligned must be null, 1, 2, or 4");
            }

            OpCode?instr = null;
            IEnumerable <StackTransition> transitions = null;

            if (type.IsPointer)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { type }),
                    new StackTransition(new [] { type.MakePointerType() }, new[] { type }),
                    new StackTransition(new [] { type.MakeByRefType() }, new[] { type })
                };


                instr = OpCodes.Ldind_I;
            }

            if (!type.IsValueType && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { type }),
                    new StackTransition(new [] { type.MakePointerType() }, new[] { type }),
                    new StackTransition(new [] { type.MakeByRefType() }, new[] { type })
                };

                instr = OpCodes.Ldind_Ref;
            }

            if (type == typeof(sbyte) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(int) }),
                    new StackTransition(new [] { typeof(sbyte *) }, new[] { typeof(int) }),
                    new StackTransition(new [] { typeof(sbyte).MakeByRefType() }, new[] { typeof(int) })
                };

                instr = OpCodes.Ldind_I1;
            }

            if (type == typeof(bool) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(int) }),
                    new StackTransition(new [] { typeof(bool *) }, new[] { typeof(int) }),
                    new StackTransition(new [] { typeof(bool).MakeByRefType() }, new[] { typeof(int) })
                };

                instr = OpCodes.Ldind_I1;
            }

            if (type == typeof(byte) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(int) }),
                    new StackTransition(new [] { typeof(byte *) }, new[] { typeof(int) }),
                    new StackTransition(new [] { typeof(byte).MakeByRefType() }, new[] { typeof(int) })
                };

                instr = OpCodes.Ldind_U1;
            }

            if (type == typeof(short) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(int) }),
                    new StackTransition(new [] { typeof(short *) }, new[] { typeof(int) }),
                    new StackTransition(new [] { typeof(short).MakeByRefType() }, new[] { typeof(int) })
                };

                instr = OpCodes.Ldind_I2;
            }

            if (type == typeof(ushort) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(int) }),
                    new StackTransition(new [] { typeof(ushort *) }, new[] { typeof(int) }),
                    new StackTransition(new [] { typeof(ushort).MakeByRefType() }, new[] { typeof(int) })
                };

                instr = OpCodes.Ldind_U2;
            }

            if (type == typeof(char) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(int) }),
                    new StackTransition(new [] { typeof(char *) }, new[] { typeof(int) }),
                    new StackTransition(new [] { typeof(char).MakeByRefType() }, new[] { typeof(int) })
                };

                instr = OpCodes.Ldind_U2;
            }

            if (type == typeof(int) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(int) }),
                    new StackTransition(new [] { typeof(int *) }, new[] { typeof(int) }),
                    new StackTransition(new [] { typeof(int).MakeByRefType() }, new[] { typeof(int) })
                };

                instr = OpCodes.Ldind_I4;
            }

            if (type == typeof(uint) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(int) }),
                    new StackTransition(new [] { typeof(uint *) }, new[] { typeof(int) }),
                    new StackTransition(new [] { typeof(uint).MakeByRefType() }, new[] { typeof(int) })
                };

                instr = OpCodes.Ldind_U4;
            }

            if ((type == typeof(long) || type == typeof(ulong)) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(long) }),
                    new StackTransition(new [] { typeof(long *) }, new[] { typeof(long) }),
                    new StackTransition(new [] { typeof(long).MakeByRefType() }, new[] { typeof(long) }),
                    new StackTransition(new [] { typeof(ulong *) }, new[] { typeof(long) }),
                    new StackTransition(new [] { typeof(ulong).MakeByRefType() }, new[] { typeof(long) })
                };

                instr = OpCodes.Ldind_I8;
            }

            if (type == typeof(float) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(float) }),
                    new StackTransition(new [] { typeof(float *) }, new[] { typeof(float) }),
                    new StackTransition(new [] { typeof(float).MakeByRefType() }, new[] { typeof(float) })
                };

                instr = OpCodes.Ldind_R4;
            }

            if (type == typeof(double) && !instr.HasValue)
            {
                transitions =
                    new[]
                {
                    new StackTransition(new [] { typeof(NativeIntType) }, new [] { typeof(double) }),
                    new StackTransition(new [] { typeof(double *) }, new[] { typeof(double) }),
                    new StackTransition(new [] { typeof(double).MakeByRefType() }, new[] { typeof(double) })
                };

                instr = OpCodes.Ldind_R8;
            }

            if (!instr.HasValue)
            {
                throw new InvalidOperationException("LoadIndirect cannot be used with " + type + ", LoadObject may be more appropriate");
            }

            if (isVolatile)
            {
                UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "LoadIndirect"));
            }

            if (unaligned.HasValue)
            {
                UpdateState(OpCodes.Unaligned, (byte)unaligned.Value, Wrap(StackTransition.None(), "LoadIndirect"));
            }

            UpdateState(instr.Value, Wrap(transitions, "LoadIndirect"));

            return(this);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Emits a break instruction for use with a debugger.
        /// </summary>
        public Emit <DelegateType> Break()
        {
            UpdateState(OpCodes.Break, Wrap(StackTransition.None(), "Break"));

            return(this);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// <para>Loads a field onto the stack.</para>
        /// <para>Instance fields expect a reference on the stack, which is popped.</para>
        /// </summary>
        public Emit <DelegateType> LoadField(FieldInfo field, bool?isVolatile = null, int?unaligned = null)
        {
            if (field == null)
            {
                throw new ArgumentNullException("field");
            }

            if (unaligned.HasValue && (unaligned != 1 && unaligned != 2 && unaligned != 4))
            {
                throw new ArgumentException("unaligned must be null, 1, 2, or 4");
            }

            if (unaligned.HasValue && field.IsStatic)
            {
                throw new ArgumentException("unaligned cannot be used with static fields");
            }

            var useVolatile = isVolatile ?? ExtensionMethods.IsVolatile(field);

            if (!field.IsStatic)
            {
                if (useVolatile)
                {
                    UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "LoadField"));
                }

                if (unaligned.HasValue)
                {
                    UpdateState(OpCodes.Unaligned, (byte)unaligned.Value, Wrap(StackTransition.None(), "LoadField"));
                }

                StackTransition[] transitions;
                if (TypeHelpers.IsValueType(field.DeclaringType))
                {
                    transitions =
                        new[]
                    {
                        // This transition isn't really to spec... but it seems to work consistently in .NET soooo.... yeah
                        new StackTransition(new [] { field.DeclaringType }, new [] { field.FieldType }),
                        new StackTransition(new [] { field.DeclaringType.MakePointerType() }, new [] { field.FieldType })
                    };
                }
                else
                {
                    transitions =
                        new[]
                    {
                        new StackTransition(new [] { field.DeclaringType }, new [] { field.FieldType })
                    };
                }

                UpdateState(OpCodes.Ldfld, field, Wrap(transitions, "LoadField"));
            }
            else
            {
                if (useVolatile)
                {
                    UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "LoadField"));
                }

                UpdateState(OpCodes.Ldsfld, field, Wrap(StackTransition.Push(field.FieldType), "LoadField"));
            }

            return(this);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Calls the given method virtually.  Pops its arguments in reverse order (left-most deepest in the stack), and pushes the return value if it is non-void.
        ///
        /// The `this` reference should appear before any arguments (deepest in the stack).
        ///
        /// The method invoked at runtime is determined by the type of the `this` reference.
        ///
        /// If the method invoked shouldn't vary (or if the method is static), use Call instead.
        /// </summary>
        public Emit <DelegateType> CallVirtual(Emit <DelegateType> emit, Type constrained = null, Type[] arglist = null)
        {
            if (emit == null)
            {
                throw new ArgumentNullException("emit");
            }

            var method = emit.MtdBuilder ?? (MethodInfo)emit.DynMethod;

            if (method == null)
            {
                throw new ArgumentException("Has to be a method");
            }

            if (method.IsStatic)
            {
                throw new ArgumentException("Only non-static methods can be called using CallVirtual, found " + method);
            }

            if (HasFlag(method.CallingConvention, CallingConventions.VarArgs) && !HasFlag(method.CallingConvention, CallingConventions.Standard))
            {
                if (arglist == null)
                {
                    throw new InvalidOperationException("When calling a VarArgs method, arglist must be set");
                }
            }


            var expectedParams = ((LinqArray <Type>)emit.ParameterTypes).Select(s => TypeOnStack.Get(s)).ToList();

            if (arglist != null)
            {
                expectedParams.AddRange(((LinqArray <Type>)arglist).Select(t => TypeOnStack.Get(t)));
            }

            var resultType = method.ReturnType == typeof(void) ? null : TypeOnStack.Get(method.ReturnType);

            // Shove the constrained prefix in if it's supplied
            if (constrained != null)
            {
                UpdateState(OpCodes.Constrained, constrained, Wrap(StackTransition.None(), "CallVirtual"));
            }

            IEnumerable <StackTransition> transitions;

            if (resultType != null)
            {
                transitions =
                    new[]
                {
                    new StackTransition(expectedParams.Reverse().AsEnumerable(), new [] { resultType })
                };
            }
            else
            {
                transitions =
                    new[]
                {
                    new StackTransition(expectedParams.Reverse().AsEnumerable(), new TypeOnStack[0])
                };
            }

            UpdateState(OpCodes.Callvirt, method, emit.ParameterTypes, Wrap(transitions, "CallVirtual"), arglist: arglist);

            return(this);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Emits an instruction that does nothing.
        /// </summary>
        public Emit <DelegateType> Nop()
        {
            UpdateState(OpCodes.Nop, Wrap(StackTransition.None(), "Nop"));

            return(this);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Pops a value from the stack and stores it in the given field.
        ///
        /// If the field is an instance member, both a value and a reference to the instance are popped from the stack.
        /// </summary>
        public Emit <DelegateType> StoreField(FieldInfo field, bool isVolatile = false, int?unaligned = null)
        {
            if (field == null)
            {
                throw new ArgumentNullException("field");
            }

            if (unaligned.HasValue && (unaligned != 1 && unaligned != 2 && unaligned != 4))
            {
                throw new ArgumentException("unaligned must be null, 1, 2, or 4");
            }

            if (unaligned.HasValue && field.IsStatic)
            {
                throw new ArgumentException("unaligned cannot be used with static fields");
            }

            if (!field.IsStatic)
            {
                if (isVolatile)
                {
                    UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "StoreField"));
                }

                if (unaligned.HasValue)
                {
                    UpdateState(OpCodes.Unaligned, (byte)unaligned.Value, Wrap(StackTransition.None(), "StoreField"));
                }

                var onType = field.DeclaringType;
                if (onType.IsValueType)
                {
                    onType = onType.MakePointerType();
                }

                var transitions =
                    new[]
                {
                    new StackTransition(new [] { field.FieldType, onType }, Type.EmptyTypes)
                };

                UpdateState(OpCodes.Stfld, field, Wrap(transitions, "StoreField"));
            }
            else
            {
                if (isVolatile)
                {
                    UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "StoreField"));
                }

                var transitions =
                    new[]
                {
                    new StackTransition(new [] { field.FieldType }, Type.EmptyTypes)
                };

                UpdateState(OpCodes.Stsfld, field, Wrap(transitions, "StoreField"));
            }

            return(this);
        }