private ITest BuildCall() { var typeBuilder = Module.DefineType(Guid.NewGuid().ToString(), TypeAttributes.Class | TypeAttributes.Public); var doNothingMethod = typeBuilder.DefineMethod("DoNothingImpl", MethodAttributes.Public, typeof(void), Type.EmptyTypes); using (var il = new GroboIL(doNothingMethod)) { il.Ldfld(xField); il.Ldc_I4(1); il.Add(); il.Stfld(xField); il.Ret(); } var method = typeBuilder.DefineMethod("DoNothing", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), Type.EmptyTypes); using (var il = new GroboIL(method)) { il.Ldarg(0); il.Call(doNothingMethod); il.Ret(); } typeBuilder.DefineMethodOverride(method, typeof(ITest).GetMethod("DoNothing")); typeBuilder.AddInterfaceImplementation(typeof(ITest)); var type = typeBuilder.CreateType(); return((ITest)Activator.CreateInstance(type)); }
private ITest BuildDelegate() { var action = Build(); var typeBuilder = Module.DefineType(Guid.NewGuid().ToString(), TypeAttributes.Class | TypeAttributes.Public); var actionField = typeBuilder.DefineField("action", typeof(Action), FieldAttributes.Private | FieldAttributes.InitOnly); var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(Action) }); using (var il = new GroboIL(constructor)) { il.Ldarg(0); il.Ldarg(1); il.Stfld(actionField); il.Ret(); } var method = typeBuilder.DefineMethod("DoNothing", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), Type.EmptyTypes); using (var il = new GroboIL(method)) { il.Ldarg(0); il.Ldfld(actionField); il.Call(typeof(Action).GetMethod("Invoke", Type.EmptyTypes), typeof(Action)); il.Ret(); } typeBuilder.DefineMethodOverride(method, typeof(ITest).GetMethod("DoNothing")); typeBuilder.AddInterfaceImplementation(typeof(ITest)); var type = typeBuilder.CreateType(); return((ITest)Activator.CreateInstance(type, new object[] { action.Item1 })); }
private void LoadTupleField(GroboIL il, ValueTupleField tupleFiled) { il.Ldstr(tupleFiled.NameInUserCode); il.Ldarga(0); il.Ldfld(tupleFiled.FieldInfo); if (tupleFiled.FieldInfo.FieldType.IsValueType) { il.Box(tupleFiled.FieldInfo.FieldType); } }
private Func <string, string> BuildSwitch4() { Init(new[] { "0", "2", "5", "1000001", "7", "1000000" }); var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), new[] { typeof(string) }, Module, true); using (var il = new GroboIL(dynamicMethod)) { var zzzLabel = il.DefineLabel("zzz"); var qxxLabel = il.DefineLabel("qxx"); var qzzLabel = il.DefineLabel("qzz"); var xxxLabel = il.DefineLabel("xxx"); var index = il.DeclareLocal(typeof(uint)); il.Ldfld(typeof(TestPerformance).GetField("testValues2")); il.Ldarg(0); il.Call(typeof(object).GetMethod("GetHashCode"), typeof(string)); il.Ldc_I4(testValues2.Length); il.Rem(true); il.Stloc(index); il.Ldloc(index); il.Ldelem(typeof(string)); il.Ldarg(0); il.Call(typeof(object).GetMethod("Equals", new[] { typeof(object) }), typeof(string)); il.Brfalse(xxxLabel); il.Ldfld(typeof(TestPerformance).GetField("indexes2")); il.Ldloc(index); il.Ldelem(typeof(int)); il.Switch(zzzLabel, zzzLabel, qxxLabel, qxxLabel, qzzLabel, qzzLabel); il.Br(xxxLabel); il.MarkLabel(zzzLabel); il.Ldstr("zzz"); il.Ret(); il.MarkLabel(qxxLabel); il.Ldstr("qxx"); il.Ret(); il.MarkLabel(qzzLabel); il.Ldstr("qzz"); il.Ret(); il.MarkLabel(xxxLabel); il.Ldstr("xxx"); il.Ret(); } return((Func <string, string>)dynamicMethod.CreateDelegate(typeof(Func <string, string>))); }
public static TryGetValueDelegate <T> Build <T>(string[] keys, T[] values, Func <string, int> hashCodeEvaluator) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(Closure <T>), typeof(string), typeof(T).MakeByRefType() }, typeof(string), true); var hashCodes = keys.Select(hashCodeEvaluator).ToArray(); int n = keys.Length; var indexes = new int[n]; for (int i = 0; i < n; ++i) { indexes[i] = i; } Array.Sort(indexes, (lhs, rhs) => hashCodes[lhs].CompareTo(hashCodes[rhs])); using (var il = new GroboIL(method)) { var retFalseLabel = il.DefineLabel("retFalse"); var hashCode = il.DeclareLocal(typeof(int), "hashCode"); il.Ldarg(0); // stack: [closure] il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.hashCodeEvaluator)); // stack: [closure.hashCodeEvaluator] il.Ldarg(1); // stack: [closure.hashCodeEvaluator, key] il.Call(typeof(Func <string, int>).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public)); // stack: [closure.hashCodeEvaluator(key)] il.Stloc(hashCode); // hashCode = closure.hashCodeEvaluator(key); stack: [] var context = new EmittingContext { Il = il, Keys = keys, HashCodes = hashCodes, Indexes = indexes, HashCode = hashCode, RetFalseLabel = retFalseLabel }; DoBinarySearch <T>(context, 0, n - 1); il.MarkLabel(retFalseLabel); il.Ldarg(2); // stack: [ref value] if (typeof(T).IsValueType) { il.Initobj(typeof(T)); // value = default(T); stack: [] } else { il.Ldnull(); // stack: [ref value, null] il.Stind(typeof(T)); // value = null; stack: [] } il.Ldc_I4(0); // stack: [false] il.Ret(); } var closure = new Closure <T> { hashCodeEvaluator = hashCodeEvaluator, values = values }; return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure)); }
private static Tuple <Delegate, IntPtr> EmitFieldExtractor <T, TValue>(FieldInfo field) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(TValue), new[] { typeof(T) }, typeof(string), true); using (var il = new GroboIL(method)) { il.Ldarg(0); // stack: [list] il.Ldfld(field); il.Ret(); } return(new Tuple <Delegate, IntPtr>((Func <T, TValue>)method.CreateDelegate(typeof(Func <T, TValue>)), DynamicMethodInvokerBuilder.DynamicMethodPointerExtractor(method))); }
private DynamicMethod BuildAccessorMethod() { var assertMethod = typeof(TestGrobufUsages).GetMethod("AssertDateTimeOffsetFields", BindingFlags.Static | BindingFlags.NonPublic); var method = new DynamicMethod("Grobuf_Write_DateTimeOffset_" + Guid.NewGuid(), typeof(void), new[] { dateTimeOffsetType }, typeof(TestGrobufUsages), true); using (var il = new GroboIL(method)) { il.Ldarga(0); // stack: [obj] il.Ldfld(GetDateTimeOffsetField("_dateTime", "m_dateTime")); // stack: [obj.m_dateTime] il.Ldarga(0); // stack: [obj] il.Ldfld(GetDateTimeOffsetField("_offsetMinutes", "m_offsetMinutes")); // stack: [obj.m_offsetMinutes] il.Call(assertMethod); // stack: [] il.Ret(); } return(method); }
private Func <int, string> BuildSwitch2() { var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), new[] { typeof(int) }, Module, true); using (var il = new GroboIL(dynamicMethod)) { var zzzLabel = il.DefineLabel("zzz"); var qxxLabel = il.DefineLabel("qxx"); var qzzLabel = il.DefineLabel("qzz"); var xxxLabel = il.DefineLabel("xxx"); var index = il.DeclareLocal(typeof(uint)); il.Ldfld(typeof(TestPerformance).GetField("testValues")); il.Ldarg(0); il.Ldc_I4(14); il.Rem(true); il.Stloc(index); il.Ldloc(index); il.Ldelem(typeof(int)); il.Ldarg(0); il.Bne_Un(xxxLabel); il.Ldfld(typeof(TestPerformance).GetField("indexes")); il.Ldloc(index); il.Ldelem(typeof(int)); il.Switch(zzzLabel, zzzLabel, qxxLabel, qzzLabel, qzzLabel, qxxLabel); il.Br(xxxLabel); il.MarkLabel(zzzLabel); il.Ldstr("zzz"); il.Ret(); il.MarkLabel(qxxLabel); il.Ldstr("qxx"); il.Ret(); il.MarkLabel(qzzLabel); il.Ldstr("qzz"); il.Ret(); il.MarkLabel(xxxLabel); il.Ldstr("xxx"); il.Ret(); } return((Func <int, string>)dynamicMethod.CreateDelegate(typeof(Func <int, string>))); }
private static Func <object, object> EmitResolveVarArgsMethod() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object) }, typeof(string), true); using (var il = new GroboIL(method)) { var VarArgMethod_t = typeof(DynamicMethod).Assembly.GetType("System.Reflection.Emit.VarArgMethod"); if (VarArgMethod_t == null) { throw new InvalidOperationException("Missing type 'System.Reflection.Emit.VarArgMethod'"); } il.Ldarg(0); // stack: [value] il.Isinst(VarArgMethod_t); // stack: [(VarArgMethod)value] var retLabel = il.DefineLabel("ret"); il.Dup(); // stack: [(VarArgMethod)value, (VarArgMethod)value] il.Brfalse(retLabel); // if(!(value is VarArgMethod)) goto ret; stack: [value as VarArgMethod] var m_method_f = VarArgMethod_t.GetField("m_method", BindingFlags.Instance | BindingFlags.NonPublic); if (m_method_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.VarArgMethod.m_method'"); } var m_dynamicMethod_f = VarArgMethod_t.GetField("m_dynamicMethod", BindingFlags.Instance | BindingFlags.NonPublic); if (m_dynamicMethod_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.VarArgMethod.m_dynamicMethod'"); } var temp = il.DeclareLocal(VarArgMethod_t); il.Dup(); il.Stloc(temp); // temp = (VarArgMethod)value; stack: [(VarArgMethod)value] il.Ldfld(m_method_f); // stack: [((VarArgMethod)value).m_method] il.Dup(); // stack: [((VarArgMethod)value).m_method, ((VarArgMethod)value).m_method] il.Brtrue(retLabel); // if(((VarArgMethod)value).m_method != null) goto ret; stack: [((VarArgMethod)value).m_method] il.Pop(); // stack: [] il.Ldloc(temp); // stack: [(VarArgMethod)value] il.Ldfld(m_dynamicMethod_f); // stack: [((VarArgMethod)value).m_dynamicMethod] il.MarkLabel(retLabel); il.Ret(); } return((Func <object, object>)method.CreateDelegate(typeof(Func <object, object>))); }
private static Func <object, object> EmitResolveGenericMethodInfo() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object) }, typeof(string), true); using (var il = new GroboIL(method)) { var GenericMethodInfo_t = typeof(DynamicMethod).Assembly.GetType("System.Reflection.Emit.GenericMethodInfo"); if (GenericMethodInfo_t == null) { throw new InvalidOperationException("Missing type 'System.Reflection.Emit.GenericMethodInfo'"); } il.Ldarg(0); // stack: [value] il.Isinst(GenericMethodInfo_t); // stack: [(GenericMethodInfo)value] var retLabel = il.DefineLabel("ret"); il.Dup(); // stack: [(GenericMethodInfo)value, (GenericMethodInfo)value] il.Brfalse(retLabel); // if(!(value is GenericMethodInfo)) goto ret; stack: [value as GenericMethodInfo] var m_methodHandle_f = GenericMethodInfo_t.GetField("m_methodHandle", BindingFlags.Instance | BindingFlags.NonPublic); if (m_methodHandle_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.GenericMethodInfo.m_methodHandle'"); } var m_context_f = GenericMethodInfo_t.GetField("m_context", BindingFlags.Instance | BindingFlags.NonPublic); if (m_context_f == null) { throw new InvalidOperationException("Missing field 'System.Reflection.Emit.GenericMethodInfo.m_context'"); } var temp = il.DeclareLocal(GenericMethodInfo_t); il.Dup(); il.Stloc(temp); // temp = (GenericMethodInfo)value; stack: [(GenericMethodInfo)value] il.Ldfld(m_methodHandle_f); // stack: [((GenericMethodInfo)value).m_methodHandle] il.Ldloc(temp); // stack: [((GenericMethodInfo)value).m_methodHandle, (GenericMethodInfo)value] il.Ldfld(m_context_f); // stack: [((GenericMethodInfo)value).m_methodHandle, ((GenericMethodInfo)value).m_context] var getMethodFromHandle_m = HackHelpers.GetMethodDefinition <int>(x => MethodBase.GetMethodFromHandle(default(RuntimeMethodHandle), default(RuntimeTypeHandle))); il.Call(getMethodFromHandle_m); // stack: [MethodBase.GetMethodFromHandle(((GenericMethodInfo)value).m_methodHandle, ((GenericMethodInfo)value).m_context)] il.MarkLabel(retLabel); il.Ret(); } return((Func <object, object>)method.CreateDelegate(typeof(Func <object, object>))); }
private Tuple <Action, MethodInfo> Build() { var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(void), Type.EmptyTypes, Module, true); using (var il = new GroboIL(dynamicMethod)) { il.Ldfld(xField); il.Ldc_I4(1); il.Add(); il.Stfld(xField); il.Ret(); } return(new Tuple <Action, MethodInfo>((Action)dynamicMethod.CreateDelegate(typeof(Action)), dynamicMethod)); }
private static MethodBuilder DefineMethodInterceptingDelegate(TypeBuilder typeBuilder, MethodInfo overridedMethod, Dictionary <Type, FieldInfo> interceptorFields, MethodInfo genericInterceptionAction, MethodInfo voidInterceptionAction, Type[] genericParameterTypes, MethodBuilder @delegate, int index, Type interceptor) { ConstructorInfo delegateConstructor; MethodInfo interceptorMethod; // Define the method var method = typeBuilder.DefineMethod($"{overridedMethod.Name}-{interceptor.Name}_{index}_Interceptor", MethodAttributes.Private | MethodAttributes.HideBySig, overridedMethod.ReturnType, new[] { typeof(ParamInfo[]) }); SetupGenericMethodArguments(overridedMethod, method); using (var il = new GroboIL(method)) { if (overridedMethod.ReturnType != typeof(void)) { interceptorMethod = genericInterceptionAction.MakeGenericMethod(overridedMethod.ReturnType); delegateConstructor = typeof(TDelegate <>).MakeGenericType(overridedMethod.ReturnType).GetConstructor(new[] { typeof(object), typeof(IntPtr) }); } else { interceptorMethod = voidInterceptionAction; delegateConstructor = typeof(VoidDelegate).GetConstructor(new[] { typeof(object), typeof(IntPtr) }); } il.Ldarg(0); il.Ldfld(interceptorFields[interceptor]); il.Ldarg(0); if (overridedMethod.IsGenericMethodDefinition) { il.Ldftn(@delegate.MakeGenericMethod(genericParameterTypes)); } else { il.Ldftn(@delegate); } il.Newobj(delegateConstructor); il.Ldarg(1); il.Call(interceptorMethod); il.Ret(); @delegate = method; } return(@delegate); }
public static void LoadReader(GroboIL il, Type type, ReaderTypeBuilderContext context) { var counter = context.GetReader(type); if (counter.Pointer != IntPtr.Zero) { il.Ldc_IntPtr(counter.Pointer); } else { il.Ldfld(context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic)); il.Ldc_I4(counter.Index); il.Ldelem(typeof(IntPtr)); } }
public void CallWriter(GroboIL il, Type type) { var counter = Context.GetWriter(type); if (counter.Pointer != IntPtr.Zero) { il.Ldc_IntPtr(counter.Pointer); } else { il.Ldfld(Context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic)); il.Ldc_I4(counter.Index); il.Ldelem(typeof(IntPtr)); } il.Calli(CallingConventions.Standard, typeof(void), new[] { type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) }); }
private static void DefineMethodOverrideNoInterception(MethodBuilder methodBuilder, MethodInfo overridedMethod, FieldBuilder concreteInstance, ParameterInfo[] methodParams) { using (var il = new GroboIL(methodBuilder)) { il.Ldarg(0); il.Ldfld(concreteInstance); foreach (var parameter in methodParams) { il.Ldarg(parameter.Position + 1); } il.Call(overridedMethod); il.Ret(); LogIlCode(il); } }
private static Action <DebugInfoGenerator, LambdaExpression, MethodBase, GroboIL, DebugInfoExpression> BuildSequencePointMarker() { var parameterTypes = new[] { typeof(DebugInfoGenerator), typeof(LambdaExpression), typeof(MethodBase), typeof(GroboIL), typeof(DebugInfoExpression) }; var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), parameterTypes, typeof(DebugInfoExpressionEmitter), true); using (var il = new GroboIL(dynamicMethod)) { il.Ldarg(0); il.Ldarg(1); il.Ldarg(2); il.Ldarg(3); il.Ldfld(typeof(GroboIL).GetField("il", BindingFlags.NonPublic | BindingFlags.Instance)); il.Ldarg(4); var markSequencePointMethod = typeof(DebugInfoGenerator).GetMethod("MarkSequencePoint", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(LambdaExpression), typeof(MethodBase), typeof(ILGenerator), typeof(DebugInfoExpression) }, null); il.Call(markSequencePointMethod, typeof(DebugInfoGenerator)); il.Ret(); } return((Action <DebugInfoGenerator, LambdaExpression, MethodBase, GroboIL, DebugInfoExpression>)dynamicMethod.CreateDelegate(typeof(Action <DebugInfoGenerator, LambdaExpression, MethodBase, GroboIL, DebugInfoExpression>))); }
private static void BuildChildren(TypeBuilder typeBuilder, int n, Context context) { var property = typeBuilder.DefineProperty("Children", PropertyAttributes.None, typeof(IEnumerable <MethodCallNode>), Type.EmptyTypes); var getter = typeBuilder.DefineMethod("get_Children", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(IEnumerable <MethodCallNode>), Type.EmptyTypes); using (var il = new GroboIL(getter)) { il.Ldc_I4(n); // stack: [n] il.Newarr(typeof(MethodCallNode)); // stack: [new int[n] -> values] for (int i = 0; i < n; ++i) { il.Dup(); // stack: [values, values] il.Ldc_I4(i); // stack: [values, values, i] il.Ldarg(0); // stack: [values, values, i, this] il.Ldfld(context.values[i]); // stack: [values, values, i, this.values_{i}] il.Stelem(typeof(MethodCallNode)); // values[i] = this.values_{i}; stack: [values] } il.Castclass(typeof(IEnumerable <MethodCallNode>)); il.Ret(); } property.SetGetMethod(getter); typeBuilder.DefineMethodOverride(getter, typeof(MethodCallNodeEdges).GetProperty(property.Name, BindingFlags.Public | BindingFlags.Instance).GetGetMethod()); }
private static EnumParserDelegate EmitEnumParser() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(Type), typeof(string), typeof(bool) }, typeof(string), true); var il = new GroboIL(method); var enumResultType = typeof(Enum).GetNestedType("EnumResult", BindingFlags.NonPublic); var enumResult = il.DeclareLocal(enumResultType); il.Ldarg(0); il.Ldarg(1); il.Ldarg(2); il.Ldloca(enumResult); il.Call(typeof(Enum).GetMethod("TryParseEnum", BindingFlags.Static | BindingFlags.NonPublic)); var returnNullLabel = il.DefineLabel("returnNull"); il.Brfalse(returnNullLabel); il.Ldloca(enumResult); il.Ldfld(enumResultType.GetField("parsedEnum", BindingFlags.Instance | BindingFlags.NonPublic)); il.Ret(); il.MarkLabel(returnNullLabel); il.Ldnull(); il.Ret(); return((EnumParserDelegate)method.CreateDelegate(typeof(EnumParserDelegate))); }
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 v = il.DeclareLocal(typeof(Vector2)); var arr = il.DeclareLocal(typeof(byte[])); il.Ldloc(value); if (!listValue) { il.Call(prop.Getter); } il.Stloc(v); il.Ldloca(v); //il.Dup(); //il.Box(typeof(Vector2)); il.Ldfld(xField); //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 < 4; 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, 4); il.Ldloca(v); il.Ldfld(yField); 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 < 4; 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, 4); }
private void ValueLength() => Generator.Ldfld(Info.OfField <BitsValue>(nameof(BitsValue.Length)));
private static Type BuildTypeInternal(Type type) { var parentType = typeof(ValidationResultTreeNode); var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); var typeBuilder = module.DefineType(type.Name + "_" + id++, TypeAttributes.Class | TypeAttributes.Public, parentType); typesBeingBuilt[type] = typeBuilder; var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { parentType }); using (var il = new GroboIL(constructor)) { il.Ldarg(0); // stack: [this] il.Ldarg(1); // stack: [this, parent] var baseConstructor = parentType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { parentType }, null); il.Call(baseConstructor); // base(parent); stack: [] il.Ret(); } var fields = new Dictionary <string, FieldBuilder>(); foreach (var property in properties) { var propertyType = property.PropertyType; Type fieldType; if (propertyType.IsArray) { fieldType = typeof(ValidationResultTreeArrayNode <>).MakeGenericType(BuildType(propertyType.GetElementType())); } else if (propertyType.IsDictionary() || propertyType == typeof(Hashtable)) { fieldType = typeof(ValidationResultTreeUniversalNode); } else { fieldType = BuildType(propertyType, true); } var field = typeBuilder.DefineField(property.Name, fieldType, FieldAttributes.Public); fields.Add(property.Name, field); } var getChildrenMethod = parentType.GetMethod("GetChildren", BindingFlags.Instance | BindingFlags.NonPublic); var getChildrenMethodBuilder = typeBuilder.DefineMethod(getChildrenMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(IEnumerable <KeyValuePair <object, ValidationResultTreeNode> >), Type.EmptyTypes); using (var il = new GroboIL(getChildrenMethodBuilder)) { var listType = typeof(List <KeyValuePair <object, ValidationResultTreeNode> >); var addMethod = listType.GetMethod("Add", new[] { typeof(KeyValuePair <object, ValidationResultTreeNode>) }); var itemConstructor = typeof(KeyValuePair <object, ValidationResultTreeNode>).GetConstructor(new[] { typeof(object), parentType }); var list = il.DeclareLocal(listType); il.Newobj(listType.GetConstructor(Type.EmptyTypes)); // stack: [new List<>()] il.Stloc(list); // list = new List<>(); stack: [] foreach (var field in fields.Values) { il.Ldarg(0); // stack: [this] il.Ldfld(field); // stack: [this.field] var nextLabel = il.DefineLabel("next"); il.Brfalse(nextLabel); // if(this.field == null) goto next; stack: [] il.Ldloc(list); // stack: [list] il.Ldstr(field.Name); // stack: [list, field.Name] il.Ldarg(0); // stack: [list, field.Name, this] il.Ldfld(field); // stack: [list, field.Name, this.field] il.Newobj(itemConstructor); // stack: [list, new KeyValuePair<object, ValidationResultTreeNode>(field.Name, this.field)] il.Call(addMethod); // list.Add(new KeyValuePair<object, ValidationResultTreeNode>(field.Name, this.field)); stack: [] il.MarkLabel(nextLabel); } il.Ldloc(list); il.Ret(); } typeBuilder.DefineMethodOverride(getChildrenMethodBuilder, getChildrenMethod); var traverseEdgeMethod = parentType.GetMethod("TraverseEdge", BindingFlags.Instance | BindingFlags.NonPublic); var traverseEdgeMethodBuilder = typeBuilder.DefineMethod(traverseEdgeMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, parentType, new[] { typeof(Expression) }); using (var il = new GroboIL(traverseEdgeMethodBuilder)) { il.Ldarg(1); // stack: [edge] il.Castclass(typeof(MemberExpression)); // stack: [(MemberExpression)edge] il.Call(HackHelpers.GetProp <MemberExpression>(x => x.Member).GetGetMethod()); // stack: [((MemberExpresion)edge).Member] il.Call(HackHelpers.GetProp <MemberInfo>(x => x.Name).GetGetMethod()); // stack: [((MemberExpresion)edge).Member.Name] var member = il.DeclareLocal(typeof(string)); il.Stloc(member); foreach (var property in properties) { il.Ldstr(property.Name); // stack: [property.Name] il.Ldloc(member); // stack: [property.Name, member] il.Call(typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)); var nextLabel = il.DefineLabel("next"); il.Brfalse(nextLabel); // if(property.Name != member) goto next; stack: [] il.Ldarg(0); // stack: [this] il.Ldfld(fields[property.Name]); // stack: [this.field] il.Ret(); // return this.field; il.MarkLabel(nextLabel); } il.Ldnull(); il.Ret(); } typeBuilder.DefineMethodOverride(traverseEdgeMethodBuilder, traverseEdgeMethod); var result = typeBuilder.CreateTypeInfo(); typesBeingBuilt[type] = null; return(result); }
private KeyValuePair <Delegate, IntPtr> GetMemberSetter(ReaderTypeBuilderContext context, MemberInfo member) { var method = new DynamicMethod("Set_" + Type.Name + "_" + member.Name + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) }, context.Module, true); using (var il = new GroboIL(method)) { il.Ldarg(0); // stack: [data] il.Ldarg(1); // stack: [data, ref index] switch (member.MemberType) { case MemberTypes.Field: var field = (FieldInfo)member; var done = false; if (member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && field.FieldType.IsValueType) { var equalityOperator = field.FieldType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (field.FieldType.IsPrimitive || equalityOperator != null) { var fieldValue = il.DeclareLocal(field.FieldType); il.Ldarg(2); // stack: [data, ref index, ref result] if (!Type.IsValueType) { il.Ldind(Type); // stack: [data, ref index, result] } il.Ldfld(field); il.Stloc(fieldValue); il.Ldloca(fieldValue); il.Ldarg(3); // stack: [data, ref index, ref result.field, context] ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: [] var temp = il.DeclareLocal(field.FieldType); il.Ldloca(temp); il.Initobj(field.FieldType); il.Ldloc(temp); il.Ldloc(fieldValue); if (field.FieldType.IsPrimitive) { il.Ceq(); } else { il.Call(equalityOperator); } var notDefaultLabel = il.DefineLabel("notDefault"); il.Brfalse(notDefaultLabel); il.Ret(); il.MarkLabel(notDefaultLabel); il.Ldarg(2); if (!Type.IsValueType) { il.Ldind(Type); // stack: [data, ref index, result] } il.Ldloc(fieldValue); il.Stfld(field); done = true; } } if (!done) { il.Ldarg(2); // stack: [data, ref index, ref result] if (!Type.IsValueType) { il.Ldind(Type); // stack: [data, ref index, result] } il.Ldflda(field); // stack: [data, ref index, ref result.field] il.Ldarg(3); // stack: [data, ref index, ref result.field, context] ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: [] } break; case MemberTypes.Property: var property = (PropertyInfo)member; var propertyValue = il.DeclareLocal(property.PropertyType); if (context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { var getter = property.GetGetMethod(true); if (getter == null) { throw new MissingMethodException(Type.Name, property.Name + "_get"); } il.Ldarg(2); // stack: [data, ref index, ref result] if (!Type.IsValueType) { il.Ldind(Type); // stack: [data, ref index, result] } il.Call(getter, Type); // stack: [ data, ref index, result.property] il.Stloc(propertyValue); // propertyValue = result.property; stack: [data, ref index] } il.Ldloca(propertyValue); // stack: [data, ref index, ref propertyValue] il.Ldarg(3); // stack: [data, ref index, ref propertyValue, context] ReaderMethodBuilderContext.CallReader(il, property.PropertyType, context); // reader(data, ref index, ref propertyValue, context); stack: [] if (member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && property.PropertyType.IsValueType) { var equalityOperator = property.PropertyType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (property.PropertyType.IsPrimitive || equalityOperator != null) { var temp = il.DeclareLocal(property.PropertyType); il.Ldloca(temp); il.Initobj(property.PropertyType); il.Ldloc(temp); il.Ldloc(propertyValue); if (property.PropertyType.IsPrimitive) { il.Ceq(); } else { il.Call(equalityOperator); } var notDefaultLabel = il.DefineLabel("notDefault"); il.Brfalse(notDefaultLabel); il.Ret(); il.MarkLabel(notDefaultLabel); } } il.Ldarg(2); // stack: [ref result] if (!Type.IsValueType) { il.Ldind(Type); // stack: [result] } il.Ldloc(propertyValue); // stack: [result, propertyValue] var setter = property.GetSetMethod(true); if (setter == null) { throw new MissingMethodException(Type.Name, property.Name + "_set"); } il.Call(setter, Type); // result.property = propertyValue break; default: throw new NotSupportedException("Data member of type '" + member.MemberType + "' is not supported"); } il.Ret(); } var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type)); return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method))); }
public static TryGetValueDelegate <T> Build <T>(char[] keys, T[] values, int numberOfSegments, int numberOfKeysPerSegment) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(Closure <T>), typeof(char), typeof(T).MakeByRefType() }, typeof(string), true); var indices = new List <int>(); using (var il = new GroboIL(method)) { var idx = il.DeclareLocal(typeof(int), "idx"); var retFalseLabel = il.DefineLabel("retFalse"); for (int i = 0; i < numberOfSegments; ++i) { var firstKeyInSegment = keys[i * numberOfKeysPerSegment]; var lastKeyInSegment = keys[numberOfKeysPerSegment - 1 + i * numberOfKeysPerSegment]; il.Ldarg(1); // stack: [key] il.Ldc_I4(firstKeyInSegment); // stack: [key, firstKey] var nextSegmentLabel = il.DefineLabel("nextSegment"); il.Blt(nextSegmentLabel, false); // if(key < firstKey) goto nextSegment; stack: [] il.Ldarg(1); // stack: [key] il.Ldc_I4(lastKeyInSegment); // stack: [key, lastKey] il.Bgt(nextSegmentLabel, false); // if(key > lastKey) goto nextSegment; stack: [] il.Ldarg(0); // stack: [closure] il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.indices)); // stack: [closure.indices] il.Ldarg(1); // stack: [closure.indices, key] il.Ldc_I4(firstKeyInSegment - indices.Count); // stack: [closure.indices, key, diff] il.Sub(); // stack: [closure.indices, key - diff] il.Ldelem(typeof(int)); // stack: [closure.indices[key - diff]] il.Dup(); il.Stloc(idx); // idx = closure.indices[key - diff]; stack: [idx] il.Ldc_I4(0); // stack: [idx, 0] il.Blt(retFalseLabel, false); // if(idx < 0) goto retFalse; stack: [] il.Ldarg(2); // stack: [ref value] il.Ldarg(0); // stack: [ref value, closure] il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.values)); // stack: [ref value, closure.values] il.Ldloc(idx); // stack: [ref value, closure.values, idx] il.Ldelem(typeof(T)); // stack: [ref value, closure.values[idx]] il.Stind(typeof(T)); // value = closure.values[idx]; stack: [] il.Ldc_I4(1); // stack: [true] il.Ret(); il.MarkLabel(nextSegmentLabel); var segmentLength = lastKeyInSegment - firstKeyInSegment + 1; int start = indices.Count; for (int j = 0; j < segmentLength; ++j) { indices.Add(-1); } for (int j = 0; j < numberOfKeysPerSegment; ++j) { indices[start + keys[i * numberOfKeysPerSegment + j] - firstKeyInSegment] = i * numberOfKeysPerSegment + j; } } il.MarkLabel(retFalseLabel); il.Ldarg(2); // stack: [ref value] if (typeof(T).IsValueType) { il.Initobj(typeof(T)); // value = default(T); stack: [] } else { il.Ldnull(); // stack: [ref value, null] il.Stind(typeof(T)); // value = null; stack: [] } il.Ldc_I4(0); // stack: [false] il.Ret(); } var closure = new Closure <T> { indices = indices.ToArray(), values = values }; return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure)); }
private Type BuildReaderInvoker() { var argument = Type.GetGenericArguments()[0]; var typeBuilder = module.DefineType("ReaderInvoker_" + Type, TypeAttributes.Public | TypeAttributes.Class); var reader = typeBuilder.DefineField("reader", typeof(IntPtr), FieldAttributes.Private); var serializerId = typeBuilder.DefineField("serializerId", typeof(long), FieldAttributes.Private); var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(IntPtr), typeof(long) }); using (var il = new GroboIL(constructor)) { il.Ldarg(0); // stack: [this] il.Ldarg(1); // stack: [this, reader] il.Stfld(reader); // this.reader = reader; stack: [] il.Ldarg(0); // stack: [this] il.Ldarg(2); // stack: [this, serializerId] il.Stfld(serializerId); // this.serializerId = serializerId; stack: [] il.Ret(); } var method = typeBuilder.DefineMethod("Read", MethodAttributes.Public, argument, new[] { typeof(byte[]) }); using (var il = new GroboIL(method)) { var pinnedData = il.DeclareLocal(typeof(byte).MakeByRefType(), "pinnedData", true); il.Ldarg(1); // stack: [data] il.Ldc_I4(0); // stack: [data, 0] il.Ldelema(typeof(byte)); // stack: [&data[0]] il.Stloc(pinnedData); // pinnedData = &data[0]; stack: [] var index = il.DeclareLocal(typeof(int), "index"); il.Ldc_I4(0); // stack: [0] il.Stloc(index); // index = 0; stack: [] var context = il.DeclareLocal(typeof(ReaderContext), "context"); il.Ldarg(0); // stack: [this] il.Ldfld(serializerId); // stack: [this.serializerId] il.Ldarg(1); // stack: [this.serializerId, data] il.Ldlen(); // stack: [this.serializerId, data.Length] il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0] il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0, 0] il.Newobj(typeof(ReaderContext).GetConstructor(new[] { typeof(long), typeof(int), typeof(int), typeof(int) })); // stack: [new ReaderContext(this.serializerId, data.Length, 0, 0)] il.Stloc(context); // context = new ReaderContext(..); stack: [] var result = il.DeclareLocal(argument, "result"); il.Ldloc(pinnedData); // stack: [data] il.Conv <IntPtr>(); // stack: [(IntPtr)data] il.Ldloca(index); // stack: [(IntPtr)data, ref index] il.Ldloca(result); // stack: [(IntPtr)data, ref index, ref result] il.Ldloc(context); // stack: [(IntPtr)data, ref index, ref result, context] il.Ldarg(0); // stack: [(IntPtr)data, ref index, ref result, context, this] il.Ldfld(reader); // stack: [(IntPtr)data, ref index, ref result, context, this.reader] var parameterTypes = new[] { typeof(IntPtr), typeof(int).MakeByRefType(), argument.MakeByRefType(), typeof(ReaderContext) }; il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // this.reader((IntPtr)data, ref index, ref result, context); stack: [] il.FreePinnedLocal(pinnedData); // pinnedData = null; stack: [] var retLabel = il.DefineLabel("ret"); il.Ldarg(1); // stack: [data] il.Ldlen(); // stack: [data.Length] il.Ldloc(index); // stack: [data.Length, index] il.Beq(retLabel); // if(data.Length == index) goto ret; stack: [] il.Ldstr("Encountered extra data"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(retLabel); il.Ldloc(result); il.Ret(); } return(typeBuilder.CreateType()); }
public void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext) { var method = new DynamicMethod("Read_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) }, readerTypeBuilderContext.Module, true); readerTypeBuilderContext.SetReaderMethod(Type, method); using (var il = new GroboIL(method)) { var context = new ReaderMethodBuilderContext(readerTypeBuilderContext, il, !Type.IsValueType && IsReference); ReadTypeCodeAndCheck(context); // Read TypeCode and check if (!Type.IsValueType && IsReference) { // Read reference context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] var notReadLabel = il.DefineLabel("notRead"); il.Brfalse(notReadLabel); context.LoadIndex(); // stack: [external index] context.LoadContext(); // stack: [external index, context] il.Ldfld(ReaderContext.StartField); // stack: [external index, context.start] il.Sub(); // stack: [external index - context.start] il.Stloc(context.Index); // index = external index - context.start; stack: [] context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] il.Ldloc(context.Index); // stack: [context.objects, index] var obj = il.DeclareLocal(typeof(object)); il.Ldloca(obj); object dummy; il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(index, out obj)] il.Brfalse(notReadLabel); // if(!context.objects.TryGetValue(index, out obj)) goto notRead; context.LoadResultByRef(); // stack: [ref result] il.Ldloc(obj); // stack: [ref result, obj] il.Castclass(Type); // stack: [ref result, (Type)obj] il.Stind(Type); // result = (Type)obj; stack: [] context.IncreaseIndexBy1(); // Skip type code context.SkipValue(); // Skip value - it has already been read il.Ret(); il.MarkLabel(notReadLabel); il.Ldloc(context.TypeCode); // stack: [typeCode] il.Ldc_I4((int)GroBufTypeCode.Reference); // stack: [typeCode, GroBufTypeCode.Reference] var readUsualLabel = il.DefineLabel("readUsual"); il.Bne_Un(readUsualLabel); // if(typeCode != GroBufTypeCode.Reference) goto readUsual; stack: [] context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] var objectsIsNotNullLabel = il.DefineLabel("objectsIsNotNull"); il.Brtrue(objectsIsNotNullLabel); // if(context.objects != null) goto objectsIsNotNull; stack: [context.objects] il.Ldstr("Reference is not valid at this point"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(objectsIsNotNullLabel); context.IncreaseIndexBy1(); // index = index + 1; stack: [] il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); var reference = il.DeclareLocal(typeof(int)); il.Ldind(typeof(int)); // stack: [*(int*)data[index]] il.Stloc(reference); // reference = *(int*)data[index]; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] il.Ldloc(context.Index); // stack: [index] il.Ldloc(reference); // stack: [index, reference] var goodReferenceLabel = il.DefineLabel("goodReference"); il.Bgt(goodReferenceLabel, false); // if(index > reference) goto goodReference; stack: [] il.Ldstr("Bad reference"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(goodReferenceLabel); context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] il.Ldloc(reference); // stack: [context.objects, reference] il.Ldloca(obj); // stack: [context.objects, reference, ref obj] il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(reference, out obj)] var readObjectLabel = il.DefineLabel("readObject"); il.Brfalse(readObjectLabel); // if(!context.objects.TryGetValue(reference, out obj)) goto readObjects; stack: [] context.LoadResultByRef(); // stack: [ref result] il.Ldloc(obj); // stack: [ref result, obj] il.Castclass(Type); // stack: [ref result, (Type)obj] il.Stind(Type); // result = (Type)obj; stack: [] il.Ret(); il.MarkLabel(readObjectLabel); // Referenced object has not been read - this means that the object reference belongs to is a property that had been deleted context.LoadData(); // stack: [data] il.Ldloc(reference); // stack: [data, reference] context.LoadContext(); // stack: [data, reference, context] il.Ldfld(ReaderContext.StartField); // stack: [data, reference, context.start] il.Add(); // stack: [data, reference + context.start] il.Stloc(reference); // reference += context.start; stack: [data] il.Ldloca(reference); // stack: [data, ref reference] context.LoadResultByRef(); // stack: [data, ref reference, ref result] context.LoadContext(); // stack: [data, ref reference, ref result, context] context.CallReader(Type); il.Ret(); il.MarkLabel(readUsualLabel); } ReadNotEmpty(context); // Read obj il.Ret(); } var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type)); var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); readerTypeBuilderContext.SetReaderPointer(Type, pointer, @delegate); }
private static MethodBuilder GenerateOverloadedMethodDelegate(MethodInfo methodToIntercept, TypeBuilder typeBuilder, FieldInfo concrete) { // Define the method var method = typeBuilder.DefineMethod(methodToIntercept.Name + "-Delegate", MethodAttributes.Private | MethodAttributes.HideBySig, methodToIntercept.ReturnType, new[] { typeof(ParamInfo[]) }); SetupGenericMethodArguments(methodToIntercept, method); // Local for each out/ref parameter var parameters = methodToIntercept.GetParameters(); var locals = new Dictionary <string, Local>(); using (var il = new GroboIL(method)) { foreach (ParameterInfo parameter in parameters) { if (parameter.IsOut || parameter.ParameterType.IsByRef) { locals.Add(parameter.Name, il.DeclareLocal(parameter.ParameterType.GetElementType(), parameter.Name)); } } var paramInfoType = typeof(ParamInfo); var paramInfoGetValue = paramInfoType.GetProperty("Value").GetGetMethod(); // Initialize out parameters to default values for (var i = 0; i < parameters.Length; i++) { if (parameters[i].ParameterType.IsByRef && !parameters[i].IsOut) { il.Ldarg(1); il.Ldc_I4(i); il.Ldelem(paramInfoType); il.Call(paramInfoGetValue); if (parameters[i].ParameterType.GetElementType().IsValueType) { il.Unbox_Any(parameters[i].ParameterType.GetElementType()); } else { il.Castclass(parameters[i].ParameterType.GetElementType()); } il.Stloc(locals[parameters[i].Name]); } } // Load target il.Ldarg(0); il.Ldfld(concrete); // Push call values onto stack for (var i = 0; i < parameters.Length; i++) { if (parameters[i].IsOut || parameters[i].ParameterType.IsByRef) { il.Ldloca(locals[parameters[i].Name]); } else { il.Ldarg(1); il.Ldc_I4(i); il.Ldelem(paramInfoType); il.Call(paramInfoGetValue); if (parameters[i].ParameterType.IsValueType || parameters[i].ParameterType.IsGenericParameter) { il.Unbox_Any(parameters[i].ParameterType); } else { il.Castclass(parameters[i].ParameterType); } } } // Call intercepted method il.Call(methodToIntercept); var paramInfoSetValue = paramInfoType.GetProperty("Value").GetSetMethod(); // Copy out/ref parameter values back into passed-in parameters array for (var i = 0; i < parameters.Length; i++) { if (parameters[i].IsOut || parameters[i].ParameterType.IsByRef) { il.Ldarg(1); il.Ldc_I4(i); il.Ldelem(paramInfoType); il.Ldloc(locals[parameters[i].Name]); if (parameters[i].ParameterType.GetElementType().IsValueType) { il.Box(parameters[i].ParameterType.GetElementType()); } il.Call(paramInfoSetValue); } } il.Ret(); LogIlCode(il); } return(method); }
public void BuildWriter(WriterTypeBuilderContext writerTypeBuilderContext) { var method = new DynamicMethod("Write_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] { Type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) }, writerTypeBuilderContext.Module, true); writerTypeBuilderContext.SetWriterMethod(Type, method); using (var il = new GroboIL(method)) { var context = new WriterMethodBuilderContext(writerTypeBuilderContext, il); var notEmptyLabel = il.DefineLabel("notEmpty"); if (CheckEmpty(context, notEmptyLabel)) // Check if obj is empty { context.WriteNull(); // Write null & return } il.MarkLabel(notEmptyLabel); // Now we know that obj is not empty if (!Type.IsValueType && IsReference && writerTypeBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences)) { // Pack reference var index = il.DeclareLocal(typeof(int)); context.LoadIndex(); // stack: [external index] context.LoadContext(); // stack: [external index, context] il.Ldfld(WriterContext.StartField); // stack: [external index, context.start] il.Sub(); // stack: [external index - context.start] il.Stloc(index); // index = external index - context.start; stack: [] context.LoadContext(); // stack: [context] il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] context.LoadObj(); // stack: [context.objects, obj] var reference = il.DeclareLocal(typeof(int)); il.Ldloca(reference); // stack: [context.objects, obj, ref reference] int dummy; il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.TryGetValue(null, out dummy))); // stack: [context.object.TryGetValue(obj, out reference)] var storeLocationLabel = il.DefineLabel("storeLocation"); il.Brfalse(storeLocationLabel); // Current object is in dict il.Ldloc(index); il.Ldloc(reference); // stack: [index, reference] var skipSelfLabel = il.DefineLabel("skipSelf"); il.Beq(skipSelfLabel); // if(index == reference) goto skipSelf; stack: [] il.Ldloc(index); // stack: [index] il.Ldloc(reference); // stack: [index, reference] var badReferenceLabel = il.DefineLabel("badReference"); il.Blt(badReferenceLabel, false); // if(index < reference) goto badReference; stack: [] context.WriteTypeCode(GroBufTypeCode.Reference); // result[index++] = GroBufTypeCode.Reference context.GoToCurrentLocation(); // stack: [&result[index]] il.Ldloc(reference); // stack: [&result[index], reference] il.Stind(typeof(int)); // *(int *)&result[index] = reference context.IncreaseIndexBy4(); // index += 4 il.Ret(); il.MarkLabel(badReferenceLabel); il.Ldstr("Bad reference"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(storeLocationLabel); context.LoadContext(); // stack: [context] il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] context.LoadObj(); // stack: [context.objects, obj] il.Ldloc(index); // stack: [context.objects, obj, index] il.Call(HackHelpers.GetMethodDefinition <Dictionary <object, int> >(dict => dict.Add(null, 0))); // context.objects.Add(obj, index); il.MarkLabel(skipSelfLabel); } WriteNotEmpty(context); // Write obj il.Ret(); } var @delegate = method.CreateDelegate(typeof(WriterDelegate <>).MakeGenericType(Type)); var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); writerTypeBuilderContext.SetWriterPointer(Type, pointer, @delegate); }
private static Action <Hashtable, Array, int> EmitCopyValues() { /* * private void CopyValues(Hashtable hashtable, Array array, int arrayLength) * { * bucket[] buckets = hashtable.buckets; * int length = buckets.Length; * int arrayIndex = 0; * while (--length >= 0) * { * object key = buckets[length].key; * if ((key != null) && (key != hashtable.buckets)) * { * if (arrayIndex >= arrayLength) * return; * array.SetValue(buckets[length].val, arrayIndex++); * } * } * } */ var dynamicMethod = new DynamicMethod( Guid.NewGuid().ToString(), typeof(void), new[] { typeof(Hashtable), typeof(Array), typeof(int) }, typeof(Hashtable), true); var bucketsFieldInfo = typeof(Hashtable).GetField("buckets", BindingFlags.Instance | BindingFlags.NonPublic); var bucketType = typeof(Hashtable).GetNestedType("bucket", BindingFlags.NonPublic); var bucketArrayType = bucketType.MakeArrayType(); var keyFieldInfo = bucketType.GetField("key", BindingFlags.Instance | BindingFlags.Public); var valFieldInfo = bucketType.GetField("val", BindingFlags.Instance | BindingFlags.Public); var setValueMethodInfo = typeof(Array).GetMethod("SetValue", new[] { typeof(object), typeof(int) }); using (var il = new GroboIL(dynamicMethod)) { var buckets = il.DeclareLocal(bucketArrayType, "buckets"); var length = il.DeclareLocal(typeof(int), "length"); var arrayIndex = il.DeclareLocal(typeof(int), "arrayIndex"); var key = il.DeclareLocal(typeof(object), "key"); var cycleStartLabel = il.DefineLabel("cycleStart"); var cycleNextLabel = il.DefineLabel("cycleNext"); var endLabel = il.DefineLabel("end"); il.EmitSetIntToZero(arrayIndex); il.Ldarg(0); // stack: hashtable il.Ldfld(bucketsFieldInfo); // stack: hashtable::buckets il.Stloc(buckets); il.Ldloc(buckets); // stack: hashtable::buckets il.Ldlen(); // stack: buckets.length il.Conv <int>(); // stack: buckets.length (i4) il.Stloc(length); il.Br(cycleNextLabel); // jump(cycleNext) il.MarkLabel(cycleStartLabel); il.EmitLoadArrayItemRef(buckets, length, bucketType); // stack: *bucket[current] il.Ldfld(keyFieldInfo); // stack: key il.Stloc(key); // 2: key il.Ldloc(key); // stack: key il.Brfalse(cycleNextLabel); // jump(cycleNext) if key == null il.Ldloc(key); // stack: key il.Ldarg(0); // stack+: hashtable il.Ldfld(bucketsFieldInfo); // stack: key, hashtable::buckets il.Beq(cycleNextLabel); // jump(cycleNext) if key == hashtable::buckets (какой-то хитрый хак hashtable-а) il.Ldloc(arrayIndex); // stack: arrayIndex il.Ldarg(2); // stack+: arrayLength il.Bge(endLabel, false); // jump(end) if arrayIndex >= arrayLength il.Ldarg(1); // stack: array (arg1) il.EmitLoadArrayItemRef(buckets, length, bucketType); // stack: array (arg1), *bucket[current] il.Ldfld(valFieldInfo); // stack: array (arg1), bucket[current].val il.EmitXPlusPlus(arrayIndex); // stack: array (arg1), bucket[current].val, arrayIndex++ il.Call(setValueMethodInfo); // array.SetValue(bucket[current].val, old_arrayIndex); il.MarkLabel(cycleNextLabel); il.EmitMinusMinusX(length); // stack: --current il.Ldc_I4(0); // stack+: 0 il.Bge(cycleStartLabel, false); // jump(cycleStart) if --current >= 0 il.MarkLabel(endLabel); il.Ret(); } return((Action <Hashtable, Array, int>)dynamicMethod.CreateDelegate(typeof(Action <Hashtable, Array, int>))); }
private IQxx BuildSwitch(ModuleBuilder module, string[] keys) { var numberOfCases = keys.Length; var typeBuilder = module.DefineType("Switch" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public); typeBuilder.AddInterfaceImplementation(typeof(IQxx)); var fields = new FieldInfo[numberOfCases]; for (var i = 0; i < numberOfCases; ++i) { fields[i] = typeBuilder.DefineField(keys[i], typeof(int), FieldAttributes.Public); } var tinyHashtable = Create(keys); var n = tinyHashtable.Length; var keysField = typeBuilder.DefineField("keys", typeof(string[]), FieldAttributes.Public); var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(string[]) }); using (var il = new GroboIL(constructor)) { il.Ldarg(0); il.Ldarg(1); il.Stfld(keysField); il.Ret(); } var method = typeBuilder.DefineMethod("Set", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[] { typeof(string), typeof(int) }); method.DefineParameter(1, ParameterAttributes.In, "key"); method.DefineParameter(2, ParameterAttributes.In, "value"); using (var il = new GroboIL(method)) { il.Ldarg(0); il.Ldfld(keysField); il.Ldarg(1); il.Call(HackHelpers.GetMethodDefinition <object>(o => o.GetHashCode())); il.Ldc_I4(n); il.Rem(true); var idx = il.DeclareLocal(typeof(int)); il.Dup(); il.Stloc(idx); il.Ldelem(typeof(string)); il.Ldarg(1); il.Call(stringEqualityOperator); var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); var labels = new GroboIL.Label[n]; for (var i = 0; i < n; ++i) { labels[i] = doneLabel; } foreach (var key in keys) { var index = key.GetHashCode() % n; if (index < 0) { index += n; } var label = il.DefineLabel("set_" + key); labels[index] = label; } il.Ldloc(idx); il.Switch(labels); for (var i = 0; i < keys.Length; ++i) { var index = keys[i].GetHashCode() % n; if (index < 0) { index += n; } il.MarkLabel(labels[index]); il.Ldarg(0); il.Ldarg(2); il.Stfld(fields[i]); il.Br(doneLabel); } il.MarkLabel(doneLabel); il.Ret(); } typeBuilder.DefineMethodOverride(method, typeof(IQxx).GetMethod("Set")); var type = typeBuilder.CreateType(); return((IQxx)Activator.CreateInstance(type, new object[] { tinyHashtable })); }