public static CaseDelegate CompileCases(ErrorSink errors, Case[] cases, string name) { var ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.RunAndCollect); var mb = ab.DefineDynamicModule("MainModule"); var cb = mb.DefineType("Cases"); var methods = new List <MethodInfo>(); for (int i = 0; i < cases.Length; i++) { var method = cb.DefineMethod($"Case{i}", MethodAttributes.Private | MethodAttributes.Static, typeof(void), new[] { typeof(IMachine) }); using (var il = new GroboIL(method)) { var visitor = new CompilerVisitor(il, errors); visitor.Visit(cases[i]); il.Ret(); Console.WriteLine(il.GetILCode()); } methods.Add(method); } CreateRunAllMethod(cb, methods); var type = cb.CreateType(); return((CaseDelegate)type.GetMethod("RunAll").CreateDelegate(typeof(CaseDelegate))); }
public void TestDifferentPathsGeneric() { var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); var module = assembly.DefineDynamicModule(Guid.NewGuid().ToString()); var type = module.DefineType("Zzz", TypeAttributes.Class | TypeAttributes.Public); var method = type.DefineMethod("Qzz", MethodAttributes.Public | MethodAttributes.Static); var genericParameters = method.DefineGenericParameters("TZzz"); var parameter = genericParameters[0]; method.SetParameters(typeof(bool), typeof(C1 <>).MakeGenericType(parameter), typeof(C2 <>).MakeGenericType(parameter)); method.SetReturnType(typeof(void)); using (var il = new GroboIL(method)) { il.Ldarg(0); var label1 = il.DefineLabel("L1"); il.Brfalse(label1); il.Ldarg(1); var label2 = il.DefineLabel("L2"); il.Br(label2); il.MarkLabel(label1); il.Ldarg(2); il.MarkLabel(label2); il.Dup(); il.Call(HackHelpers.GetMethodDefinition <I1 <int> >(x => F1(x)).GetGenericMethodDefinition().MakeGenericMethod(parameter)); il.Call(HackHelpers.GetMethodDefinition <I2 <int> >(x => F2(x)).GetGenericMethodDefinition().MakeGenericMethod(parameter)); il.Ret(); Console.Write(il.GetILCode()); } }
public void GetReadILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local buffer, GroboIL.Local result, GroboIL.Local typeSize, GroboIL.Local offset, bool listValue) { var r = il.DeclareLocal(typeof(byte)); il.Ldloc(buffer); il.Ldloc(offset); il.Ldelem(typeof(byte)); if (listValue) { il.Stloc(result); } else { il.Stloc(r); } BinaryStruct.WriteOffsetAppend(il, offset, 1); if (!listValue) { il.Ldloc(result); il.Ldloc(r); il.Call(prop.Setter, isVirtual: true); } }
protected void SaveOrCheck(GroboIL il, EvaluationStack stack, GroboIL.Label label) { ESType[] labelStack; if (!il.labelStacks.TryGetValue(label, out labelStack)) { il.labelStacks.Add(label, stack.Reverse().ToArray()); Propogate(il, il.ilCode.GetLabelLineNumber(label), stack); } else { ESType[] merged; var comparisonResult = CompareStacks(stack.Reverse().ToArray(), labelStack, out merged); switch (comparisonResult) { case StacksComparisonResult.Equal: return; case StacksComparisonResult.Inconsistent: ThrowError(il, string.Format("Inconsistent stack for the label '{0}'{1}Stack #1: {2}{1}Stack #2: {3}", label.Name, Environment.NewLine, stack, new EvaluationStack(labelStack))); break; case StacksComparisonResult.Equivalent: il.labelStacks[label] = merged; Propogate(il, il.ilCode.GetLabelLineNumber(label), new EvaluationStack(merged)); break; } } }
protected static void CheckNotEmpty(GroboIL il, EvaluationStack stack, Func <string> message) { if (stack.Count == 0) { ThrowError(il, message()); } }
protected static void CheckCanBeAssigned(GroboIL il, Type to, Type from) { if (!CanBeAssigned(to, from)) { ThrowError(il, string.Format("Unable to set a value of type '{0}' to an instance of type '{1}'", Formatter.Format(from), Formatter.Format(to))); } }
private SizeCounterDelegate BuildCounter(Type type, bool ignoreCustomSerialization) { IntPtr counter = GetCounter(type, ignoreCustomSerialization); var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(object), typeof(bool), typeof(WriterContext) }, GetType(), true); using (var il = new GroboIL(dynamicMethod)) { il.Ldarg(0); // stack: [obj] if (type.IsValueType) { il.Unbox_Any(type); // stack: [(type)obj] } else { il.Castclass(type); // stack: [(type)obj] } il.Ldarg(1); // stack: [(type)obj, writeEmpty] il.Ldarg(2); // stack: [(type)obj, writeEmpty, context] il.Ldc_IntPtr(counter); // stack: [(type)obj, writeEmpty, context, counter] il.Calli(CallingConventions.Standard, typeof(int), new[] { type, typeof(bool), typeof(WriterContext) }); // counter((type)obj, writeEmpty, context); stack: [] il.Ret(); } return((SizeCounterDelegate)dynamicMethod.CreateDelegate(typeof(SizeCounterDelegate))); }
protected static void CheckNotStruct(GroboIL il, ESType type) { if (ToCLIType(type) == CLIType.Struct) { ThrowError(il, string.Format("Struct of type '{0}' is not valid at this point", type)); } }
private WriterDelegate BuildWriter(Type type, bool ignoreCustomSerialization) { IntPtr writer = GetWriter(type, ignoreCustomSerialization); var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { typeof(object), typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) }, module, true); using (var il = new GroboIL(dynamicMethod)) { il.Ldarg(0); // stack: [obj] if (type.IsValueType) { il.Unbox_Any(type); // stack: [(type)obj] } else { il.Castclass(type); // stack: [(type)obj] } il.Ldarg(1); // stack: [(type)obj, writeEmpty] il.Ldarg(2); // stack: [(type)obj, writeEmpty, result] il.Ldarg(3); // stack: [(type)obj, writeEmpty, result, ref index] il.Ldarg(4); // stack: [(type)obj, writeEmpty, result, ref index, context] il.Ldc_IntPtr(writer); il.Calli(CallingConventions.Standard, typeof(void), new[] { type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) }); // writer.write<T>((type)obj, writeEmpty, result, ref index, context); stack: [] il.Ret(); } return((WriterDelegate)dynamicMethod.CreateDelegate(typeof(WriterDelegate))); }
private void TestSuccess(Type type1, Type type2) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] { type1, type2, }.Where(type => type != null).ToArray(), typeof(string), true); using (var il = new GroboIL(method)) { var index = 0; if (type1 != null) { il.Ldarg(index++); } else { il.Ldnull(); } if (type2 != null) { il.Ldarg(index++); } else { il.Ldnull(); } il.Sub(); il.Pop(); il.Ret(); Console.WriteLine(il.GetILCode()); } }
public static void WriteOffsetAppend(GroboIL il, GroboIL.Local offset, int len) { il.Ldloc(offset); il.Ldc_I4(len); il.Add(); il.Stloc(offset); }
public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack) { if (stack.Count != 0) { throw new InvalidOperationException("The evaluation stack must be empty in order to perform the 'jmp' instruction\r\n" + il.GetILCode()); } }
public static Func <Dictionary <string, object>, object> GenerateMethod(Type type) { var da = AppDomain.CurrentDomain.DefineDynamicAssembly( new AssemblyName("dyn"), // call it whatever you want AssemblyBuilderAccess.RunAndSave); var dm = da.DefineDynamicModule("dyn_mod", "dyn.dll"); var dt = dm.DefineType("dyn_type"); var emiter = Emit <Func <int> > .NewDynamicMethod("MyMethod"); var method = dt.DefineMethod( "Foo", MethodAttributes.Public | MethodAttributes.Static, typeof(object), new[] { typeof(Dictionary <string, object>) }); method.DefineParameter(1, ParameterAttributes.None, "dictionary"); using (var il = new GroboIL(method)) { var target = il.DeclareLocal(type); var value = il.DeclareLocal(typeof(object)); il.Newobj(type.GetConstructor(Type.EmptyTypes)); // [Person] il.Stloc(target); // [] foreach (var property in type.GetProperties()) { var label = il.DefineLabel("ifLabel"); il.Ldarg(0); // [Dictionary<String, Object>] il.Ldstr(property.Name); // [Dictionary<String, Object>, String] il.Ldloca(value); // [Dictionary<String, Object>, String, Object&] il.Call(typeof(Dictionary <string, object>) .GetMethod("TryGetValue")); // [Boolean] il.Brfalse(label); // [] il.Ldloc(target); // [Person] il.Ldloc(value); // [Person, Object] il.Castclass(typeof(string)); // [Dictionary<String, Object>, String] il.Call(property.GetSetMethod(true)); // [] il.MarkLabel(label); } il.Ldloc(target); il.Ret(); Console.WriteLine(il.GetILCode()); } dt.CreateType(); da.Save("dyn.dll"); return((dic) => dt.GetMethod("Foo").Invoke(null, new object[] { dic })); }
public void GetWriteILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local value, GroboIL.Local typeSize, GroboIL.Local buffer, GroboIL.Local offset, bool listValue) { BinaryStruct.WriteSizeChecker(il, buffer, offset, 8); var arr = il.DeclareLocal(typeof(byte[])); il.Ldloc(value); if (!listValue) { il.Call(prop.Getter); } il.Dup(); il.Pop(); il.Call(writeBitConverterMethodInfo); il.Stloc(arr); il.Ldloc(buffer); il.Ldloc(offset); il.Ldloc(arr); il.Ldc_I4(0); il.Ldelem(typeof(byte)); il.Stelem(typeof(byte)); for (int i = 1; i < 8; i++) { il.Ldloc(buffer); il.Ldloc(offset); il.Ldc_I4(i); il.Add(); il.Ldloc(arr); il.Ldc_I4(i); il.Ldelem(typeof(byte)); il.Stelem(typeof(byte)); } BinaryStruct.WriteOffsetAppend(il, offset, 8); }
public static void WriteOffsetAppend(GroboIL il, GroboIL.Local offset, GroboIL.Local typeSize) { il.Ldloc(offset); il.Ldloc(typeSize); il.Add(); il.Stloc(offset); }
public void GetReadILCode(PropertyData prop, BinaryStruct currentStruct, GroboIL il, GroboIL.Local binaryStruct, GroboIL.Local buffer, GroboIL.Local result, GroboIL.Local typeSize, GroboIL.Local offset, bool listValue) { var r = il.DeclareLocal(typeof(TimeSpan)); var v = il.DeclareLocal(typeof(double)); il.Ldloc(buffer); il.Ldloc(offset); il.Call(readBitConverterMethodInfo); il.Stloc(v); il.Ldloc(v); il.Call(timeSpanConstructor); if (listValue) { il.Stloc(result); } else { il.Stloc(r); } BinaryStruct.WriteOffsetAppend(il, offset, 8); if (!listValue) { il.Ldloc(result); il.Ldloc(r); il.Call(prop.Setter, isVirtual: true); } }
public static Type GenerateClass(ClassDescription description) { var name = new AssemblyName("MyAssembly"); AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly( name, AssemblyBuilderAccess.RunAndSave); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule( name.Name, name.Name + ".dll"); TypeBuilder typeBuilder = moduleBuilder.DefineType( description.TypeName, TypeAttributes.Class | TypeAttributes.Public); foreach (var constructorDescr in description.Constructors) { var staticOrDynamicAttr = constructorDescr.StaticOrDynamic == StaticOrDynamic.Static ? MethodAttributes.Static : MethodAttributes.Public; // второй вариант по сути ничего не добавляет, но атрибута Dynamic нет var inTypes = constructorDescr.InputTypes .Select(typeName => description.AllTypes[typeName].RealType) .ToArray(); typeBuilder.DefineConstructor( MethodAttributes.Public | staticOrDynamicAttr, CallingConventions.Standard, inTypes); } foreach (var methodDescr in description.Methods) { var staticOrDynamicAttr = methodDescr.StaticOrDynamic == StaticOrDynamic.Static ? MethodAttributes.Static : MethodAttributes.Public; var outType = description.AllTypes[methodDescr.OutputType].RealType; var inTypes = methodDescr.InputTypes .Select(typeName => description.AllTypes[typeName].RealType) .ToArray(); var method = typeBuilder.DefineMethod( methodDescr.MethodName, MethodAttributes.Public | staticOrDynamicAttr, outType, inTypes); GroboIL iLgenerator = new GroboIL(method); iLgenerator.Newobj(new NotImplementedException() .GetType() .GetConstructors()[0]); iLgenerator.Throw(); } var type = typeBuilder.CreateType(); assemblyBuilder.Save(name.Name + ".dll"); return(type); }
public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack) { var type = ((TypeILInstructionParameter)parameter).Type; CheckNotEmpty(il, stack, () => "An object must be put onto the evaluation stack in order to perform the 'unbox_any' instruction"); CheckCanBeAssigned(il, typeof(object), stack.Pop()); stack.Push(type); }
public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack) { var type = ((TypeILInstructionParameter)parameter).Type; CheckNotEmpty(il, stack, () => "In order to perform the 'newarr' instruction a length of an array must be loaded onto the evaluation stack"); CheckCanBeAssigned(il, typeof(int), stack.Pop()); stack.Push(type.MakeArrayType()); }
public ReaderMethodBuilderContext(ReaderTypeBuilderContext context, GroboIL il, bool referenceType) { Context = context; Il = il; TypeCode = il.DeclareLocal(typeof(int)); Length = il.DeclareLocal(typeof(uint)); Index = referenceType ? il.DeclareLocal(typeof(int)) : null; }
public void Test_ldvirtftn3() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), Type.EmptyTypes, typeof(string), true); var il = new GroboIL(method); il.Newobj(typeof(C2).GetConstructor(Type.EmptyTypes)); Assert.Throws <InvalidOperationException>(() => il.Ldvirtftn(typeof(I1).GetMethod("Zzz"))); }
public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack) { var type = ((TypeILInstructionParameter)parameter).Type; CheckNotEmpty(il, stack, () => "In order to perform the 'isinst' instruction an instance must be put onto the evaluation stack"); CheckCanBeAssigned(il, typeof(object), stack.Pop()); stack.Push(type.IsValueType ? typeof(object) : type); }
public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack) { var type = ((TypeILInstructionParameter)parameter).Type; CheckNotEmpty(il, stack, () => "To perform the 'box' instruction load a value on the evaluation stack"); CheckCanBeAssigned(il, type, stack.Pop()); stack.Push(type.IsEnum ? typeof(Enum) : typeof(object)); }
private static void EmitMinusMinusX(this GroboIL il, GroboIL.Local intLocal) { il.Ldloc(intLocal); il.Ldc_I4(1); il.Sub(); il.Dup(); il.Stloc(intLocal); }
private GroboIL.Local EmitDictDeclaration(GroboIL il) { il.Newobj(typeof(Dictionary <string, object>).GetConstructor(new Type[0])); var dict = il.DeclareLocal(typeof(Dictionary <string, object>), "dict"); il.Stloc(dict); return(dict); }
private static void EmitXPlusPlus(this GroboIL il, GroboIL.Local intLocal) { il.Ldloc(intLocal); il.Dup(); il.Ldc_I4(1); il.Add(); il.Stloc(intLocal); }
public static void ReadObjectNull(GroboIL il, GroboIL.Label finishMethod, GroboIL.Local buffer, GroboIL.Local offset, GroboIL.Local typeSize) { il.Ldloc(buffer); il.Ldloc(offset); il.Ldelem(typeof(byte)); WriteOffsetAppend(il, offset, 1); il.Brtrue(finishMethod); }
private static void EmitBne(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse) { // a.Property == b.Property il.Ldarg(0); il.Call(getMethod); il.Ldarg(1); il.Call(getMethod); il.Bne_Un(returnFalse); }
public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack) { CheckNotEmpty(il, stack, () => "In order to perform the 'initblk' instruction a number of bytes to initialize must be put onto the evaluation stack"); CheckCanBeAssigned(il, typeof(int), stack.Pop()); CheckNotEmpty(il, stack, () => "In order to perform the 'initblk' instruction an initialization value must be put onto the evaluation stack"); CheckCanBeAssigned(il, typeof(int), stack.Pop()); CheckNotEmpty(il, stack, () => "In order to perform the 'initblk' instruction a starting address must be put onto the evaluation stack"); CheckIsAPointer(il, stack.Pop()); }
public static Delegate Emit(Type type) { Console.WriteLine("EMITTING " + type); var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { type, type }, type, true); using (var il = new GroboIL(method)) { var r0 = il.DefineLabel("Return_0", false); // todo: inheritance // todo: public/private // todo: fields // todo: options for public/private, field/property var props = type.GetProperties(); foreach (var propertyInfo in props) { // todo: nullable // todo: array // todo: struct (DateTime, Guid) var propertyType = propertyInfo.PropertyType; var nullableType = Nullable.GetUnderlyingType(propertyType); if (BneTypes.Contains(propertyType) || propertyType.IsEnum) { EmitBne(il, propertyInfo.GetMethod, r0); } else if (StaticEqualsTypes.ContainsKey(propertyType)) { EmitStatic(il, propertyInfo.GetMethod, StaticEqualsTypes[propertyType], r0); } else if (InstanceEqualsTypes.ContainsKey(propertyType)) { EmitInstance(il, propertyInfo.GetMethod, InstanceEqualsTypes[propertyType], r0); } else if (nullableType != null && (BneTypes.Contains(nullableType) || nullableType.IsEnum)) { EmitNullableBne(il, propertyInfo.GetMethod, r0); } else if (nullableType != null) { EmitNullableEquals(il, propertyInfo.GetMethod, r0); } else { EmitStatic(il, propertyInfo.GetMethod, EmittedEquals, r0); } } il.Ldc_I4(1); il.Ret(); il.MarkLabel(r0); il.Ldc_I4(0); il.Ret(); Console.WriteLine(il.GetILCode()); } return(method.CreateDelegate(typeof(Func <, ,>).MakeGenericType(type, type, typeof(bool)))); }
public static Delegate Emit(Type type) { Console.WriteLine("EMITTING " + type); var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof (bool), new[] { type, type }, type, true); using (var il = new GroboIL(method)) { var r0 = il.DefineLabel("Return_0", false); // todo: inheritance // todo: public/private // todo: fields // todo: options for public/private, field/property var props = type.GetProperties(); foreach (var propertyInfo in props) { // todo: nullable // todo: array // todo: struct (DateTime, Guid) var propertyType = propertyInfo.PropertyType; var nullableType = Nullable.GetUnderlyingType(propertyType); if (BneTypes.Contains(propertyType) || propertyType.IsEnum) EmitBne(il, propertyInfo.GetMethod, r0); else if (StaticEqualsTypes.ContainsKey(propertyType)) EmitStatic(il, propertyInfo.GetMethod, StaticEqualsTypes[propertyType], r0); else if (InstanceEqualsTypes.ContainsKey(propertyType)) EmitInstance(il, propertyInfo.GetMethod, InstanceEqualsTypes[propertyType], r0); else if (nullableType != null && (BneTypes.Contains(nullableType) || nullableType.IsEnum)) EmitNullableBne(il, propertyInfo.GetMethod, r0); else if (nullableType != null) EmitNullableEquals(il, propertyInfo.GetMethod, r0); else EmitStatic(il, propertyInfo.GetMethod, EmittedEquals, r0); } il.Ldc_I4(1); il.Ret(); il.MarkLabel(r0); il.Ldc_I4(0); il.Ret(); Console.WriteLine(il.GetILCode()); } return method.CreateDelegate(typeof(Func<,,>).MakeGenericType(type, type, typeof(bool))); }
private static void EmitNullableBne(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse) { // a.GetValueOrDefault() == b.GetValueOrDefault() && a.HasValue == b.HasValue; var type = getMethod.ReturnType; var getValueOrDefault = type.GetMethod("GetValueOrDefault", new Type[0]); var hasValue = type.GetMethod("get_HasValue"); var a = il.DeclareLocal(type); var b = il.DeclareLocal(type); il.Ldarg(0); il.Call(getMethod); il.Stloc(a); il.Ldarg(1); il.Call(getMethod); il.Stloc(b); il.Ldloca(a); il.Call(getValueOrDefault); il.Ldloca(b); il.Call(getValueOrDefault); il.Bne_Un(returnFalse); il.Ldloca(a); il.Call(hasValue); il.Ldloca(b); il.Call(hasValue); il.Bne_Un(returnFalse); }
private static void EmitNullableEquals(GroboIL il, MethodInfo getMethod, GroboIL.Label returnFalse) { // a.Equals(b) var type = getMethod.ReturnType; var local = il.DeclareLocal(type); il.Ldarg(0); il.Call(getMethod); il.Stloc(local); il.Ldloca(local); il.Ldarg(1); il.Call(getMethod); il.Box(type); il.Call(ObjectEquals, type); il.Brfalse(returnFalse); }
private static void EmitStatic(GroboIL il, MethodInfo getMethod, MethodInfo staticMethod, GroboIL.Label returnFalse) { // Equals(a.Property, b.Property) il.Ldarg(0); il.Call(getMethod); il.Ldarg(1); il.Call(getMethod); il.Call(staticMethod); il.Brfalse(returnFalse); }
private static void EmitInstance(GroboIL il, MethodInfo getMethod, MethodInfo instanceMethod, GroboIL.Label returnFalse) { // a.Property.Equals(b.Property) var type = getMethod.ReturnType; var local = il.DeclareLocal(type); il.Ldarg(0); il.Call(getMethod); il.Stloc(local); il.Ldloca(local); il.Ldarg(1); il.Call(getMethod); il.Call(instanceMethod, type); il.Brfalse(returnFalse); }