public static ProtoSerializer BuildSerializer(IProtoSerializer head) { Type type = head.ExpectedType; CompilerContext ctx = new CompilerContext(type, true, true); ctx.LoadValue(Local.InputValue); ctx.CastFromObject(type); ctx.WriteNullCheckedTail(type, head, null); ctx.Emit(OpCodes.Ret); return (ProtoSerializer)ctx.method.CreateDelegate( typeof(ProtoSerializer)); }
public void Dispose() { if (ctx != null) { // only *actually* dispose if this is context-bound; note that non-bound // objects are cheekily re-used, and *must* be left intact agter a "using" etc ctx.ReleaseToPool(value); value = null; ctx = null; } }
public static ProtoSerializer BuildSerializer(IProtoSerializer head, TypeModel model) { Type type = head.ExpectedType; try { CompilerContext ctx = new CompilerContext(type, true, true, model, typeof(object)); ctx.LoadValue(ctx.InputValue); ctx.CastFromObject(type); ctx.WriteNullCheckedTail(type, head, null); ctx.Emit(OpCodes.Ret); return (ProtoSerializer)ctx.method.CreateDelegate( typeof(ProtoSerializer)); } catch (Exception ex) { string name = type.FullName; if(string.IsNullOrEmpty(name)) name = type.Name; throw new InvalidOperationException("It was not possible to prepare a serializer for: " + name, ex); } }
public void Dispose() { if (local == null || ctx == null) return; ctx.EndTry(label, false); ctx.BeginFinally(); Type disposableType = ctx.MapType(typeof (IDisposable)); MethodInfo dispose = disposableType.GetMethod("Dispose"); Type type = local.Type; // remember that we've already (in the .ctor) excluded the case // where it *cannot* be disposable if (type.IsValueType) { ctx.LoadAddress(local, type); switch (ctx.MetadataVersion) { case ILVersion.Net1: ctx.LoadValue(local); ctx.CastToObject(type); break; default: #if FX11 throw new NotSupportedException(); #else ctx.Constrain(type); break; #endif } ctx.EmitCall(dispose); } else { Compiler.CodeLabel @null = ctx.DefineLabel(); if (disposableType.IsAssignableFrom(type)) { // *known* to be IDisposable; just needs a null-check ctx.LoadValue(local); ctx.BranchIfFalse(@null, true); ctx.LoadAddress(local, type); } else { // *could* be IDisposable; test via "as" using (Compiler.Local disp = new Compiler.Local(ctx, disposableType)) { ctx.LoadValue(local); ctx.TryCast(disposableType); ctx.CopyValue(); ctx.StoreValue(disp); ctx.BranchIfFalse(@null, true); ctx.LoadAddress(disp, disposableType); } } ctx.EmitCall(dispose); ctx.MarkLabel(@null); } ctx.EndFinally(); this.local = null; this.ctx = null; label = new CodeLabel(); // default }
/// <summary> /// Creates a new "using" block (equivalent) around a variable; /// the variable must exist, and note that (unlike in C#) it is /// the variables *final* value that gets disposed. If you need /// *original* disposal, copy your variable first. /// /// It is the callers responsibility to ensure that the variable's /// scope fully-encapsulates the "using"; if not, the variable /// may be re-used (and thus re-assigned) unexpectedly. /// </summary> public UsingBlock(CompilerContext ctx, Local local) { if (ctx == null) throw new ArgumentNullException("ctx"); if (local == null) throw new ArgumentNullException("local"); Type type = local.Type; // check if **never** disposable if ((type.IsValueType || type.IsSealed) && !ctx.MapType(typeof(IDisposable)).IsAssignableFrom(type)) { return; // nothing to do! easiest "using" block ever // (note that C# wouldn't allow this as a "using" block, // but we'll be generous and simply not do anything) } this.local = local; this.ctx = ctx; label = ctx.BeginTry(); }
/*public static ProtoCallback BuildCallback(IProtoTypeSerializer head) { Type type = head.ExpectedType; CompilerContext ctx = new CompilerContext(type, true, true); using (Local typedVal = new Local(ctx, type)) { ctx.LoadValue(Local.InputValue); ctx.CastFromObject(type); ctx.StoreValue(typedVal); CodeLabel[] jumpTable = new CodeLabel[4]; for(int i = 0 ; i < jumpTable.Length ; i++) { jumpTable[i] = ctx.DefineLabel(); } ctx.LoadReaderWriter(); ctx.Switch(jumpTable); ctx.Return(); for(int i = 0 ; i < jumpTable.Length ; i++) { ctx.MarkLabel(jumpTable[i]); if (head.HasCallbacks((TypeModel.CallbackType)i)) { head.EmitCallback(ctx, typedVal, (TypeModel.CallbackType)i); } ctx.Return(); } } ctx.Emit(OpCodes.Ret); return (ProtoCallback)ctx.method.CreateDelegate( typeof(ProtoCallback)); }*/ public static ProtoDeserializer BuildDeserializer(IProtoSerializer head, TypeModel model) { Type type = head.ExpectedType; CompilerContext ctx = new CompilerContext(type, false, true, model, typeof(object)); using (Local typedVal = new Local(ctx, type)) { if (!type.IsValueType) { ctx.LoadValue(ctx.InputValue); ctx.CastFromObject(type); ctx.StoreValue(typedVal); } else { ctx.LoadValue(ctx.InputValue); CodeLabel notNull = ctx.DefineLabel(), endNull = ctx.DefineLabel(); ctx.BranchIfTrue(notNull, true); ctx.LoadAddress(typedVal, type); ctx.EmitCtor(type); ctx.Branch(endNull, true); ctx.MarkLabel(notNull); ctx.LoadValue(ctx.InputValue); ctx.CastFromObject(type); ctx.StoreValue(typedVal); ctx.MarkLabel(endNull); } head.EmitRead(ctx, typedVal); if (head.ReturnsValue) { ctx.StoreValue(typedVal); } ctx.LoadValue(typedVal); ctx.CastToObject(type); } ctx.Emit(OpCodes.Ret); return (ProtoDeserializer)ctx.method.CreateDelegate( typeof(ProtoDeserializer)); }
internal Local(Compiler.CompilerContext ctx, Type type) { this.ctx = ctx; if (ctx != null) { value = ctx.GetFromPool(type); } this.type = type; }
void IProtoSerializer.EmitRead(CompilerContext ctx, Local valueFrom) { throw new NotImplementedException(); }
void IProtoSerializer.EmitWrite(CompilerContext ctx, Local valueFrom) { // burn the value off the stack if needed (creates a variable and does a stloc) using (Local tmp = ctx.GetLocalWithValue(type, valueFrom)) { } }
public void Dispose() { if (local == null || ctx == null) return; ctx.EndTry(label, false); ctx.BeginFinally(); MethodInfo dispose = typeof(IDisposable).GetMethod("Dispose"); Type type = local.Type; // remember that we've already (in the .ctor) excluded the case // where it *cannot* be disposable if (type.IsValueType) { ctx.LoadAddress(local, type); ctx.Constrain(type); ctx.EmitCall(dispose); } else { Compiler.CodeLabel @null = ctx.DefineLabel(); if (typeof(IDisposable).IsAssignableFrom(type)) { // *known* to be IDisposable; just needs a null-check ctx.LoadValue(local); ctx.BranchIfFalse(@null, true); ctx.LoadAddress(local, type); } else { // *could* be IDisposable; test via "as" using (Compiler.Local disp = new Compiler.Local(ctx, typeof(IDisposable))) { ctx.LoadValue(local); ctx.TryCast(typeof(IDisposable)); ctx.CopyValue(); ctx.StoreValue(disp); ctx.BranchIfFalse(@null, true); ctx.LoadAddress(disp, typeof(IDisposable)); } } ctx.EmitCall(dispose); ctx.MarkLabel(@null); } ctx.EndFinally(); this.local = null; this.ctx = null; label = default(CodeLabel); }