/// <summary> /// Pops an array reference (containing elements of the given type), and index and a value of the given type, and stores the value in the array at that index /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="type">The type of elements in the array</param> public static XsILGenerator StoreElement(this XsILGenerator generator, Type type) { if (!type.IsValueType) { return(generator.FluentEmit(OpCodes.Stelem_Ref)); } else if (type == typeof(sbyte) || type == typeof(byte) || type == typeof(bool)) { return(generator.FluentEmit(OpCodes.Stelem_I1)); } else if (type == typeof(short) || type == typeof(ushort)) { return(generator.FluentEmit(OpCodes.Stelem_I2)); } else if (type == typeof(int) || type == typeof(uint)) { return(generator.FluentEmit(OpCodes.Stelem_I4)); } else if (type == typeof(long) || type == typeof(ulong)) { return(generator.FluentEmit(OpCodes.Ldelem_I8)); } else if (type == typeof(float)) { return(generator.FluentEmit(OpCodes.Stelem_R4)); } else if (type == typeof(double)) { return(generator.FluentEmit(OpCodes.Stelem_R8)); } else { return(generator.FluentEmit(OpCodes.Stelem, type)); } }
/// <summary> /// Pops the address of the storage location of a value type and initializes each field of the type at that location /// </summary> /// <param name="type">The type to initialize</param> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> public static XsILGenerator InitializeValueType(this XsILGenerator generator, Type type) { if (!type.IsValueType) { throw new InvalidOperationException("Cannot initialize a non-value type"); } return(generator.FluentEmit(OpCodes.Initobj, type)); }
/// <summary> /// Pops a reference from the evaluation stack, and pushes a reference of the given type if the object is an instance of that type, otherwise an <see cref="InvalidCastException" /> is thrown /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="type">The type to attempt to cast to</param> public static XsILGenerator CastClass(this XsILGenerator generator, Type type) { if (type.IsValueType) { throw new InvalidOperationException("Cannot cast to a value type"); } return(generator.FluentEmit(OpCodes.Castclass, type)); }
/// <summary> /// Pops two addresses from the evaluation stack and copies the value type object (of the given type) in the first into the second /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="type">The type of the value type object</param> public static XsILGenerator CopyObject(this XsILGenerator generator, Type type) { if (!type.IsValueType) { throw new InvalidOperationException("Copying a non-value-type results in unspecified runtime behaviour"); } return(generator.FluentEmit(OpCodes.Cpobj, type)); }
/// <summary> /// Duplicates the value on the top of the evaluation stack <paramref name="n"/> times /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="n">The number of times to duplicate the value</param> public static XsILGenerator Duplicate(this XsILGenerator generator, uint n) { for (int i = 0; i < n; i++) { generator.FluentEmit(OpCodes.Dup); } return(generator); }
/// <summary> /// Pops a value type object from the evaluation stack, and pushes a reference to a new boxed instance of the object onto the evaluation stack /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="type">The type of the value type object</param> public static XsILGenerator Box(this XsILGenerator generator, Type type) { if (!type.IsValueType) { throw new InvalidOperationException("Can only box value types"); } return(generator.FluentEmit(OpCodes.Box, type)); }
/// <summary> /// Stores the given value in the given local /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="local">The local to store value in</param> /// <param name="value">The value to store in the local</param> /// <exception cref="ArgumentException">Thrown if the local is not of type <see cref="SByte" /></exception> public static XsILGenerator OverwriteLocalWith(this XsILGenerator generator, LocalBuilder local, SByte value) { if (local.LocalType != typeof(SByte)) { throw new ArgumentException("Cannot store a SByte value in a local of type " + local.LocalType.Name); } return(generator.LoadConstant(value) .StoreInLocal(local)); }
/// <summary> /// Pops an address from the evaluation stack and pushes the value type object (of the given type) at that location onto the evaluation stack, with volatile semantics /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="type">The type of the value type object</param> public static XsILGenerator LoadValueTypeOntoStackVolatile(this XsILGenerator generator, Type type) { if (!type.IsValueType) { throw new InvalidOperationException("This operation is not valid on reference types"); } return(generator.FluentEmit(OpCodes.Volatile) .LoadValueTypeOntoStack(type)); }
/// <summary> /// Pops a reference off the evaluation stack and calls the setter of the given property on the object with the given value /// </summary> /// <param name="generator"></param> /// <param name="property">The property to set</param> /// <param name="value">The value to set the property to</param> public static XsILGenerator SetProperty(this XsILGenerator generator, PropertyInfo property, UInt64 value) { if (property.PropertyType != typeof(UInt64)) { throw new InvalidOperationException("Property is not of type UInt64"); } return(generator.LoadConstant(value) .SetProperty(property)); }
/// <summary> /// Pops an address and a value type object (of the given type) from the evaluation stack, and copies the object into the address, with volatile semantics /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="type">The type of the value type object</param> public static XsILGenerator StoreValueTypeFromStackVolatile(this XsILGenerator generator, Type type) { if (!type.IsValueType) { throw new InvalidOperationException("This operation is not valid on a reference type"); } return(generator.FluentEmit(OpCodes.Volatile) .FluentEmit(OpCodes.Stobj, type)); }
internal static LocalBuilder GetLocal(this XsILGenerator generator, string localName) { LocalBuilder local; if (!GeneratorExtraData.GetOrCreateValue(generator).Locals.TryGetValue(localName, out local)) { throw new InvalidOperationException("No local with the name `" + localName + "` declared"); } return(local); }
/// <summary> /// Pops a reference and a value off the evaluation stack and calls the setter of the given property on the object with the value /// </summary> /// <param name="generator"></param> /// <param name="property">The property to set</param> public static XsILGenerator SetProperty(this XsILGenerator generator, PropertyInfo property) { if (!property.CanWrite) { throw new InvalidOperationException("Cannot write to this property"); } var setMethod = property.GetSetMethod(); return(generator.Call(setMethod)); }
/// <summary> /// Pops a reference off the evaluation stack and calls the getter of the given property on the object /// </summary> /// <param name="generator"></param> /// <param name="property">The property to get the value of</param> public static XsILGenerator GetProperty(this XsILGenerator generator, PropertyInfo property) { if (!property.CanRead) { throw new InvalidOperationException("Cannot read from this property"); } var getMethod = property.GetGetMethod(); return(generator.Call(getMethod)); }
/// <summary> /// Pushes the given value onto the evaluation stack /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="value">The value to push onto the evaluation stack</param> public static XsILGenerator LoadConstant(this XsILGenerator generator, ulong value) { if (value <= uint.MaxValue) { return(generator.LoadConstant((uint)value) .ConvertToUInt64()); } else { return(generator.FluentEmit(OpCodes.Ldc_I8, value)); } }
/// <summary> /// Pops an array reference (containing elements of the given type) and an index off the evaluation stack and pushes the element at that array index /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="type">The type of elements in the array</param> public static XsILGenerator LoadElement(this XsILGenerator generator, Type type) { if (!type.IsValueType) { return(generator.FluentEmit(OpCodes.Ldelem_Ref)); } else if (type == typeof(sbyte) || type == typeof(bool)) { return(generator.FluentEmit(OpCodes.Ldelem_I1)); } else if (type == typeof(byte)) { return(generator.FluentEmit(OpCodes.Ldelem_U1)); } else if (type == typeof(short)) { return(generator.FluentEmit(OpCodes.Ldelem_I2)); } else if (type == typeof(ushort)) { return(generator.FluentEmit(OpCodes.Ldelem_U2)); } else if (type == typeof(int)) { return(generator.FluentEmit(OpCodes.Ldelem_I4)); } else if (type == typeof(uint)) { return(generator.FluentEmit(OpCodes.Ldelem_U4)); } else if (type == typeof(long)) { return(generator.FluentEmit(OpCodes.Ldelem_I8)); } else if (type == typeof(ulong)) { // Not a mistake! ldelem.U8 is an alias for ldelem.I8 return(generator.FluentEmit(OpCodes.Ldelem_I8)); } else if (type == typeof(float)) { return(generator.FluentEmit(OpCodes.Ldelem_R4)); } else if (type == typeof(double)) { return(generator.FluentEmit(OpCodes.Ldelem_R8)); } else { return(generator.FluentEmit(OpCodes.Ldelem, type)); } }
/// <summary> /// Throws an exception of the given type with the given message /// </summary> /// <typeparam name="T"></typeparam> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="message">The message to give the exception</param> /// <exception cref="InvalidOperationException">Exception type <typeparamref name="T"/> does not have a public constructor taking only a string</exception> public static XsILGenerator Throw <T>(this XsILGenerator generator, string message) where T : Exception { var constructor = typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, StringTypeArray, null); if (constructor == null) { throw new InvalidOperationException("Exception type " + typeof(T).Name + " does not have a public constructor taking only a string"); } return(generator.LoadString(message) .NewObject(constructor) .Throw()); }
private static XsILGenerator CreateLocal(this XsILGenerator generator, string localName, Type localType, bool pinned) { var data = GeneratorExtraData.GetOrCreateValue(generator); if (data.Locals.ContainsKey(localName)) { throw new InvalidOperationException("Local with the name `" + localName + "` already declared"); } var local = generator.DeclareLocal(localType, pinned); data.Locals.Add(localName, local); return(generator); }
/// <summary> /// Mark the fluently-specified label /// </summary> /// <param name="generator"></param> /// <param name="labelName">The name of the fluently-specified label</param> public static XsILGenerator MarkLabel(this XsILGenerator generator, string labelName) { var data = GeneratorExtraData.GetOrCreateValue(generator); Label label; if (!data.Labels.TryGetValue(labelName, out label)) { throw new InvalidOperationException("No label with the name `" + labelName + "` declared"); } generator.MarkLabel(label); data.Labels.Remove(labelName); return(generator); }
/// <summary> /// Pops an address from the evaluation stack and pushes the value type object (of the given type) at that location onto the evaluation stack /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="type">The type of the value type object</param> public static XsILGenerator LoadValueTypeOntoStack(this XsILGenerator generator, Type type) { if (!type.IsValueType) { throw new InvalidOperationException("This operation is not valid on reference types"); } if (type == typeof(sbyte)) { return(generator.FluentEmit(OpCodes.Ldind_I1)); } else if (type == typeof(byte)) { return(generator.FluentEmit(OpCodes.Ldind_U1)); } else if (type == typeof(short)) { return(generator.FluentEmit(OpCodes.Ldind_I2)); } else if (type == typeof(ushort)) { return(generator.FluentEmit(OpCodes.Ldind_U2)); } else if (type == typeof(int)) { return(generator.FluentEmit(OpCodes.Ldind_I4)); } else if (type == typeof(uint)) { return(generator.FluentEmit(OpCodes.Ldind_U4)); } else if (type == typeof(long) || type == typeof(ulong)) { return(generator.FluentEmit(OpCodes.Ldind_I8)); } else if (type == typeof(float)) { return(generator.FluentEmit(OpCodes.Ldind_R4)); } else if (type == typeof(double)) { return(generator.FluentEmit(OpCodes.Ldind_R8)); } else { return(generator.FluentEmit(OpCodes.Ldobj, type)); } }
public static XsILGenerator LoadConstantNumber(this XsILGenerator generator, string type, decimal number) { var itl = type.ToLower(); if (itl == "f64") { return(generator.LoadConstant((double)number)); } if (itl == "f32") { return(generator.LoadConstant((float)number)); } if (itl == "i64") { return(generator.LoadConstant((long)number)); } if (itl == "i32") { return(generator.LoadConstant((int)number)); } if (itl == "i16") { return(generator.LoadConstant((short)number)); } if (itl == "i8") { return(generator.LoadConstant((sbyte)number)); } if (itl == "u64") { return(generator.LoadConstant((ulong)number)); } if (itl == "u32") { return(generator.LoadConstant((uint)number)); } if (itl == "u16") { return(generator.LoadConstant((ushort)number)); } if (itl == "u8") { return(generator.LoadConstant((byte)number)); } return(generator.LoadConstant((double)number)); }
internal static Label GetOrCreateLabel(this XsILGenerator generator, string labelName) { var data = GeneratorExtraData.GetOrCreateValue(generator); Label label; if (data.Labels.TryGetValue(labelName, out label)) { return(label); } else { label = generator.DefineLabel(); data.Labels.Add(labelName, label); return(label); } }
/// <summary> /// Pops a value from the evaluation stack and stores it in the given local /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="local">The local to store the evaluation stack value in</param> public static XsILGenerator StoreInLocal(this XsILGenerator generator, LocalBuilder local) { switch (local.LocalIndex) { case 0: return(generator.FluentEmit(OpCodes.Stloc_0)); case 1: return(generator.FluentEmit(OpCodes.Stloc_1)); case 2: return(generator.FluentEmit(OpCodes.Stloc_2)); default: return((local.LocalIndex <= 255) ? generator.FluentEmit(OpCodes.Stloc_S, local) : generator.FluentEmit(OpCodes.Stloc, local)); } }
private void TryStoreReference(object varRef, XsILGenerator il = null) { if (il == null) { il = ctx.GetILGenerator(); } if (varRef is XsField field) { il.StoreInField(field); ctx.LastStoredReference = varRef; } else if (varRef is XsVariable local) { il.StoreInLocal(local); } else if (varRef is XsParameter param) { il.StoreInArgument(param); } }
/// <summary> /// Pushes the given value onto the evaluation stack /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="value">The value to push onto the evaluation stack</param> public static XsILGenerator LoadConstant(this XsILGenerator generator, Int32 value) { switch (value) { case -1: return(generator.FluentEmit(OpCodes.Ldc_I4_M1)); case 0: return(generator.FluentEmit(OpCodes.Ldc_I4_0)); case 1: return(generator.FluentEmit(OpCodes.Ldc_I4_1)); case 2: return(generator.FluentEmit(OpCodes.Ldc_I4_2)); case 3: return(generator.FluentEmit(OpCodes.Ldc_I4_3)); case 4: return(generator.FluentEmit(OpCodes.Ldc_I4_4)); case 5: return(generator.FluentEmit(OpCodes.Ldc_I4_5)); case 6: return(generator.FluentEmit(OpCodes.Ldc_I4_6)); case 7: return(generator.FluentEmit(OpCodes.Ldc_I4_7)); case 8: return(generator.FluentEmit(OpCodes.Ldc_I4_8)); default: return(value <= 127 && value >= -128 ? generator.FluentEmit(OpCodes.Ldc_I4_S, value) : generator.FluentEmit(OpCodes.Ldc_I4, value)); } }
/// <summary> /// Loads the specified argument onto the evaluation stack /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="argNum">The index of the argument to load</param> public static XsILGenerator LoadArgument(this XsILGenerator generator, ushort argNum) { switch (argNum) { case 0: return(generator.FluentEmit(OpCodes.Ldarg_0)); case 1: return(generator.FluentEmit(OpCodes.Ldarg_1)); case 2: return(generator.FluentEmit(OpCodes.Ldarg_2)); case 3: return(generator.FluentEmit(OpCodes.Ldarg_3)); default: return(argNum <= 255 ? generator.FluentEmit(OpCodes.Ldarg_S, (byte)argNum) : generator.FluentEmit(OpCodes.Ldarg, argNum)); } }
private void TryLoadReference(object value, XsILGenerator il = null) { if (il == null) { il = ctx.GetILGenerator(); } if (value is XsVariable variable) { il.LoadLocal(variable); } else if (value is XsField field) { if (!field.FIeldInfo.IsStatic) { il.LoadThis(); } il.LoadField(field); ctx.LastLoadedReference = value; } else if (value is XsParameter param) { il.LoadArgument(param); } }
/// <summary> /// Stores the given value in the given local /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="localName">The name of the fluently-specified local</param> /// <param name="value">The value to store in the local</param> /// <exception cref="ArgumentException">Thrown if the local is not of type <see cref="Char" /></exception> public static XsILGenerator OverwriteLocalWith(this XsILGenerator generator, string localName, Char value) => generator.OverwriteLocalWith(generator.GetLocal(localName), value);
/// <summary> /// Branch to the given label, clearing the evaluation stack; can be used to leave a protected region /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="label">The label to branch to</param> public static XsILGenerator Leave(this XsILGenerator generator, Label label) => generator.FluentEmit(OpCodes.Leave, label);
/// <summary> /// Pops an integer value from the evaluation stack and branches to the corresponding zero-indexed label in the provided list, continuing to the next instruction if the value is outside the valid range /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="labelNames">The names of the fluently-specified labels to form a jump table from</param> public static XsILGenerator Switch(this XsILGenerator generator, params string[] labelNames) => generator.Switch(labelNames.Select(generator.GetOrCreateLabel).ToArray());
/// <summary> /// Pops an integer value from the evaluation stack and branches to the corresponding zero-indexed label in the provided list, continuing to the next instruction if the value is outside the valid range /// </summary> /// <param name="generator">The <see cref="T:System.Reflection.Emit.XsILGenerator" /> to emit instructions from</param> /// <param name="labels">The labels to form a jump table from</param> public static XsILGenerator Switch(this XsILGenerator generator, params Label[] labels) => generator.FluentEmit(OpCodes.Switch, labels);