void CreateCompareMethod(List <PropertySerializationInfo> properties) { const string endFalseLabel = "compareFailedLabel"; DynamicMethodHelper il = new DynamicMethodHelper( "Compare_" + type.Name, typeof(bool), new Type[] { typeof(object), typeof(object) }, this.type ); // Create calls to compare each member foreach (PropertySerializationInfo propInfo in properties) { il.BeginScope(); propInfo.GenerateCompareIL(il, 0, 1); il.EndScope(); il.GotoIfFalse(endFalseLabel); } // Return true if all properties passed (didn't goto endFalseLabel) il.PushInt(Convert.ToInt32(true)); il.Return(); // Return false if any properties failed (did goto endFalseLabel) il.MarkLabel(endFalseLabel); il.PushInt(Convert.ToInt32(false)); il.Return(); this.compareMethod = (CompareMethod)il.Compile(typeof(CompareMethod)); }
/// <summary> /// Generates IL to read a single item from the stream and leaves the result on the stack. /// </summary> /// <param name="type">The <see cref="Type"/> of item to read.</param> /// <param name="args">The arguments for generating the il.</param> void GenerateReadTypeIL(Type type, GenerateArgs args) { MethodInfo method = GetTypeMethod(type, TypeMethodType.Deserialize); DynamicMethodHelper il = args.il; bool dynamic = IsDynamic && (type.IsValueType == false); // Variable names const string valueVar = "_readValue"; const string dynamicTypeIndexVar = "_typeIndex"; const string dynamicTypeVar = "_dynamicType"; const string dynamicTypeNameVar = "_dynamicTypeName"; const string dynamicTypeResolvedLabel = "_dynamicTypeResolved"; const string dynamicTypeNotNullLabel = "_dynamicTypeNotNull"; const string dynamicTypeDoneLabel = "_dynamicTypeDone"; il.BeginScope(); { if (dynamic) { il.DeclareLocal(dynamicTypeIndexVar, typeof(byte)); il.DeclareLocal(valueVar, typeof(object)); il.DeclareLocal(dynamicTypeNameVar, typeof(string)); il.DeclareLocal(dynamicTypeVar, typeof(Type)); // Read type index il.PushLocal(args.streamVar); il.CallMethod(GetTypeMethod(typeof(byte), TypeMethodType.Deserialize)); il.PopLocal(dynamicTypeIndexVar); // if (typeIndex == -1) goto :dynamicInstanceNull il.PushLocal(dynamicTypeIndexVar); il.PushInt(SerializerHeaders.NullVersion); il.GotoIfNotEqual(dynamicTypeNotNullLabel); // return null // goto :dynamicTypeDone il.PushNull(); il.Goto(dynamicTypeDoneLabel); // :dynamicTypeNotNull il.MarkLabel(dynamicTypeNotNullLabel); // Get type info for typeIndex il.PushLocal(args.nameTableVar); il.PushLocal(dynamicTypeIndexVar); il.PushLocalAsRef(dynamicTypeVar); il.PushLocalAsRef(dynamicTypeNameVar); il.CallMethod(typeof(TypeNameTable).GetMethod("GetTypeInfo")); // If (type != null) goto :typeResolved il.PushLocal(dynamicTypeVar); il.GotoIfTrue(dynamicTypeResolvedLabel); // Call Type.GetType to resolve type. We must do this // in the context of the type being deserialized to // get the appropriate visibility permissions il.PushLocal(dynamicTypeNameVar); il.PushBool(true); il.CallMethod(typeof(Type).GetMethod( "GetType", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(string), typeof(bool) }, null )); il.PopLocal(dynamicTypeVar); // Save the resolved type back to the type table so // subsequent instances of the same type don't have to // do it again il.PushLocal(args.nameTableVar); il.PushLocal(dynamicTypeIndexVar); il.PushLocal(dynamicTypeVar); il.CallMethod(typeof(TypeNameTable).GetMethod("SetResolvedType")); // :typeResolved il.MarkLabel(dynamicTypeResolvedLabel); // Create an empty instance of the resolved type il.PushLocal(dynamicTypeVar); il.PushBool(true); il.CallMethod(typeof(Activator).GetMethod( "CreateInstance", new [] { typeof(Type), typeof(bool) } )); il.PopLocal(valueVar); // Call the serializer to read it il.PushLocalAsRef(valueVar); il.PushArg(args.dataArg); il.CallMethod(method); il.Pop(); // return (baseType)dynamicInstance il.PushLocal(valueVar); il.Cast(type); // :dynamicTypeDone il.MarkLabel(dynamicTypeDoneLabel); } else if (method.DeclaringType == typeof(IPrimitiveReader)) { // return reader.ReadXXXX() il.PushLocal(args.streamVar); il.CallMethod(method); } else //if (type.IsClass) { // Create empty instance of type il.DeclareLocal(valueVar, typeof(object)); if (type.IsClass) { il.NewObject(valueVar, type, Type.EmptyTypes); } // Call the serializer to read it il.PushLocalAsRef(valueVar); il.PushArg(args.dataArg); il.CallMethod(method); il.Pop(); // Ignore return value // return (type)instance il.PushLocal(valueVar); if (type.IsClass) { il.Cast(type); } else { il.UnboxValueType(type); } } } il.EndScope(); }
/// <summary> /// Generates IL to write a single value from the stack to the stream /// </summary> /// <param name="type">Type of the object on the stack</param> /// <param name="args">The generate args.</param> void GenerateWriteTypeIL(Type type, GenerateArgs args) { MethodInfo method = GetTypeMethod(type, TypeMethodType.Serialize); const string valueVar = "writeValue"; const string valueDoneLabel = "_writeValueDone"; DynamicMethodHelper il = args.il; bool dynamic = IsDynamic && (type.IsValueType == false); il.BeginScope(); { il.DeclareLocal(valueVar, type); il.PopLocalFromObject(valueVar); if (dynamic) { const string notNullLabel = "_dynamicNotNull"; // If value is a reference type then serialize // NullVersion (-1) and do nothing else. No need to // save a type name or anything. If not null then // add type to name table and write the type byte // before calling serializer to write the instance il.PushLocal(valueVar); il.GotoIfTrue(notNullLabel); il.PushLocal(args.streamVar); il.PushInt(-1); il.CallMethod(GetTypeMethod(typeof(byte), TypeMethodType.Serialize)); il.Goto(valueDoneLabel); il.MarkLabel(notNullLabel); // push writer for Write(byte) call il.PushLocal(args.streamVar); // push nameTable for Add(Type) call il.DebugWriteNamedLocal(args.nameTableVar); il.PushLocal(args.nameTableVar); // push (object)value // call object.GetType() il.PushLocal(valueVar); il.Cast(typeof(object)); il.CallMethod(typeof(object).GetMethod("GetType")); // push this.Version il.PushInt(this.Version); // call TypeNameTable.Add(Type, version) il.CallMethod(typeof(TypeNameTable).GetMethod("Add", new [] { typeof(Type), typeof(int) })); // Return type byte // call IPrimitiveWriter.Write(byte) il.CallMethod(GetTypeMethod(typeof(byte), TypeMethodType.Serialize)); } if (method.DeclaringType == typeof(IPrimitiveWriter)) { // push IPrimitiveWriter ; arg 1 for method call // push elemValue ; arg 2 for method call il.PushLocal(args.streamVar); il.PushLocal(valueVar); } else { // push value // push TypeSerializationArgs il.PushLocal(valueVar); il.PushArg(args.dataArg); } il.CallMethod(method); if (dynamic) { il.MarkLabel(valueDoneLabel); } } il.EndScope(); }
static void GenerateCompareTypeIL(DynamicMethodHelper il, Type t) { MethodInfo method = GetTypeMethod(t, TypeMethodType.Compare); if ((method == null) && (t.IsPrimitive == false)) { il.Pop(); il.Pop(); il.PushInt(1); return; } il.BeginScope(); { const string valX = "x"; const string valY = "y"; const string valThis = "_thisX"; const string trueLabel = "endTrue"; const string falseLabel = "endFalse"; const string endLabel = "endCheck"; il.DeclareLocal(valX, typeof(object)); il.PopLocal(valX); il.DeclareLocal(valY, typeof(object)); il.PopLocal(valY); // If both null or the same object then return true il.PushLocal(valX); il.PushLocal(valY); il.GotoIfEqual(trueLabel); // Exit false if either value is null il.PushLocal(valX); il.GotoIfFalse(falseLabel); il.PushLocal(valY); il.GotoIfFalse(falseLabel); // Both operands are non-null so call the type-specific comparison method if (t.IsPrimitive) { il.PushLocal(valX); il.UnboxValueType(t); il.PushLocal(valX); il.UnboxValueType(t); il.CompareEqual(); } else { Type paramType = method.GetParameters()[0].ParameterType; il.DebugWriteLine("Calling " + method); if (method.IsStatic) { il.PushLocal(valX); if (paramType.IsValueType) il.UnboxValueType(paramType); } else { il.DeclareLocal(valThis, t); il.PushLocal(valX); il.PopLocalFromObject(valThis); il.PushThis(valThis, method); } il.PushLocal(valY); if (paramType.IsValueType) il.UnboxValueType(paramType); il.CallMethod(method); } il.GotoIfFalse(falseLabel); il.MarkLabel(trueLabel); il.PushInt(1); il.Goto(endLabel); il.MarkLabel(falseLabel); il.DebugWriteLine("The following values are not equal:"); il.DebugWriteLocal(valX); il.DebugWriteLocal(valY); il.PushInt(0); il.MarkLabel(endLabel); } il.EndScope(); }