private static void EmitBeq(Compiler.CompilerContext ctx, Compiler.CodeLabel label, Type type) { switch (Helpers.GetTypeCode(type)) { case ProtoTypeCode.Boolean: case ProtoTypeCode.Byte: case ProtoTypeCode.Char: case ProtoTypeCode.Double: case ProtoTypeCode.Int16: case ProtoTypeCode.Int32: case ProtoTypeCode.Int64: case ProtoTypeCode.SByte: case ProtoTypeCode.Single: case ProtoTypeCode.UInt16: case ProtoTypeCode.UInt32: case ProtoTypeCode.UInt64: ctx.BranchIfEqual(label, false); break; default: MethodInfo method = type.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.Static, null, new Type[] { type, type }, null); if (method is null || method.ReturnType != typeof(bool)) { throw new InvalidOperationException("No suitable equality operator found for default-values of type: " + type.FullName); } ctx.EmitCall(method); ctx.BranchIfTrue(label, false); break; } }
private void EmitCreateIfNull(Compiler.CompilerContext ctx, Compiler.Local storage) { Helpers.DebugAssert(storage != null); if (!ExpectedType.IsValueType) { Compiler.CodeLabel afterNullCheck = ctx.DefineLabel(); ctx.LoadValue(storage); ctx.BranchIfTrue(afterNullCheck, false); ((IProtoTypeSerializer)this).EmitCreateInstance(ctx); if (callbacks != null) { EmitInvokeCallback(ctx, callbacks.BeforeDeserialize, true, null, forType); } ctx.StoreValue(storage); ctx.MarkLabel(afterNullCheck); } }
void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) { Helpers.DebugAssert(((IProtoTypeSerializer)this).HasCallbacks(callbackType), "Shouldn't be calling this if there is nothing to do"); MethodInfo method = callbacks == null ? null : callbacks[callbackType]; ctx.LoadValue(valueFrom); EmitInvokeCallback(ctx, method); Compiler.CodeLabel @break = ctx.DefineLabel(); if (CanHaveInheritance) { for (int i = 0; i < serializers.Length; i++) { IProtoSerializer ser = serializers[i]; IProtoTypeSerializer typeser; if (ser.ExpectedType != forType && (typeser = (IProtoTypeSerializer)ser).HasCallbacks(callbackType)) { Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel(); ctx.CopyValue(); ctx.TryCast(ser.ExpectedType); ctx.CopyValue(); ctx.BranchIfTrue(ifMatch, true); ctx.DiscardValue(); ctx.Branch(nextTest, false); ctx.MarkLabel(ifMatch); typeser.EmitCallback(ctx, null, callbackType); ctx.Branch(@break, false); ctx.MarkLabel(nextTest); } } } ctx.MarkLabel(@break); ctx.DiscardValue(); }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { Tail.EmitRead(ctx, valueFrom); ctx.CopyValue(); Compiler.CodeLabel @nonEmpty = ctx.DefineLabel(), @end = ctx.DefineLabel(); ctx.LoadValue(typeof(string).GetProperty("Length")); ctx.BranchIfTrue(@nonEmpty, true); ctx.DiscardValue(); ctx.LoadNullRef(); ctx.Branch(@end, true); ctx.MarkLabel(@nonEmpty); ctx.EmitCtor(ctx.MapType(typeof(Uri)), ctx.MapType(typeof(string))); ctx.MarkLabel(@end); }
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 (factory != null) { EmitInvokeCallback(ctx, factory, false); } else if (!useConstructor) { // DataContractSerializer style ctx.LoadValue(constructType); ctx.EmitCall(ctx.MapType(typeof(BclHelpers)).GetMethod("GetUninitializedObject")); ctx.Cast(forType); } else if (constructType.IsClass && hasConstructor) { // XmlSerializer style ctx.EmitCtor(constructType); } else { ctx.LoadValue(type); ctx.EmitCall(ctx.MapType(typeof(TypeModel)).GetMethod("ThrowCannotCreateInstance", BindingFlags.Static | BindingFlags.Public)); ctx.LoadNullRef(); callNoteObject = false; } if (callNoteObject) { // track root object creation ctx.CopyValue(); ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("NoteObject", BindingFlags.Static | BindingFlags.Public)); } if (baseCtorCallbacks != null) { for (int i = 0; i < baseCtorCallbacks.Length; i++) { EmitInvokeCallback(ctx, baseCtorCallbacks[i], true); } } if (callbacks != null) { EmitInvokeCallback(ctx, callbacks.BeforeDeserialize, true); } ctx.StoreValue(storage); ctx.MarkLabel(afterNullCheck); } }
void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) { using (ctx.StartDebugBlockAuto(this)) { bool actuallyHasInheritance = false; if (CanHaveInheritance) { for (int i = 0; i < _serializers.Length; i++) { IProtoSerializer ser = _serializers[i]; if (ser.ExpectedType != ExpectedType && ((ser as IProtoTypeSerializer)?.HasCallbacks(callbackType) ?? false)) { actuallyHasInheritance = true; } } } Helpers.DebugAssert(((IProtoTypeSerializer)this).HasCallbacks(callbackType), "Shouldn't be calling this if there is nothing to do"); MethodInfo method = _callbacks?[callbackType]; if (method == null && !actuallyHasInheritance) { return; } ctx.LoadAddress(valueFrom, ExpectedType); EmitInvokeCallback(ctx, method, actuallyHasInheritance, null, ExpectedType); if (actuallyHasInheritance) { Compiler.CodeLabel @break = ctx.DefineLabel(); for (int i = 0; i < _serializers.Length; i++) { IProtoSerializer ser = _serializers[i]; IProtoTypeSerializer typeser; Type serType = ser.ExpectedType; if (serType != ExpectedType && (typeser = (IProtoTypeSerializer)ser).HasCallbacks(callbackType)) { Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel(); ctx.CopyValue(); ctx.TryCast(serType); ctx.CopyValue(); ctx.BranchIfTrue(ifMatch, true); ctx.DiscardValue(); ctx.Branch(nextTest, false); ctx.MarkLabel(ifMatch); typeser.EmitCallback(ctx, null, callbackType); ctx.Branch(@break, false); ctx.MarkLabel(nextTest); } } ctx.MarkLabel(@break); ctx.DiscardValue(); } } }
private void WriteFieldHandler( Compiler.CompilerContext ctx, Type expected, Compiler.Local loc, Compiler.CodeLabel handler, Compiler.CodeLabel @continue, IProtoSerializer serializer) { ctx.MarkLabel(handler); Type serType = serializer.ExpectedType; if (serType == forType) { EmitCreateIfNull(ctx, loc); serializer.EmitRead(ctx, loc); } else { //RuntimeTypeModel rtm = (RuntimeTypeModel)ctx.Model; if (((IProtoTypeSerializer)serializer).CanCreateInstance()) { Compiler.CodeLabel allDone = ctx.DefineLabel(); ctx.LoadValue(loc); ctx.BranchIfFalse(allDone, false); // null is always ok ctx.LoadValue(loc); ctx.TryCast(serType); ctx.BranchIfTrue(allDone, false); // not null, but of the correct type // otherwise, need to convert it ctx.LoadReaderWriter(); ctx.LoadValue(loc); ((IProtoTypeSerializer)serializer).EmitCreateInstance(ctx); ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("Merge")); ctx.Cast(expected); ctx.StoreValue(loc); // Merge always returns a value // nothing needs doing ctx.MarkLabel(allDone); } ctx.LoadValue(loc); ctx.Cast(serType); 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 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); } }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom)) { ctx.LoadAddress(loc, ExpectedType); if (Tail.RequiresOldValue) { ctx.CopyValue(); ctx.LoadValue(field); } // value is either now on the stack or not needed ctx.ReadNullCheckedTail(field.FieldType, Tail, null); if (Tail.ReturnsValue) { if (field.FieldType.IsValueType) { // stack is now the return value ctx.StoreValue(field); } else { Compiler.CodeLabel hasValue = ctx.DefineLabel(), allDone = ctx.DefineLabel(); ctx.CopyValue(); ctx.BranchIfTrue(hasValue, true); // interpret null as "don't assign" // no value, discard ctx.DiscardValue(); ctx.DiscardValue(); ctx.Branch(allDone, true); ctx.MarkLabel(hasValue); ctx.StoreValue(field); ctx.MarkLabel(allDone); } } else { ctx.DiscardValue(); } } }
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 (!Helpers.IsValueType(ExpectedType)) { ctx.LoadValue(oldList); ctx.BranchIfFalse(done, false); // old value null; nothing to add } #if COREFX TypeInfo typeInfo = ExpectedType.GetTypeInfo(); #else Type typeInfo = ExpectedType; #endif PropertyInfo prop = Helpers.GetProperty(typeInfo, "Length", false); if (prop == null) { prop = Helpers.GetProperty(typeInfo, "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); } } }
} // updates field directly #if FEAT_COMPILER void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { Type expected = ExpectedType; using (Compiler.Local loc = ctx.GetLocalWithValue(expected, valueFrom)) { // pre-callbacks EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeSerialize); Compiler.CodeLabel startFields = ctx.DefineLabel(); // inheritance if (CanHaveInheritance) { for (int i = 0; i < serializers.Length; i++) { IProtoSerializer ser = serializers[i]; Type serType = ser.ExpectedType; if (serType != forType) { Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel(); ctx.LoadValue(loc); ctx.TryCast(serType); ctx.CopyValue(); ctx.BranchIfTrue(ifMatch, true); ctx.DiscardValue(); ctx.Branch(nextTest, true); ctx.MarkLabel(ifMatch); ser.EmitWrite(ctx, null); ctx.Branch(startFields, false); ctx.MarkLabel(nextTest); } } if (constructType != null && constructType != forType) { using (Compiler.Local actualType = new Compiler.Local(ctx, ctx.MapType(typeof(System.Type)))) { // would have jumped to "fields" if an expected sub-type, so two options: // a: *exactly* that type, b: an *unexpected* type ctx.LoadValue(loc); ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType")); ctx.CopyValue(); ctx.StoreValue(actualType); ctx.LoadValue(forType); ctx.BranchIfEqual(startFields, true); ctx.LoadValue(actualType); ctx.LoadValue(constructType); ctx.BranchIfEqual(startFields, true); } } else { // would have jumped to "fields" if an expected sub-type, so two options: // a: *exactly* that type, b: an *unexpected* type ctx.LoadValue(loc); ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType")); ctx.LoadValue(forType); ctx.BranchIfEqual(startFields, true); } // unexpected, then... note that this *might* be a proxy, which // is handled by ThrowUnexpectedSubtype ctx.LoadValue(forType); ctx.LoadValue(loc); ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType")); ctx.EmitCall(ctx.MapType(typeof(TypeModel)).GetMethod("ThrowUnexpectedSubtype", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)); } // fields ctx.MarkLabel(startFields); for (int i = 0; i < serializers.Length; i++) { IProtoSerializer ser = serializers[i]; if (ser.ExpectedType == forType) { ser.EmitWrite(ctx, loc); } } // extension data if (isExtensible) { ctx.LoadValue(loc); ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("AppendExtensionData")); } // post-callbacks EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.AfterSerialize); } }
private void WriteFieldHandler( Compiler.CompilerContext ctx, Type expected, Compiler.Local loc, Compiler.CodeLabel handler, Compiler.CodeLabel @continue, IProtoSerializer serializer) { ctx.MarkLabel(handler); Type serType = serializer.ExpectedType; if (serType == ExpectedType) { EmitCreateIfNull(ctx, loc); serializer.EmitRead(ctx, loc); } else { //RuntimeTypeModel rtm = (RuntimeTypeModel)ctx.Model; if (((IProtoTypeSerializer)serializer).CanCreateInstance()) { Compiler.CodeLabel allDone = ctx.DefineLabel(); ctx.LoadValue(loc); ctx.BranchIfFalse(allDone, false); // null is always ok ctx.LoadValue(loc); ctx.TryCast(serType); ctx.BranchIfTrue(allDone, false); // not null, but of the correct type // otherwise, need to convert it ctx.LoadReader(false); ctx.LoadValue(loc); ((IProtoTypeSerializer)serializer).EmitCreateInstance(ctx); ctx.EmitCall(typeof(ProtoReader).GetMethod("Merge", new[] { typeof(ProtoReader), typeof(object), typeof(object) })); ctx.Cast(expected); ctx.StoreValue(loc); // Merge always returns a value // nothing needs doing ctx.MarkLabel(allDone); } if (Helpers.IsValueType(serType)) { Compiler.CodeLabel initValue = ctx.DefineLabel(); Compiler.CodeLabel hasValue = ctx.DefineLabel(); using (Compiler.Local emptyValue = new Compiler.Local(ctx, serType)) { ctx.LoadValue(loc); ctx.BranchIfFalse(initValue, false); ctx.LoadValue(loc); ctx.CastFromObject(serType); ctx.Branch(hasValue, false); ctx.MarkLabel(initValue); ctx.InitLocal(serType, emptyValue); ctx.LoadValue(emptyValue); ctx.MarkLabel(hasValue); } } else { ctx.LoadValue(loc); ctx.Cast(serType); } serializer.EmitRead(ctx, null); } if (serializer.ReturnsValue) { // update the variable if (Helpers.IsValueType(serType)) { // but box it first in case of value type ctx.CastToObject(serType); } ctx.StoreValue(loc); } ctx.Branch(@continue, false); // "continue" }
public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local incoming) { using (Compiler.Local objValue = ctx.GetLocalWithValue(ExpectedType, incoming)) { Compiler.Local[] locals = new Compiler.Local[members.Length]; try { for (int i = 0; i < locals.Length; i++) { Type type = GetMemberType(i); bool store = true; locals[i] = new Compiler.Local(ctx, type); if (!ExpectedType.IsValueType) { // value-types always read the old value if (type.IsValueType) { switch (Helpers.GetTypeCode(type)) { case ProtoTypeCode.Boolean: case ProtoTypeCode.Byte: case ProtoTypeCode.Int16: case ProtoTypeCode.Int32: case ProtoTypeCode.SByte: case ProtoTypeCode.UInt16: case ProtoTypeCode.UInt32: ctx.LoadValue(0); break; case ProtoTypeCode.Int64: case ProtoTypeCode.UInt64: ctx.LoadValue(0L); break; case ProtoTypeCode.Single: ctx.LoadValue(0.0F); break; case ProtoTypeCode.Double: ctx.LoadValue(0.0D); break; case ProtoTypeCode.Decimal: ctx.LoadValue(0M); break; case ProtoTypeCode.Guid: ctx.LoadValue(Guid.Empty); break; default: ctx.LoadAddress(locals[i], type); ctx.EmitCtor(type); store = false; break; } } else { ctx.LoadNullRef(); } if (store) { ctx.StoreValue(locals[i]); } } } Compiler.CodeLabel skipOld = ExpectedType.IsValueType ? new Compiler.CodeLabel() : ctx.DefineLabel(); if (!ExpectedType.IsValueType) { ctx.LoadAddress(objValue, ExpectedType); ctx.BranchIfFalse(skipOld, false); } for (int i = 0; i < members.Length; i++) { ctx.LoadAddress(objValue, ExpectedType); switch (members[i].MemberType) { case MemberTypes.Field: ctx.LoadValue((FieldInfo)members[i]); break; case MemberTypes.Property: ctx.LoadValue((PropertyInfo)members[i]); break; } ctx.StoreValue(locals[i]); } if (!ExpectedType.IsValueType) { ctx.MarkLabel(skipOld); } using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) { Compiler.CodeLabel @continue = ctx.DefineLabel(), processField = ctx.DefineLabel(), notRecognised = ctx.DefineLabel(); ctx.Branch(@continue, false); Compiler.CodeLabel[] handlers = new Compiler.CodeLabel[members.Length]; for (int i = 0; i < members.Length; i++) { handlers[i] = ctx.DefineLabel(); } ctx.MarkLabel(processField); ctx.LoadValue(fieldNumber); ctx.LoadValue(1); ctx.Subtract(); // jump-table is zero-based ctx.Switch(handlers); // and the default: ctx.Branch(notRecognised, false); for (int i = 0; i < handlers.Length; i++) { ctx.MarkLabel(handlers[i]); IProtoSerializer tail = tails[i]; Compiler.Local oldValIfNeeded = tail.RequiresOldValue ? locals[i] : null; ctx.ReadNullCheckedTail(locals[i].Type, tail, oldValIfNeeded); if (tail.ReturnsValue) { if (locals[i].Type.IsValueType) { ctx.StoreValue(locals[i]); } else { Compiler.CodeLabel hasValue = ctx.DefineLabel(), allDone = ctx.DefineLabel(); ctx.CopyValue(); ctx.BranchIfTrue(hasValue, true); // interpret null as "don't assign" ctx.DiscardValue(); ctx.Branch(allDone, true); ctx.MarkLabel(hasValue); ctx.StoreValue(locals[i]); ctx.MarkLabel(allDone); } } ctx.Branch(@continue, false); } ctx.MarkLabel(notRecognised); ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("SkipField")); ctx.MarkLabel(@continue); ctx.EmitBasicRead("ReadFieldHeader", ctx.MapType(typeof(int))); ctx.CopyValue(); ctx.StoreValue(fieldNumber); ctx.LoadValue(0); ctx.BranchIfGreater(processField, false); } for (int i = 0; i < locals.Length; i++) { ctx.LoadValue(locals[i]); } ctx.EmitCtor(ctor); ctx.StoreValue(objValue); } finally { for (int i = 0; i < locals.Length; i++) { if (locals[i] != null) { locals[i].Dispose(); // release for re-use } } } } }
private void EmitBranchIfDefaultValue(Compiler.CompilerContext ctx, Compiler.CodeLabel label) { Type expected = ExpectedType; switch (Helpers.GetTypeCode(expected)) { case ProtoTypeCode.Boolean: if ((bool)defaultValue) { ctx.BranchIfTrue(label, false); } else { ctx.BranchIfFalse(label, false); } break; case ProtoTypeCode.Byte: if ((byte)defaultValue == (byte)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(byte)defaultValue); EmitBeq(ctx, label, expected); } break; case ProtoTypeCode.SByte: if ((sbyte)defaultValue == (sbyte)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(sbyte)defaultValue); EmitBeq(ctx, label, expected); } break; case ProtoTypeCode.Int16: if ((short)defaultValue == (short)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(short)defaultValue); EmitBeq(ctx, label, expected); } break; case ProtoTypeCode.UInt16: if ((ushort)defaultValue == (ushort)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(ushort)defaultValue); EmitBeq(ctx, label, expected); } break; case ProtoTypeCode.Int32: if ((int)defaultValue == (int)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)defaultValue); EmitBeq(ctx, label, expected); } break; case ProtoTypeCode.UInt32: if ((uint)defaultValue == (uint)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(uint)defaultValue); EmitBeq(ctx, label, expected); } break; case ProtoTypeCode.Char: if ((char)defaultValue == (char)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(char)defaultValue); EmitBeq(ctx, label, expected); } break; case ProtoTypeCode.Int64: ctx.LoadValue((long)defaultValue); EmitBeq(ctx, label, expected); break; case ProtoTypeCode.UInt64: ctx.LoadValue((long)(ulong)defaultValue); EmitBeq(ctx, label, expected); break; case ProtoTypeCode.Double: ctx.LoadValue((double)defaultValue); EmitBeq(ctx, label, expected); break; case ProtoTypeCode.Single: ctx.LoadValue((float)defaultValue); EmitBeq(ctx, label, expected); break; case ProtoTypeCode.String: ctx.LoadValue((string)defaultValue); EmitBeq(ctx, label, expected); break; case ProtoTypeCode.Decimal: { decimal d = (decimal)defaultValue; ctx.LoadValue(d); EmitBeq(ctx, label, expected); } break; case ProtoTypeCode.TimeSpan: { TimeSpan ts = (TimeSpan)defaultValue; if (ts == TimeSpan.Zero) { ctx.LoadValue(typeof(TimeSpan).GetField("Zero")); } else { ctx.LoadValue(ts.Ticks); ctx.EmitCall(ctx.MapType(typeof(TimeSpan)).GetMethod("FromTicks")); } EmitBeq(ctx, label, expected); break; } case ProtoTypeCode.Guid: { ctx.LoadValue((Guid)defaultValue); EmitBeq(ctx, label, expected); break; } case ProtoTypeCode.DateTime: { #if FX11 ctx.LoadValue(((DateTime)defaultValue).ToFileTime()); ctx.EmitCall(typeof(DateTime).GetMethod("FromFileTime")); #else ctx.LoadValue(((DateTime)defaultValue).ToBinary()); ctx.EmitCall(ctx.MapType(typeof(DateTime)).GetMethod("FromBinary")); #endif EmitBeq(ctx, label, expected); break; } default: throw new NotSupportedException("Type cannot be represented as a default value: " + expected.FullName); } }
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 (!Helpers.IsValueType(ExpectedType)) { ctx.LoadValue(oldList); ctx.BranchIfFalse(done, false); // old value null; nothing to add } ctx.LoadAddress(oldList, oldList.Type); if (isEmpty != null) { ctx.EmitCall(Helpers.GetGetMethod(isEmpty, false, false)); ctx.BranchIfTrue(done, false); // old list is empty; nothing to add } else { ctx.EmitCall(Helpers.GetGetMethod(length, false, false)); ctx.BranchIfFalse(done, false); // old list is empty; nothing to add } Type voidType = 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(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); } } }
private void EmitBranchIfDefaultValue(Compiler.CompilerContext ctx, Compiler.CodeLabel label) { switch (Type.GetTypeCode(ExpectedType)) { case TypeCode.Boolean: if ((bool)defaultValue) { ctx.BranchIfTrue(label, false); } else { ctx.BranchIfFalse(label, false); } break; case TypeCode.Byte: if ((byte)defaultValue == (byte)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(byte)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case TypeCode.SByte: if ((sbyte)defaultValue == (sbyte)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(sbyte)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case TypeCode.Int16: if ((short)defaultValue == (short)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(short)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case TypeCode.UInt16: if ((ushort)defaultValue == (ushort)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(ushort)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case TypeCode.Int32: if ((int)defaultValue == (int)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case TypeCode.UInt32: if ((uint)defaultValue == (uint)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(uint)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case TypeCode.Char: if ((char)defaultValue == (char)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(char)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case TypeCode.Int64: ctx.LoadValue((long)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case TypeCode.UInt64: ctx.LoadValue((long)(ulong)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case TypeCode.Double: ctx.LoadValue((double)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case TypeCode.Single: ctx.LoadValue((float)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case TypeCode.String: ctx.LoadValue((string)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case TypeCode.Decimal: { decimal d = (decimal)defaultValue; ctx.LoadValue(d); EmitBeq(ctx, label, ExpectedType); } break; default: if (ExpectedType == typeof(TimeSpan)) { TimeSpan ts = (TimeSpan)defaultValue; if (ts == TimeSpan.Zero) { ctx.LoadValue(typeof(TimeSpan).GetField("Zero")); } else { ctx.LoadValue(ts.Ticks); ctx.EmitCall(typeof(TimeSpan).GetMethod("FromTicks")); } EmitBeq(ctx, label, ExpectedType); } else { throw new NotSupportedException("Type cannot be represented as a default value: " + ExpectedType.FullName); } break; } }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (ctx.StartDebugBlockAuto(this)) { Type voidType = ctx.MapType(typeof(void)); using (Compiler.Local value = ctx.GetLocalWithValueForEmitRead(this, valueFrom)) using (Compiler.Local builderInstance = new Compiler.Local(ctx, _builderFactory.ReturnType)) using (Compiler.Local trappedKey = new Compiler.Local(ctx, typeof(int))) { ctx.G.Assign(trappedKey, ctx.G.ReaderFunc.ReserveNoteObject_int()); ctx.EmitCall(_builderFactory); ctx.StoreValue(builderInstance); if (AppendToCollection) { Compiler.CodeLabel done = ctx.DefineLabel(); if (!ExpectedType.IsValueType) { ctx.LoadValue(value); ctx.BranchIfFalse(done, false); // old value null; nothing to add } PropertyInfo prop = Helpers.GetProperty(ExpectedType, "Length", false) ?? Helpers.GetProperty(ExpectedType, "Count", false); #if !NO_GENERICS if (prop == null) { prop = Helpers.GetProperty(ResolveIReadOnlyCollection(ExpectedType, Tail.ExpectedType), "Count", false); } #endif ctx.LoadAddress(value, value.Type); ctx.EmitCall(Helpers.GetGetMethod(prop, false, false)); ctx.BranchIfFalse(done, false); // old list is empty; nothing to add if (_addRange != null) { ctx.LoadValue(builderInstance); ctx.LoadValue(value); 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(value, 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(builderInstance, builderInstance.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); } ListHelpers.EmitRead( ctx.G, null, null, o => { using (ctx.StartDebugBlockAuto(this, "add")) { ctx.LoadAddress(builderInstance, builderInstance.Type); ctx.LoadValue(o); ctx.EmitCall(_add); if (_add.ReturnType != null && _add.ReturnType != voidType) { ctx.DiscardValue(); } } }); ctx.LoadAddress(builderInstance, builderInstance.Type); ctx.EmitCall(_finish); if (ExpectedType != _finish.ReturnType) { ctx.Cast(ExpectedType); } ctx.StoreValue(value); ctx.G.Reader.NoteReservedTrappedObject(trappedKey, value); if (EmitReadReturnsValue) { ctx.LoadValue(value); } } } }
void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) { bool actuallyHasInheritance = false; if (CanHaveInheritance) { for (int i = 0; i < serializers.Length; i++) { IProtoSerializer ser = serializers[i]; if (ser.ExpectedType != forType && ((IProtoTypeSerializer)ser).HasCallbacks(callbackType)) { actuallyHasInheritance = true; } } } Helpers.DebugAssert(((IProtoTypeSerializer)this).HasCallbacks(callbackType), "Shouldn't be calling this if there is nothing to do"); MethodInfo method = callbacks?[callbackType]; if (method == null && !actuallyHasInheritance) { return; } if (!method.IsStatic) { ctx.LoadAddress(valueFrom, ExpectedType); } EmitInvokeCallback(ctx, method, actuallyHasInheritance, null, forType); if (actuallyHasInheritance) { // Make sure that the object is on the top of the stack. // If the callback is non-static, it's already here from the EmitInvokeCallback call. if (method.IsStatic) { ctx.LoadAddress(valueFrom, ExpectedType); } Compiler.CodeLabel @break = ctx.DefineLabel(); for (int i = 0; i < serializers.Length; i++) { IProtoSerializer ser = serializers[i]; IProtoTypeSerializer typeser; Type serType = ser.ExpectedType; if (serType != forType && (typeser = (IProtoTypeSerializer)ser).HasCallbacks(callbackType)) { Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel(); ctx.CopyValue(); ctx.TryCast(serType); ctx.CopyValue(); ctx.BranchIfTrue(ifMatch, true); ctx.DiscardValue(); ctx.Branch(nextTest, false); ctx.MarkLabel(ifMatch); typeser.EmitCallback(ctx, null, callbackType); ctx.Branch(@break, false); ctx.MarkLabel(nextTest); } } ctx.MarkLabel(@break); ctx.DiscardValue(); } }