private static void GenerateWriteValue(WriterGenerationContext context, Variable valueLocal, Type formalType) { ObjectWriter.CheckLegality(formalType); if (formalType.IsEnum) { formalType = Enum.GetUnderlyingType(formalType); } var writeMethod = typeof(PrimitiveWriter).GetMethod("Write", new[] { formalType }); // if this method is null, then it is a non-primitive (i.e. custom) struct if (writeMethod != null) { context.PushPrimitiveWriterOntoStack(); context.Generator.PushVariableOntoStack(valueLocal); context.Generator.Emit(OpCodes.Call, writeMethod); return; } var nullableUnderlyingType = Nullable.GetUnderlyingType(formalType); if (nullableUnderlyingType != null) { var hasValueLabel = context.Generator.DefineLabel(); var finishLabel = context.Generator.DefineLabel(); var underlyingValueLocal = context.Generator.DeclareLocal(nullableUnderlyingType); var underlyingVariable = new Variable(underlyingValueLocal); context.PushPrimitiveWriterOntoStack(); context.Generator.PushVariableAddressOntoStack(valueLocal); context.Generator.Emit(OpCodes.Call, formalType.GetProperty("HasValue").GetGetMethod()); context.Generator.Emit(OpCodes.Brtrue_S, hasValueLabel); context.Generator.PushIntegerOntoStack(0); context.Generator.Call <PrimitiveWriter>(x => x.Write(false)); context.Generator.Emit(OpCodes.Br_S, finishLabel); context.Generator.MarkLabel(hasValueLabel); context.Generator.PushIntegerOntoStack(1); context.Generator.Call <PrimitiveWriter>(x => x.Write(false)); context.Generator.PushVariableAddressOntoStack(valueLocal); context.Generator.Emit(OpCodes.Call, formalType.GetProperty("Value").GetGetMethod()); context.Generator.StoreLocalValueFromStack(underlyingValueLocal); GenerateWriteValue(context, underlyingVariable, nullableUnderlyingType); context.Generator.MarkLabel(finishLabel); return; } GenerateWriteFields(context, valueLocal, formalType); }
internal static bool GenerateTryWriteObjectInline(WriterGenerationContext context, bool generatePreSerializationCallback, bool generatePostSerializationCallback, Variable valueLocal, Type actualType) { if (actualType.IsArray) { var rank = actualType.GetArrayRank(); // write rank context.PushPrimitiveWriterOntoStack(); context.Generator.PushIntegerOntoStack(rank); context.Generator.Call <PrimitiveWriter>(x => x.Write(0)); if (rank == 1) { // write length context.PushPrimitiveWriterOntoStack(); context.Generator.PushVariableOntoStack(valueLocal); context.Generator.Emit(OpCodes.Castclass, actualType); context.Generator.Emit(OpCodes.Ldlen); context.Generator.Call <PrimitiveWriter>(x => x.Write(0)); } else { // write lengths in loop for (var i = 0; i < rank; i++) { context.PushPrimitiveWriterOntoStack(); context.Generator.PushVariableOntoStack(valueLocal); context.Generator.PushIntegerOntoStack(i); context.Generator.Call <Array>(x => x.GetLength(0)); context.Generator.Call <PrimitiveWriter>(x => x.Write(0)); } } return(false); } if (actualType == typeof(string)) { GenerateInvokeCallbacksAndExecute(context, generatePreSerializationCallback, generatePostSerializationCallback, valueLocal, actualType, c => { c.PushPrimitiveWriterOntoStack(); c.Generator.PushVariableOntoStack(valueLocal); c.Generator.Call <PrimitiveWriter>(x => x.Write((string)null)); }); return(true); } return(GenerateSpecialWrite(context, actualType, valueLocal, false)); }
protected override bool InnerGenerate(WriterGenerationContext context) { Variable value; if (type.IsValueType) { var valueLocal = context.Generator.DeclareLocal(type); context.Generator.Emit(OpCodes.Ldarg_1); context.Generator.Emit(OpCodes.Unbox_Any, type); context.Generator.StoreLocalValueFromStack(valueLocal); value = new Variable(valueLocal); } else { value = new Variable(1); } var objectForSurrogatesIndex = objectsForSurrogates == null ? -1 : objectsForSurrogates.FindMatchingIndex(type); context.PushPrimitiveWriterOntoStack(); context.Generator.PushIntegerOntoStack(objectForSurrogatesIndex != -1 ? 1 : 0); context.Generator.Call <PrimitiveWriter>(x => x.Write(false)); if (objectForSurrogatesIndex != -1) { context.PushObjectWriterOntoStack(); context.Generator.Emit(OpCodes.Dup); context.Generator.PushFieldValueOntoStack <ObjectWriter, SwapList>(x => x.objectsForSurrogates); context.Generator.PushIntegerOntoStack(objectForSurrogatesIndex); context.Generator.Call <SwapList>(x => x.GetByIndex(0)); var delegateType = typeof(Func <,>).MakeGenericType(type, typeof(object)); context.Generator.Emit(OpCodes.Castclass, delegateType); context.Generator.Emit(OpCodes.Ldarg_1); context.Generator.Emit(OpCodes.Call, delegateType.GetMethod("Invoke")); // here should be a primitive writer on a stack context.Generator.Call <object>(x => x.GetType()); context.Generator.Call <ObjectWriter>(x => x.TouchAndWriteTypeId(typeof(void))); context.Generator.Emit(OpCodes.Pop); } if (WriteMethodGenerator.GenerateTryWriteObjectInline(context, generatePreSerializationCallback, generatePostSerializationCallback, value, type)) { context.PushObjectWriterOntoStack(); context.Generator.PushFieldValueOntoStack <ObjectWriter, HashSet <int> >(x => x.objectsWrittenInline); context.Generator.Emit(OpCodes.Ldarg_2); // reference identifier context.Generator.Call <HashSet <int> >(x => x.Add(0)); context.Generator.Emit(OpCodes.Pop); } return(true); }
private static void GenerateWriteDelegate(WriterGenerationContext context, Variable valueLocal) { var array = context.Generator.DeclareLocal(typeof(Delegate[])); var loopLength = context.Generator.DeclareLocal(typeof(int)); var element = context.Generator.DeclareLocal(typeof(Delegate)); var delegateTargetLocal = context.Generator.DeclareLocal(typeof(object)); var delegateTargetVariable = new Variable(delegateTargetLocal); context.PushPrimitiveWriterOntoStack(); context.PushObjectWriterOntoStack(); context.Generator.PushVariableOntoStack(valueLocal); context.Generator.Call <ObjectWriter>(x => x.GetDelegatesWithNonTransientTargets(null)); context.Generator.Emit(OpCodes.Castclass, typeof(Delegate[])); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(array); // array refrence should be on the top of stack here context.Generator.Emit(OpCodes.Ldlen); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(loopLength); // primitive writer should be on the stack // array length should be on the stack context.Generator.Call <PrimitiveWriter>(x => x.Write(0)); GeneratorHelper.GenerateLoop(context, loopLength, c => { context.Generator.PushLocalValueOntoStack(array); context.Generator.PushLocalValueOntoStack(c); context.Generator.Emit(OpCodes.Ldelem, element.LocalType); context.Generator.Emit(OpCodes.Dup); context.Generator.StoreLocalValueFromStack(element); // element reference should be on the stack context.Generator.PushPropertyValueOntoStack <MulticastDelegate, object>(x => x.Target); context.Generator.StoreLocalValueFromStack(delegateTargetLocal); GenerateWriteDeferredReference(context, delegateTargetVariable, typeof(object)); context.PushObjectWriterOntoStack(); context.Generator.PushPropertyValueOntoStack <ObjectWriter, IdentifiedElementsDictionary <MethodDescriptor> >(x => x.Methods); context.Generator.PushLocalValueOntoStack(element); context.Generator.PushPropertyValueOntoStack <MulticastDelegate, MethodInfo>(x => x.Method); context.Generator.Emit(OpCodes.Newobj, Helpers.GetConstructorInfo <MethodDescriptor>(typeof(MethodInfo))); context.Generator.Call <IdentifiedElementsDictionary <MethodDescriptor> >(x => x.TouchAndWriteId(null)); context.Generator.Emit(OpCodes.Pop); }); }
private static void GenerateWriteEnumerable(WriterGenerationContext context, Variable valueLocal, CollectionMetaToken token) { var genericTypes = new[] { token.FormalElementType }; var enumerableType = token.IsGeneric ? typeof(IEnumerable <>).MakeGenericType(genericTypes) : typeof(IEnumerable); var enumeratorType = token.IsGeneric ? typeof(IEnumerator <>).MakeGenericType(genericTypes) : typeof(IEnumerator); var iteratorLocal = context.Generator.DeclareLocal(enumeratorType); var currentElementLocal = context.Generator.DeclareLocal(token.FormalElementType); var elementVariable = new Variable(currentElementLocal); var loopBegin = context.Generator.DefineLabel(); var finish = context.Generator.DefineLabel(); context.PushPrimitiveWriterOntoStack(); context.Generator.PushVariableOntoStack(valueLocal); context.Generator.Emit(token.CountMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, token.CountMethod); context.Generator.Call <PrimitiveWriter>(x => x.Write(0)); var getEnumeratorMethod = enumerableType.GetMethod("GetEnumerator"); context.Generator.PushVariableOntoStack(valueLocal); context.Generator.Emit(OpCodes.Callvirt, getEnumeratorMethod); context.Generator.StoreLocalValueFromStack(iteratorLocal); context.Generator.MarkLabel(loopBegin); context.Generator.PushLocalValueOntoStack(iteratorLocal); context.Generator.Callvirt <IEnumerator>(x => x.MoveNext()); context.Generator.Emit(OpCodes.Brfalse, finish); context.Generator.PushLocalValueOntoStack(iteratorLocal); context.Generator.Emit(OpCodes.Callvirt, enumeratorType.GetProperty("Current").GetGetMethod()); context.Generator.StoreLocalValueFromStack(currentElementLocal); GenerateWriteField(context, elementVariable, token.FormalElementType); context.Generator.Emit(OpCodes.Br, loopBegin); context.Generator.MarkLabel(finish); }