private static void CreateMethod(AmObjectClassBuildingContext context, IAmBindingDescription bindingDesc, MethodInfo method) { var methodBuilder = context.TypeBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual); methodBuilder.SetParameters(method.GetParameters().Select(x => x.ParameterType).ToArray()); methodBuilder.SetReturnType(method.ReturnType); methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed); var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); var field = context.Fields.GetOrAddBindingField(bindingDesc); if (method.Name.StartsWith("get_")) { il.Ldarg(0); il.Ldfld(field); il.Call(bindingDesc.MakePropertyGetMethod(context.AmClass)); il.Ret(); } else if (method.Name.StartsWith("set_")) { il.Ldarg(0); il.Ldfld(field); il.Ldarg(1); il.Call(bindingDesc.MakePropertySetMethod(context.AmClass)); il.Ret(); } else { throw new Exception($"Either getter or setter expected, but '{method.Name}' found."); } context.TypeBuilder.DefineMethodOverride(methodBuilder, method); }
private void CreateInitBindingsMethod(AmObjectClassBuildingContext context) { var methodBuilder = context.TypeBuilder.DefineMethod("AmInitBindings", MethodAttributes.Public | MethodAttributes.Virtual); methodBuilder.SetParameters(Type.EmptyTypes); methodBuilder.SetReturnType(typeof(List <IAmBinding>)); methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed); var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); var varList = il.DeclareLocal(typeof(List <IAmBinding>)); il.Newobj(typeof(List <IAmBinding>).GetConstructor(Type.EmptyTypes)); il.Stloc(varList); foreach (var bindingDesc in context.Desc.Bindings) { var field = context.Fields.GetOrAddBindingField(bindingDesc); il.Ldarg(0); // [this] il.Dup(); // [this, this] il.Ldstr(bindingDesc.Property.Name); // [this, this, propName] il.Ldc_I4((int)bindingDesc.Flags); // [this, this, propName, flags] var bindingCtor = field.FieldType.GetConstructors().Single(); il.Newobj(bindingCtor); // [this, binding] il.Stfld(field); // [] il.Ldloc(varList); // [list] il.Ldarg(0); // [list, this] il.Ldfld(field); // [list, binding] var addMethod = typeof(List <IAmBinding>).GetMethod(nameof(List <IAmBinding> .Add)); il.Callvirt(addMethod); // [] } il.Ldloc(varList); il.Ret(); }
// int SizeOf<T>() private static void DefineSizeOfGenericMethod(TypeBuilder typeBuilder) { var methodBuilder = typeBuilder.DefineMethod("SizeOf", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static); var genericTypeParams = methodBuilder.DefineGenericParameters("T"); var genericParam = genericTypeParams.Single(); methodBuilder.SetReturnType(typeof(int)); methodBuilder.SetParameters(Type.EmptyTypes); methodBuilder.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); il.Sizeof(genericParam); il.Conv_I4(); il.Ret(); }
// T Read<T>(byte* src) private static void DefineReadMethod(TypeBuilder typeBuilder) { var methodBuilder = typeBuilder.DefineMethod("Read", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static); var genericTypeParams = methodBuilder.DefineGenericParameters("T"); var genericParam = genericTypeParams.Single(); methodBuilder.SetReturnType(genericParam); methodBuilder.SetParameters(typeof(byte *)); methodBuilder.DefineParameter(1, 0, "src"); methodBuilder.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); il.Ldarg(0); il.Ldobj(genericParam); il.Ret(); }
// void Write<T>(byte* dst, T[] array) private static void DefineWriteArrayMethod(TypeBuilder typeBuilder) { var methodBuilder = typeBuilder.DefineMethod("Write", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static); var genericTypeParams = methodBuilder.DefineGenericParameters("T"); var genericParam = genericTypeParams.Single(); methodBuilder.SetReturnType(typeof(void)); methodBuilder.SetParameters(typeof(byte *), genericParam.MakeArrayType()); methodBuilder.DefineParameter(1, 0, "dst"); methodBuilder.DefineParameter(2, 0, "src"); methodBuilder.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); var okLabel = il.DefineLabel(); var endLabel = il.DefineLabel(); il.Ldarg(1); il.Brtrue(okLabel); il.Ldstr("src"); il.Newobj(typeof(ArgumentNullException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(okLabel); il.Ldarg(1); il.Ldlen(); il.Conv_I4(); il.Brfalse(endLabel); var pinnedVar = il.PinArray(genericParam, 1); il.Ldarg(0); il.Ldloc(pinnedVar); il.Ldarg(1); il.Ldlen(); il.Conv_I4(); il.Sizeof(genericParam); il.Mul(); il.Cpblk(); il.UnpinArray(pinnedVar); il.MarkLabel(endLabel); il.Ret(); }
// int SizeOf(Type type) //private static void DefineSizeOfMethod(TypeBuilder typeBuilder) //{ // var methodBuilder = typeBuilder.DefineMethod("SizeOf", // MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static); // methodBuilder.SetReturnType(typeof(int)); // methodBuilder.SetParameters(typeof(Type)); // methodBuilder.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); // var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); // // il.Ldarg(0); // var sizeOfMethod = typeof(Marshal).GetMethod("SizeOf", new[] { typeof(Type) }); // il.Call(sizeOfMethod); // il.Ret(); //} // void CopyBulk(byte* dst, byte* src, int numBytes) private static void DefineCopyBulkMethod(TypeBuilder typeBuilder) { var methodBuilder = typeBuilder.DefineMethod("CopyBulk", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static); methodBuilder.SetReturnType(typeof(void)); methodBuilder.SetParameters(typeof(byte *), typeof(byte *), typeof(int)); methodBuilder.DefineParameter(1, 0, "dst"); methodBuilder.DefineParameter(2, 0, "src"); methodBuilder.DefineParameter(3, 0, "numBytes"); methodBuilder.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); il.Ldarg(0); il.Ldarg(1); il.Ldarg(2); il.Cpblk(); il.Ret(); }
private void CreateConstructor(AmObjectClassBuildingContext context) { var baseConstructor = context.AmClass.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance).Single(); var parameterTypes = baseConstructor.GetParameters().Select(x => x.ParameterType).ToArray(); var constructorBuilder = context.TypeBuilder.DefineConstructor( MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, parameterTypes); var il = new CilEmitterSugar(constructorBuilder.GetILGenerator()); il.Ldarg(0); // [this] for (int i = 0; i < parameterTypes.Length; i++) { il.Ldarg(i + 1); } il.Call(baseConstructor); // [] //il.Ldarg(0); //il.Callvirt(typeof(IAmObject).GetMethod(nameof(IAmObject.AmOnFinalized))); il.Ret(); }
// void CopyBulkUniversal(byte* dst, byte* src, int numBytes) private static void DefineCopyBulkUniversalMethod(TypeBuilder typeBuilder) { var methodBuilder = typeBuilder.DefineMethod("CopyBulkUniversal", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static); methodBuilder.SetReturnType(typeof(void)); methodBuilder.SetParameters(typeof(byte *), typeof(byte *), typeof(int)); methodBuilder.DefineParameter(1, 0, "dst"); methodBuilder.DefineParameter(2, 0, "src"); methodBuilder.DefineParameter(3, 0, "numBytes"); methodBuilder.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); var toInt64Method = typeof(IntPtr).GetMethod("ToInt64"); var getSizeMethod = typeof(IntPtr).GetMethod("get_Size"); il.Ldarg(0); il.Call(toInt64Method); il.Ldarg(1); il.Call(toInt64Method); il.Or(); // [(dst.ToInt64() | src.ToInt64())] il.Call(getSizeMethod); il.Ldc_I4(1); il.Sub(); il.Conv_I8(); il.And(); // [((dst.ToInt64() | src.ToInt64()) & (IntPtr.Size - 1))] var cpblkLabel = il.DefineLabel(); il.Brfalse(cpblkLabel); il.Unaligned(1); il.MarkLabel(cpblkLabel); il.Ldarg(0); il.Ldarg(1); il.Ldarg(2); il.Cpblk(); il.Ret(); }
// void Read<T>(T[] dst, byte* src, int startElem, int numElems) private static void DefineReadArrayRangeMethod(TypeBuilder typeBuilder) { var methodBuilder = typeBuilder.DefineMethod("Read", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static); var genericTypeParams = methodBuilder.DefineGenericParameters("T"); var genericParam = genericTypeParams.Single(); methodBuilder.SetReturnType(typeof(void)); methodBuilder.SetParameters(genericParam.MakeArrayType(), typeof(byte *), typeof(int), typeof(int)); methodBuilder.DefineParameter(1, 0, "dst"); methodBuilder.DefineParameter(2, 0, "src"); methodBuilder.DefineParameter(3, 0, "startElem"); methodBuilder.DefineParameter(4, 0, "numElems"); methodBuilder.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); var il = new CilEmitterSugar(methodBuilder.GetILGenerator()); var throwLabel = il.DefineLabel(); var okLabel = il.DefineLabel(); var endLabel = il.DefineLabel(); il.Ldarg(0); il.Brfalse(throwLabel); il.Ldarg(2); il.Ldc_I4(0); il.Blt(throwLabel); il.Ldarg(0); il.Ldlen(); il.Ldarg(2); il.Ldarg(3); il.Add(); il.Bge(okLabel); il.MarkLabel(throwLabel); il.Ldstr("Array is either null or the range is outside its bounds."); il.Newobj(typeof(ArgumentException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(okLabel); il.Ldarg(3); il.Ldc_I4(1); il.Blt(endLabel); var pinnedVar = il.PinArray(genericParam, 0); il.Ldloc(pinnedVar); il.Ldarg(2); il.Sizeof(genericParam); il.Mul(); il.Add(); il.Ldarg(1); il.Ldarg(3); il.Sizeof(genericParam); il.Mul(); il.Cpblk(); il.UnpinArray(pinnedVar); il.MarkLabel(endLabel); il.Ret(); }