private static TryParseDelegate EmitTryParseDelegate() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(string), typeof(DateTimeTypeCode), typeof(object).MakeByRefType() }, typeof(string), true); var xsdDateTimeType = typeof(XmlReader).Assembly.GetTypes().FirstOrDefault(type => type.Name == "XsdDateTime"); if (xsdDateTimeType == null) { throw new InvalidOperationException("The type 'XsdDateTime' is not found"); } var tryParseMethod = xsdDateTimeType.GetMethod("TryParse", BindingFlags.Static | BindingFlags.NonPublic); if (tryParseMethod == null) { throw new InvalidOperationException("The method 'XsdDateTime.TryParse' is not found"); } using (var il = new GroboIL(method)) { il.Ldarg(0); // stack: [value] il.Ldarg(1); // stack: [value, typeCode] var strongBoxType = typeof(StrongBox <>).MakeGenericType(xsdDateTimeType); var strongBox = il.DeclareLocal(strongBoxType); il.Ldarg(2); // stack: [value, typeCode, ref result] il.Newobj(strongBoxType.GetConstructor(Type.EmptyTypes)); // stack: [value, typeCode, ref result, new StrongBox<XsdDateTime>()] il.Dup(); il.Stloc(strongBox); // strongBox = new StrongBox<XsdDateTime>(); stack: [value, typeCode, ref result, strongBox] il.Stind(typeof(object)); // result = strongBox; stack: [value, typeCode] il.Ldloc(strongBox); // stack: [value, typeCode, strongBox] il.Ldflda(strongBoxType.GetField("Value", BindingFlags.Instance | BindingFlags.Public)); // stack: [value, typeCode, ref strongBox.Value] il.Call(tryParseMethod); // stack: [XsdDateTime.TryParse(value, typeCode, ref strongBox.Value] il.Ret(); } return((TryParseDelegate)method.CreateDelegate(typeof(TryParseDelegate))); }
private Func <object> BuildConstants(Type type, ClosureSubstituter closureSubstituter) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object[]) }, typeof(ExpressionClosureBuilder), true); var root = Expression.Parameter(type); var consts = new object[hashtable.Count]; using (var il = new GroboIL(method)) { il.Newobj(type.GetConstructor(Type.EmptyTypes)); // stack: [new Constants()] var result = il.DeclareLocal(type, "result"); il.Stloc(result); // result = new Constants(); stack: [] int index = 0; foreach (DictionaryEntry entry in hashtable) { var pair = (Tuple <Type, object>)entry.Key; var constType = pair.Item1; consts[index] = pair.Item2 is Expression?closureSubstituter.Visit((Expression)pair.Item2) : pair.Item2; var fieldAccessor = constantsBuilder.MakeAccess(root, ((int?)entry.Value).Value); var pathToField = new List <FieldInfo>(); while (fieldAccessor.NodeType != ExpressionType.Parameter) { var memberExpression = (MemberExpression)fieldAccessor; pathToField.Add((FieldInfo)memberExpression.Member); fieldAccessor = memberExpression.Expression; } pathToField.Reverse(); il.Ldloc(result); for (int i = 0; i < pathToField.Count - 1; ++i) { il.Ldflda(pathToField[i]); // stack: [ref result.field] il.Dup(); // stack: [ref result.field, ref result.field] var fieldType = pathToField[i].FieldType; il.Ldind(fieldType); // stack: [ref result.field, result.field] var notNullLabel = il.DefineLabel("notNull"); il.Brtrue(notNullLabel); // if(result.field != null) goto notNull; stack: [ref result.field] il.Dup(); // stack: [ref result.field, ref result.field] il.Newobj(fieldType.GetConstructor(Type.EmptyTypes)); // stack: [ref result.field, ref result.field, new field()] il.Stind(fieldType); // result.field = new field(); stack: [ref result.field] il.MarkLabel(notNullLabel); il.Ldind(fieldType); // stack: [result.field] } il.Ldarg(0); // stack: [path, args] il.Ldc_I4(index++); // stack: [path, args, index] il.Ldelem(typeof(object)); // stack: [path, args[index]] var field = pathToField.Last(); if (!constType.IsValueType) { il.Castclass(field.FieldType); // stack: [path, (FieldType)args[index]] } else { il.Unbox_Any(constType); if (field.FieldType != constType) { var constructor = field.FieldType.GetConstructor(new[] { constType }); if (constructor == null) { throw new InvalidOperationException(string.Format("Missing constructor of type '{0}' with parameter of type '{1}'", Formatter.Format(field.FieldType), Formatter.Format(constType))); } il.Newobj(constructor); } } il.Stfld(field); // path.field = (FieldType)args[index]; stack: [] } il.Ldloc(result); il.Ret(); } var func = (Func <object[], object>)method.CreateDelegate(typeof(Func <object[], object>)); return(() => func(consts)); }
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))); }