bool EmitDedicatedMethod(Compiler.CompilerContext ctx, Compiler.Local valueFrom, bool read) { System.Reflection.Emit.MethodBuilder method = ctx.GetDedicatedMethod(key, read); if (method == null) return false; using (Compiler.Local token = new ProtoBuf.Compiler.Local(ctx, typeof(SubItemToken))) { Type rwType = read ? typeof(ProtoReader) : typeof(ProtoWriter); ctx.LoadValue(valueFrom); if (!read) // write requires the object for StartSubItem; read doesn't { if (type.IsValueType) { ctx.LoadNullRef(); } else { ctx.CopyValue(); } } ctx.LoadReaderWriter(); ctx.EmitCall(rwType.GetMethod("StartSubItem")); ctx.StoreValue(token); // note: value already on the stack ctx.LoadReaderWriter(); ctx.EmitCall(method); // handle inheritance (we will be calling the *base* version of things, // but we expect Read to return the "type" type) if (read && type != method.ReturnType) ctx.Cast(this.type); ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(rwType.GetMethod("EndSubItem")); } return true; }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (Compiler.Local oldList = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : null) using(Compiler.Local builder = new Compiler.Local(ctx, builderFactory.ReturnType)) { ctx.EmitCall(builderFactory); ctx.StoreValue(builder); if(AppendToCollection) { Compiler.CodeLabel done = ctx.DefineLabel(); if(!ExpectedType.IsValueType) { ctx.LoadValue(oldList); ctx.BranchIfFalse(done, false); // old value null; nothing to add } PropertyInfo prop = Helpers.GetProperty(ExpectedType, "Length", false); if(prop == null) prop = Helpers.GetProperty(ExpectedType, "Count", false); #if !NO_GENERICS if (prop == null) prop = Helpers.GetProperty(ResolveIReadOnlyCollection(ExpectedType, Tail.ExpectedType), "Count", false); #endif ctx.LoadAddress(oldList, oldList.Type); ctx.EmitCall(Helpers.GetGetMethod(prop, false, false)); ctx.BranchIfFalse(done, false); // old list is empty; nothing to add Type voidType = ctx.MapType(typeof(void)); if(addRange != null) { ctx.LoadValue(builder); ctx.LoadValue(oldList); ctx.EmitCall(addRange); if (addRange.ReturnType != null && add.ReturnType != voidType) ctx.DiscardValue(); } else { // loop and call Add repeatedly MethodInfo moveNext, current, getEnumerator = GetEnumeratorInfo(ctx.Model, out moveNext, out current); Helpers.DebugAssert(moveNext != null); Helpers.DebugAssert(current != null); Helpers.DebugAssert(getEnumerator != null); Type enumeratorType = getEnumerator.ReturnType; using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType)) { ctx.LoadAddress(oldList, ExpectedType); ctx.EmitCall(getEnumerator); ctx.StoreValue(iter); using (ctx.Using(iter)) { Compiler.CodeLabel body = ctx.DefineLabel(), next = ctx.DefineLabel(); ctx.Branch(next, false); ctx.MarkLabel(body); ctx.LoadAddress(builder, builder.Type); ctx.LoadAddress(iter, enumeratorType); ctx.EmitCall(current); ctx.EmitCall(add); if (add.ReturnType != null && add.ReturnType != voidType) ctx.DiscardValue(); ctx.MarkLabel(@next); ctx.LoadAddress(iter, enumeratorType); ctx.EmitCall(moveNext); ctx.BranchIfTrue(body, false); } } } ctx.MarkLabel(done); } EmitReadList(ctx, builder, Tail, add, packedWireType, false); ctx.LoadAddress(builder, builder.Type); ctx.EmitCall(finish); if(ExpectedType != finish.ReturnType) { ctx.Cast(ExpectedType); } } }
bool EmitDedicatedMethod(Compiler.CompilerContext ctx, Compiler.Local valueFrom, bool read) { #if SILVERLIGHT return false; #else MethodBuilder method = ctx.GetDedicatedMethod(key, read); if (method == null) return false; using (Compiler.Local token = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken)))) { Type rwType = ctx.MapType(read ? typeof(ProtoReader) : typeof(ProtoWriter)); ctx.LoadValue(valueFrom); if (!read) // write requires the object for StartSubItem; read doesn't { // (if recursion-check is disabled [subtypes] then null is fine too) if (type.IsValueType || !recursionCheck) { ctx.LoadNullRef(); } else { ctx.CopyValue(); } } ctx.LoadReaderWriter(); ctx.EmitCall(rwType.GetMethod("StartSubItem")); ctx.StoreValue(token); // note: value already on the stack ctx.LoadReaderWriter(); ctx.EmitCall(method); // handle inheritance (we will be calling the *base* version of things, // but we expect Read to return the "type" type) if (read && type != method.ReturnType) ctx.Cast(this.type); ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(rwType.GetMethod("EndSubItem")); } return true; #endif }
private void WriteFieldHandler( Compiler.CompilerContext ctx, Type expected, Compiler.Local loc, Compiler.CodeLabel handler, Compiler.CodeLabel @continue, IProtoSerializer serializer) { ctx.MarkLabel(handler); if (serializer.ExpectedType == forType) { EmitCreateIfNull(ctx, expected, loc); serializer.EmitRead(ctx, loc); } else { ctx.LoadValue(loc); ctx.Cast(serializer.ExpectedType); serializer.EmitRead(ctx, null); } if (serializer.ReturnsValue) { // update the variable ctx.StoreValue(loc); } ctx.Branch(@continue, false); // "continue" }
private void EmitCreateIfNull(Compiler.CompilerContext ctx, Type type, Compiler.Local storage) { Helpers.DebugAssert(storage != null); if (!type.IsValueType) { Compiler.CodeLabel afterNullCheck = ctx.DefineLabel(); ctx.LoadValue(storage); ctx.BranchIfTrue(afterNullCheck, true); // different ways of creating a new instance bool callNoteObject = true; if (!useConstructor) { // DataContractSerializer style ctx.LoadValue(constructType); ctx.EmitCall(typeof(BclHelpers).GetMethod("GetUninitializedObject")); ctx.Cast(forType); } else if (constructType.IsClass && hasConstructor) { // XmlSerializer style ctx.EmitCtor(constructType); } else { ctx.LoadValue(type); ctx.EmitCall(typeof(TypeModel).GetMethod("ThrowCannotCreateInstance", BindingFlags.Static | BindingFlags.Public)); ctx.LoadNullRef(); callNoteObject = false; } if (callNoteObject) { // track root object creation ctx.CopyValue(); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoReader).GetMethod("NoteObject", BindingFlags.Static | BindingFlags.Public)); } if (baseCtorCallbacks != null) { for (int i = 0; i < baseCtorCallbacks.Length; i++) { EmitInvokeCallback(ctx, baseCtorCallbacks[i]); } } if (callbacks != null) EmitInvokeCallback(ctx, callbacks.BeforeDeserialize); ctx.StoreValue(storage); ctx.MarkLabel(afterNullCheck); } }
private void EmitCreateIfNull(Compiler.CompilerContext ctx, Type type, Compiler.Local storage) { Helpers.DebugAssert(storage != null); if (!type.IsValueType) { Compiler.CodeLabel afterNullCheck = ctx.DefineLabel(); ctx.LoadValue(storage); ctx.BranchIfTrue(afterNullCheck, true); // different ways of creating a new instance if (!useConstructor) { // DataContractSerializer style ctx.LoadValue(forType); ctx.EmitCall(typeof(BclHelpers).GetMethod("GetUninitializedObject")); ctx.Cast(forType); } else if (type.IsClass && !type.IsAbstract && ( (type.GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Helpers.EmptyTypes, null)) != null)) { // XmlSerializer style ctx.EmitCtor(type); } else { ctx.LoadValue(type); ctx.EmitCall(typeof(TypeModel).GetMethod("ThrowCannotCreateInstance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); ctx.LoadNullRef(); } if (baseCtorCallbacks != null) { for (int i = 0; i < baseCtorCallbacks.Length; i++) { EmitInvokeCallback(ctx, baseCtorCallbacks[i]); } } if (callbacks != null) EmitInvokeCallback(ctx, callbacks.BeforeDeserialize); ctx.StoreValue(storage); ctx.MarkLabel(afterNullCheck); } }