internal void MarkLabel(CodeLabel label) { il.MarkLabel(label.Value); #if DEBUG_COMPILE Helpers.DebugWriteLine("#: " + label.Index); #endif }
internal void BranchIfTrue(CodeLabel label, bool @short) { OpCode opCode; opCode = (@short ? OpCodes.Brtrue_S : OpCodes.Brtrue); this.il.Emit(opCode, label.Value); }
internal void BranchIfEqual(CodeLabel label, bool @short) { OpCode opCode; opCode = (@short ? OpCodes.Beq_S : OpCodes.Beq); this.il.Emit(opCode, label.Value); }
internal void BranchIfLess(CodeLabel label, bool @short) { OpCode opCode; opCode = (@short ? OpCodes.Blt_S : OpCodes.Blt); this.il.Emit(opCode, label.Value); }
internal void WriteNullCheckedTail(Type type, IProtoSerializer tail, Local valueFrom) { if (!type.IsValueType) { this.LoadValue(valueFrom); this.CopyValue(); CodeLabel codeLabel = this.DefineLabel(); CodeLabel codeLabel1 = this.DefineLabel(); this.BranchIfTrue(codeLabel, true); this.DiscardValue(); this.Branch(codeLabel1, false); this.MarkLabel(codeLabel); tail.EmitWrite(this, null); this.MarkLabel(codeLabel1); } else { if (Helpers.GetUnderlyingType(type) == null) { tail.EmitWrite(this, valueFrom); return; } using (Local localWithValue = this.GetLocalWithValue(type, valueFrom)) { this.LoadAddress(localWithValue, type); this.LoadValue(type.GetProperty("HasValue")); CodeLabel codeLabel2 = this.DefineLabel(); this.BranchIfFalse(codeLabel2, false); this.LoadAddress(localWithValue, type); this.EmitCall(type.GetMethod("GetValueOrDefault", Helpers.EmptyTypes)); tail.EmitWrite(this, null); this.MarkLabel(codeLabel2); } } }
internal void EndTry(CodeLabel label, bool @short) { OpCode opCode; opCode = (@short ? OpCodes.Leave_S : OpCodes.Leave); this.il.Emit(opCode, label.Value); }
public void Dispose() { if (this.local == null || this.ctx == null) { return; } this.ctx.EndTry(this.label, false); this.ctx.BeginFinally(); Type type = this.ctx.MapType(typeof(IDisposable)); MethodInfo method = type.GetMethod("Dispose"); Type type1 = this.local.Type; if (!type1.IsValueType) { CodeLabel codeLabel = this.ctx.DefineLabel(); if (!type.IsAssignableFrom(type1)) { using (Local local = new Local(this.ctx, type)) { this.ctx.LoadValue(this.local); this.ctx.TryCast(type); this.ctx.CopyValue(); this.ctx.StoreValue(local); this.ctx.BranchIfFalse(codeLabel, true); this.ctx.LoadAddress(local, type); } } else { this.ctx.LoadValue(this.local); this.ctx.BranchIfFalse(codeLabel, true); this.ctx.LoadAddress(this.local, type1); } this.ctx.EmitCall(method); this.ctx.MarkLabel(codeLabel); } else { this.ctx.LoadAddress(this.local, type1); if (this.ctx.MetadataVersion != CompilerContext.ILVersion.Net1) { this.ctx.Constrain(type1); } else { this.ctx.LoadValue(this.local); this.ctx.CastToObject(type1); } this.ctx.EmitCall(method); } this.ctx.EndFinally(); this.local = null; this.ctx = null; this.label = new CodeLabel(); }
/*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); using (Local typedVal = new Local(ctx, type)) { if (!type.IsValueType) { ctx.LoadValue(Local.InputValue); ctx.CastFromObject(type); ctx.StoreValue(typedVal); } else { ctx.LoadValue(Local.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(Local.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))); }
public UsingBlock(CompilerContext ctx, Local local) { if (ctx == null) { throw new ArgumentNullException("ctx"); } if (local == null) { throw new ArgumentNullException("local"); } Type type = local.Type; if ((type.IsValueType || type.IsSealed) && !ctx.MapType(typeof(IDisposable)).IsAssignableFrom(type)) { return; } this.local = local; this.ctx = ctx; this.label = ctx.BeginTry(); }
public static ProtoDeserializer BuildDeserializer(IProtoSerializer head, TypeModel model) { Type expectedType = head.ExpectedType; CompilerContext compilerContext = new CompilerContext(expectedType, false, true, model, typeof(object)); using (Local local = new Local(compilerContext, expectedType)) { if (expectedType.IsValueType) { compilerContext.LoadValue(compilerContext.InputValue); CodeLabel codeLabel = compilerContext.DefineLabel(); CodeLabel codeLabel1 = compilerContext.DefineLabel(); compilerContext.BranchIfTrue(codeLabel, true); compilerContext.LoadAddress(local, expectedType); compilerContext.EmitCtor(expectedType); compilerContext.Branch(codeLabel1, true); compilerContext.MarkLabel(codeLabel); compilerContext.LoadValue(compilerContext.InputValue); compilerContext.CastFromObject(expectedType); compilerContext.StoreValue(local); compilerContext.MarkLabel(codeLabel1); } else { compilerContext.LoadValue(compilerContext.InputValue); compilerContext.CastFromObject(expectedType); compilerContext.StoreValue(local); } head.EmitRead(compilerContext, local); if (head.ReturnsValue) { compilerContext.StoreValue(local); } compilerContext.LoadValue(local); compilerContext.CastToObject(expectedType); } compilerContext.Emit(OpCodes.Ret); return((ProtoDeserializer)compilerContext.method.CreateDelegate(typeof(ProtoDeserializer))); }
internal void LoadLength(Local arr, bool zeroIfNull) { if (!zeroIfNull) { this.LoadValue(arr); this.Emit(OpCodes.Ldlen); this.Emit(OpCodes.Conv_I4); return; } CodeLabel codeLabel = this.DefineLabel(); CodeLabel codeLabel1 = this.DefineLabel(); this.LoadValue(arr); this.CopyValue(); this.BranchIfTrue(codeLabel, true); this.DiscardValue(); this.LoadValue(0); this.Branch(codeLabel1, true); this.MarkLabel(codeLabel); this.Emit(OpCodes.Ldlen); this.Emit(OpCodes.Conv_I4); this.MarkLabel(codeLabel1); }
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(); }
internal CodeLabel DefineLabel() { CodeLabel result = new CodeLabel(il.DefineLabel(), nextLabel++); return(result); }
internal CodeLabel BeginTry() { CodeLabel label = new CodeLabel(il.BeginExceptionBlock(), nextLabel++); #if DEBUG_COMPILE Helpers.DebugWriteLine("BeginExceptionBlock: " + label.Index); #endif return label; }
internal CodeLabel DefineLabel() { CodeLabel result = new CodeLabel(il.DefineLabel(), nextLabel++); return result; }
public void Switch(CodeLabel[] jumpTable) { const int MAX_JUMPS = 128; if (jumpTable.Length <= MAX_JUMPS) { // simple case Label[] labels = new Label[jumpTable.Length]; for (int i = 0; i < labels.Length; i++) { labels[i] = jumpTable[i].Value; } #if DEBUG_COMPILE Helpers.DebugWriteLine(OpCodes.Switch.ToString()); #endif il.Emit(OpCodes.Switch, labels); } else { // too many to jump easily (especially on Android) - need to split up (note: uses a local pulled from the stack) using (Local val = GetLocalWithValue(MapType(typeof(int)), null)) { int count = jumpTable.Length, offset = 0; int blockCount = count / MAX_JUMPS; if ((count % MAX_JUMPS) != 0) blockCount++; Label[] blockLabels = new Label[blockCount]; for (int i = 0; i < blockCount; i++) { blockLabels[i] = il.DefineLabel(); } CodeLabel endOfSwitch = DefineLabel(); LoadValue(val); LoadValue(MAX_JUMPS); Emit(OpCodes.Div); #if DEBUG_COMPILE Helpers.DebugWriteLine(OpCodes.Switch.ToString()); #endif il.Emit(OpCodes.Switch, blockLabels); Branch(endOfSwitch, false); Label[] innerLabels = new Label[MAX_JUMPS]; for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) { il.MarkLabel(blockLabels[blockIndex]); int itemsThisBlock = Math.Min(MAX_JUMPS, count); count -= itemsThisBlock; if (innerLabels.Length != itemsThisBlock) innerLabels = new Label[itemsThisBlock]; int subtract = offset; for (int j = 0; j < itemsThisBlock; j++) { innerLabels[j] = jumpTable[offset++].Value; } LoadValue(val); if (subtract != 0) // switches are always zero-based { LoadValue(subtract); Emit(OpCodes.Sub); } #if DEBUG_COMPILE Helpers.DebugWriteLine(OpCodes.Switch.ToString()); #endif il.Emit(OpCodes.Switch, innerLabels); if (count != 0) { // force default to the very bottom Branch(endOfSwitch, false); } } Helpers.DebugAssert(count == 0, "Should use exactly all switch items"); MarkLabel(endOfSwitch); } } }
public void Switch(CodeLabel[] jumpTable) { if ((int)jumpTable.Length <= 128) { Label[] value = new Label[(int)jumpTable.Length]; for (int i = 0; i < (int)value.Length; i++) { value[i] = jumpTable[i].Value; } this.il.Emit(OpCodes.Switch, value); return; } using (Local localWithValue = this.GetLocalWithValue(this.MapType(typeof(int)), null)) { int length = (int)jumpTable.Length; int num = 0; int num1 = length / 128; if (length % 128 != 0) { num1++; } Label[] labelArray = new Label[num1]; for (int j = 0; j < num1; j++) { labelArray[j] = this.il.DefineLabel(); } CodeLabel codeLabel = this.DefineLabel(); this.LoadValue(localWithValue); this.LoadValue(128); this.Emit(OpCodes.Div); this.il.Emit(OpCodes.Switch, labelArray); this.Branch(codeLabel, false); Label[] value1 = new Label[128]; for (int k = 0; k < num1; k++) { this.il.MarkLabel(labelArray[k]); int num2 = Math.Min(128, length); length -= num2; if ((int)value1.Length != num2) { value1 = new Label[num2]; } int num3 = num; for (int l = 0; l < num2; l++) { int num4 = num; num = num4 + 1; value1[l] = jumpTable[num4].Value; } this.LoadValue(localWithValue); if (num3 != 0) { this.LoadValue(num3); this.Emit(OpCodes.Sub); } this.il.Emit(OpCodes.Switch, value1); if (length != 0) { this.Branch(codeLabel, false); } } this.MarkLabel(codeLabel); } }
public void Switch(CodeLabel[] jumpTable) { Label[] labels = new Label[jumpTable.Length]; #if DEBUG_COMPILE StringBuilder sb = new StringBuilder(OpCodes.Switch.ToString()); #endif for (int i = 0; i < labels.Length; i++) { labels[i] = jumpTable[i].Value; #if DEBUG_COMPILE sb.Append("; ").Append(i).Append("=>").Append(jumpTable[i].Index); #endif } il.Emit(OpCodes.Switch, labels); #if DEBUG_COMPILE Helpers.DebugWriteLine(sb.ToString()); #endif }
public void Switch(CodeLabel[] jumpTable) { const int MAX_JUMPS = 128; // if too many jumps, push the value into a local using(Local val = jumpTable.Length >= MAX_JUMPS ? GetLocalWithValue(MapType(typeof(int)),null) : null) { int count = jumpTable.Length, offset = 0; do { // if multi-switch, need to load the value again, and offset if necessary if (val != null) { LoadValue(val); if (offset != 0) { LoadValue(offset); Subtract(); } } int itemsThisIteration = Math.Min(count, MAX_JUMPS); count -= itemsThisIteration; Label[] labels = new Label[itemsThisIteration]; #if DEBUG_COMPILE StringBuilder sb = new StringBuilder(OpCodes.Switch.ToString()); #endif for (int i = 0; i < labels.Length; i++) { labels[i] = jumpTable[offset++].Value; #if DEBUG_COMPILE sb.Append("; ").Append(i).Append("=>").Append(jumpTable[i].Index); #endif } il.Emit(OpCodes.Switch, labels); #if DEBUG_COMPILE Helpers.DebugWriteLine(sb.ToString()); #endif } while (count > 0); } }
internal void BranchIfTrue(CodeLabel label, bool @short) { OpCode code = @short ? OpCodes.Brtrue_S : OpCodes.Brtrue; il.Emit(code, label.Value); #if DEBUG_COMPILE Helpers.DebugWriteLine(code + ": " + label.Index); #endif }
internal void MarkLabel(CodeLabel label) { il.MarkLabel(label.Value); }
internal void EndTry(CodeLabel label, bool @short) { OpCode code = @short ? OpCodes.Leave_S : OpCodes.Leave; il.Emit(code, label.Value); #if DEBUG_COMPILE Helpers.DebugWriteLine(code + ": " + label.Index); #endif }
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); }