コード例 #1
0
ファイル: CompilerContext.cs プロジェクト: viktorius/Viktor
        internal void MarkLabel(CodeLabel label)
        {
            il.MarkLabel(label.Value);
#if DEBUG_COMPILE
            Helpers.DebugWriteLine("#: " + label.Index);
#endif
        }
コード例 #2
0
        internal void BranchIfTrue(CodeLabel label, bool @short)
        {
            OpCode opCode;

            opCode = (@short ? OpCodes.Brtrue_S : OpCodes.Brtrue);
            this.il.Emit(opCode, label.Value);
        }
コード例 #3
0
        internal void BranchIfEqual(CodeLabel label, bool @short)
        {
            OpCode opCode;

            opCode = (@short ? OpCodes.Beq_S : OpCodes.Beq);
            this.il.Emit(opCode, label.Value);
        }
コード例 #4
0
        internal void BranchIfLess(CodeLabel label, bool @short)
        {
            OpCode opCode;

            opCode = (@short ? OpCodes.Blt_S : OpCodes.Blt);
            this.il.Emit(opCode, label.Value);
        }
コード例 #5
0
 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);
         }
     }
 }
コード例 #6
0
        internal void MarkLabel(CodeLabel label)
        {
            il.MarkLabel(label.Value);
#if DEBUG_COMPILE
            Helpers.DebugWriteLine("#: " + label.Index);
#endif
        }
コード例 #7
0
        internal void EndTry(CodeLabel label, bool @short)
        {
            OpCode opCode;

            opCode = (@short ? OpCodes.Leave_S : OpCodes.Leave);
            this.il.Emit(opCode, label.Value);
        }
コード例 #8
0
            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();
            }
コード例 #9
0
ファイル: CompilerContext.cs プロジェクト: viktorius/Viktor
        /*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)));
        }
コード例 #10
0
            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();
            }
コード例 #11
0
        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)));
        }
コード例 #12
0
        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);
        }
コード例 #13
0
            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
            }
コード例 #14
0
            /// <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();
            }
コード例 #15
0
ファイル: CompilerContext.cs プロジェクト: viktorius/Viktor
        internal CodeLabel DefineLabel()
        {
            CodeLabel result = new CodeLabel(il.DefineLabel(), nextLabel++);

            return(result);
        }
コード例 #16
0
 internal CodeLabel BeginTry()
 {
     CodeLabel label = new CodeLabel(il.BeginExceptionBlock(), nextLabel++);
     #if DEBUG_COMPILE
     Helpers.DebugWriteLine("BeginExceptionBlock: " + label.Index);
     #endif
     return label;
 }
コード例 #17
0
 internal CodeLabel DefineLabel()
 {
     CodeLabel result = new CodeLabel(il.DefineLabel(), nextLabel++);
     return result;
 }
コード例 #18
0
        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);
                }
            }
        }
コード例 #19
0
 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);
     }
 }
コード例 #20
0
        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
        }
コード例 #21
0
        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);
            }
        }
コード例 #22
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
 }
コード例 #23
0
 internal void MarkLabel(CodeLabel label)
 {
     il.MarkLabel(label.Value);
 }
コード例 #24
0
 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
 }
コード例 #25
0
            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);
            }