/// <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); }
/// <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); }
/// <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> /// 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); }
/// <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); }
/// <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); }
/// <summary> /// Loads a null reference onto the stack. /// </summary> public Emit <DelegateType> LoadNull() { UpdateState(OpCodes.Ldnull, Wrap(StackTransition.Push <NullType>(), "LoadNull")); return(this); }
/// <summary> /// Emits an instruction that does nothing. /// </summary> public Emit <DelegateType> Nop() { UpdateState(OpCodes.Nop, Wrap(StackTransition.None(), "Nop")); return(this); }
/// <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); }
/// <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); }
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; }
/// <summary> /// Emits a break instruction for use with a debugger. /// </summary> public Emit <DelegateType> Break() { UpdateState(OpCodes.Break, Wrap(StackTransition.None(), "Break")); return(this); }
/// <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); }
/// <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); }
/// <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); }
/// <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"); }
/// <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); }
/// <summary> /// Removes the top value on the stack. /// </summary> public Emit <DelegateType> Pop() { UpdateState(OpCodes.Pop, Wrap(StackTransition.Pop <WildcardType>(), "Pop")); return(this); }
/// <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); }