Пример #1
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);
        }
Пример #2
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);
        }
Пример #3
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);
        }
Пример #4
0
        /// <summary>
        /// Loads a pointer to the argument at index (starting at zero) onto the stack.
        /// </summary>
        public Emit <DelegateType> LoadArgumentAddress(ushort index)
        {
            if (ParameterTypes.Length == 0)
            {
                throw new ArgumentException("Delegate of type " + typeof(DelegateType) + " takes no parameters");
            }

            if (index >= ParameterTypes.Length)
            {
                throw new ArgumentException("index must be between 0 and " + (ParameterTypes.Length - 1) + ", inclusive");
            }

            if (index >= byte.MinValue && index <= byte.MaxValue)
            {
                byte asByte;
                unchecked
                {
                    asByte = (byte)index;
                }

                UpdateState(OpCodes.Ldarga_S, asByte, Wrap(StackTransition.Push(ParameterTypes[index].MakePointerType()), "LoadArgumentAddress"));

                return(this);
            }

            short asShort;

            unchecked
            {
                asShort = (short)index;
            }

            UpdateState(OpCodes.Ldarga, asShort, Wrap(StackTransition.Push(ParameterTypes[index].MakePointerType()), "LoadArgumentAddress"));

            return(this);
        }
Пример #5
0
        /// <summary>
        /// Expects a pointer, an initialization value, and a count on the stack.  Pops all three.
        ///
        /// Writes the initialization value to count bytes at the passed pointer.
        /// </summary>
        public Emit <DelegateType> InitializeBlock(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");
            }

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

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

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

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

            UpdateState(OpCodes.Initblk, Wrap(transition, "InitializeBlock"));

            return(this);
        }
Пример #6
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);
        }
Пример #7
0
        /// <summary>
        /// Loads a null reference onto the stack.
        /// </summary>
        public Emit <DelegateType> LoadNull()
        {
            UpdateState(OpCodes.Ldnull, Wrap(StackTransition.Push <NullType>(), "LoadNull"));

            return(this);
        }
Пример #8
0
        /// <summary>
        /// Emits an instruction that does nothing.
        /// </summary>
        public Emit <DelegateType> Nop()
        {
            UpdateState(OpCodes.Nop, Wrap(StackTransition.None(), "Nop"));

            return(this);
        }
Пример #9
0
        /// <summary>
        /// Push a constant float onto the stack.
        /// </summary>
        public Emit <DelegateType> LoadConstant(float f)
        {
            UpdateState(OpCodes.Ldc_R4, f, Wrap(StackTransition.Push <float>(), "LoadConstant"));

            return(this);
        }
Пример #10
0
        /// <summary>
        /// Push a constant int64 onto the stack.
        /// </summary>
        public Emit <DelegateType> LoadConstant(ulong l)
        {
            UpdateState(OpCodes.Ldc_I8, l, Wrap(StackTransition.Push <long>(), "LoadConstant"));

            return(this);
        }
Пример #11
0
        private LinqList<StackTransition> GetLegalTransitions(LinqList<StackTransition> ops, LinqStack<LinqList<TypeOnStack>> runningStack)
        {
            var ret = new LinqList<StackTransition>(ops.Count);

            for (var i = 0; i < ops.Count; i++)
            {
                var w = ops[i];

                if (LinqAlternative.All(w.PoppedFromStack, u => u == TypeOnStack.Get<PopAllType>()))
                {
                    ret.Add(w);
                    continue;
                }

                var onStack = runningStack.Peek(IsBaseless, w.PoppedCount);

                if (onStack == null)
                {
                    continue;
                }

                if (LinqAlternative.Any(w.PushedToStack, p => p == TypeOnStack.Get<SamePointerType>()))
                {
                    if (w.PushedToStack.Length > 1)
                    {
                        throw new Exception("SamePointerType can be only product of a transition which contains it");
                    }

                    var shouldBePointer = LinqAlternative.SelectMany(onStack, p => p.Where(x => x.IsPointer || x == TypeOnStack.Get<WildcardType>()).AsEnumerable()).Distinct().ToList();

                    if (shouldBePointer.Count == 0) continue;
                    w = new StackTransition(w.PoppedFromStack, new [] { shouldBePointer.Single() });
                }

                if (LinqAlternative.Any(w.PushedToStack, p => p == TypeOnStack.Get<SameByRefType>()))
                {
                    if (w.PushedToStack.Length > 1)
                    {
                        throw new Exception("SameByRefType can be only product of a transition which contains it");
                    }

                    var shouldBeByRef = LinqAlternative.SelectMany(onStack, p => p.Where(x => x.IsReference || x == TypeOnStack.Get<WildcardType>()).AsEnumerable()).Distinct().ToList();

                    if (shouldBeByRef.Count == 0) continue;
                    w = new StackTransition(w.PoppedFromStack, new[] { shouldBeByRef.Single() });
                }

                bool outerContinue = false;

                for (var j = 0; j < w.PoppedCount; j++)
                {
                    var shouldBe = w.PoppedFromStack[j];
                    var actuallyIs = onStack[j];

                    if (!actuallyIs.Any(a => shouldBe.IsAssignableFrom(a)))
                    {
                        outerContinue = true;
                        break;
                    }
                }

                if (outerContinue) continue;

                ret.Add(w);
            }

            return ret;
        }
Пример #12
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);
        }
Пример #13
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);
        }
Пример #14
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);
        }
Пример #15
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);
        }
Пример #16
0
        /// <summary>
        /// Push a constant double onto the stack.
        /// </summary>
        public Emit <DelegateType> LoadConstant(double d)
        {
            UpdateState(OpCodes.Ldc_R8, d, Wrap(StackTransition.Push <double>(), "LoadConstant"));

            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");
        }
Пример #18
0
        /// <summary>
        /// Push a constant string onto the stack.
        /// </summary>
        public Emit <DelegateType> LoadConstant(string str)
        {
            UpdateState(OpCodes.Ldstr, str, Wrap(StackTransition.Push <string>(), "LoadConstant"));

            return(this);
        }
Пример #19
0
        /// <summary>
        /// Removes the top value on the stack.
        /// </summary>
        public Emit <DelegateType> Pop()
        {
            UpdateState(OpCodes.Pop, Wrap(StackTransition.Pop <WildcardType>(), "Pop"));

            return(this);
        }
Пример #20
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);
        }