private void Emit(BlockExpression node, CompilationFlags flags)
        {
            int count = node.ExpressionCount;

            if (count == 0)
            {
                return;
            }

            EnterScope(node);

            CompilationFlags emitAs = flags & CompilationFlags.EmitAsTypeMask;

            CompilationFlags tailCall = flags & CompilationFlags.EmitAsTailCallMask;
            for (int index = 0; index < count - 1; index++)
            {
                var e = node.GetExpression(index);
                var next = node.GetExpression(index + 1);

                CompilationFlags tailCallFlag;
                if (tailCall != CompilationFlags.EmitAsNoTail)
                {
                    var g = next as GotoExpression;
                    if (g != null && (g.Value == null || !Significant(g.Value)) && ReferenceLabel(g.Target).CanReturn)
                    {
                        // Since tail call flags are not passed into EmitTryExpression, CanReturn means the goto will be emitted
                        // as Ret. Therefore we can emit the current expression with tail call.
                        tailCallFlag = CompilationFlags.EmitAsTail;
                    }
                    else
                    {
                        // In the middle of the block.
                        // We may do better here by marking it as Tail if the following expressions are not going to emit any IL.
                        tailCallFlag = CompilationFlags.EmitAsMiddle;
                    }
                }
                else
                {
                    tailCallFlag = CompilationFlags.EmitAsNoTail;
                }

                flags = UpdateEmitAsTailCallFlag(flags, tailCallFlag);
                EmitExpressionAsVoid(e, flags);
            }

            // if the type of Block it means this is not a Comma
            // so we will force the last expression to emit as void.
            // We don't need EmitAsType flag anymore, should only pass
            // the EmitTailCall field in flags to emitting the last expression.
            if (emitAs == CompilationFlags.EmitAsVoidType || node.Type == typeof(void))
            {
                EmitExpressionAsVoid(node.GetExpression(count - 1), tailCall);
            }
            else
            {
                EmitExpressionAsType(node.GetExpression(count - 1), node.Type, tailCall);
            }

            ExitScope(node);
        }
        private void EmitConditionalExpression(Expression expr, CompilationFlags flags)
        {
            ConditionalExpression node = (ConditionalExpression)expr;
            Debug.Assert(node.Test.Type == typeof(bool));
            Label labFalse = _ilg.DefineLabel();
            EmitExpressionAndBranch(false, node.Test, labFalse);
            EmitExpressionAsType(node.IfTrue, node.Type, flags);

            if (NotEmpty(node.IfFalse))
            {
                Label labEnd = _ilg.DefineLabel();
                if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail)
                {
                    // We know the conditional expression is at the end of the lambda,
                    // so it is safe to emit Ret here.
                    _ilg.Emit(OpCodes.Ret);
                }
                else
                {
                    _ilg.Emit(OpCodes.Br, labEnd);
                }
                _ilg.MarkLabel(labFalse);
                EmitExpressionAsType(node.IfFalse, node.Type, flags);
                _ilg.MarkLabel(labEnd);
            }
            else
            {
                _ilg.MarkLabel(labFalse);
            }
        }
        private void EmitExpressionAsVoid(Expression node, CompilationFlags flags) {
            Debug.Assert(node != null);

            CompilationFlags startEmitted = EmitExpressionStart(node);

            switch (node.NodeType) {
                case ExpressionType.Assign:
                    EmitAssign((BinaryExpression)node, CompilationFlags.EmitAsVoidType);
                    break;
                case ExpressionType.Block:
                    Emit((BlockExpression)node, UpdateEmitAsTypeFlag(flags, CompilationFlags.EmitAsVoidType));
                    break;
                case ExpressionType.Throw:
                    EmitThrow((UnaryExpression)node, CompilationFlags.EmitAsVoidType);
                    break;
                case ExpressionType.Goto:
                    EmitGotoExpression(node, UpdateEmitAsTypeFlag(flags, CompilationFlags.EmitAsVoidType));
                    break;
                case ExpressionType.Constant:
                case ExpressionType.Default:
                case ExpressionType.Parameter:
                    // no-op
                    break;
                default:
                    if (node.Type == typeof(void)) {
                        EmitExpression(node, UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitNoExpressionStart));
                    } else {
                        EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
                        _ilg.Emit(OpCodes.Pop);
                    }
                    break;
            }
            EmitExpressionEnd(startEmitted);
        }
        private static bool TryParseArgs(string[] args, out string sourceFile, out CompilationFlags flags)
        {
            sourceFile = null;
            flags = 0;
            if (args.Length < 1)
                return false;

            foreach (string arg in args)
            {
                string normalizedArg = arg.ToUpper();
                switch (normalizedArg)
                {
                    case "/32":
                        flags |= CompilationFlags.Platform32;
                        break;
                    case "/64":
                        flags |= CompilationFlags.Platform64;
                        break;
                    case "/NODEBUG":
                        flags |= CompilationFlags.NoDebug;
                        break;
                    case "/ASM":
                        flags |= CompilationFlags.Assembly;
                        break;
                    default:
                        if (normalizedArg.StartsWith("/"))
                        {
                            Console.WriteLine("Unrecognized option {0}", normalizedArg);
                            return false;
                        }
                        if (!File.Exists(arg))
                        {
                            Console.WriteLine("Source file '{0}' not found", arg);
                            return false;
                        }
                        if (sourceFile != null)
                        {
                            Console.WriteLine("Multiple source files specified.  Only one file is supported");
                            return false;
                        }
                        sourceFile = arg;
                        break;
                }
            }

            if (flags.HasFlag(CompilationFlags.Platform32) && flags.HasFlag(CompilationFlags.Platform64))
            {
                Console.WriteLine("Both 32-bit and 64-bit platforms specified.  Only one platform is supported");
                return false;
            }

            if (!flags.HasFlag(CompilationFlags.Platform32) && !flags.HasFlag(CompilationFlags.Platform64))
                flags |= CompilationFlags.Platform32;

            if (sourceFile == null)
                return false;

            return true;
        }
        /// <summary>
        /// Initializes a new instance of the PeEmitter class.
        /// Use this constructor to when saving the PE file to disk
        /// </summary>
        /// <param name="outputFile">Path to output file</param>
        /// <param name="flags">Compiler flags</param>
        public PeEmitter(string outputFile, CompilationFlags flags)
        {
            _ilFile = GetPathToTempFile("il");
            _textEmitter = new TextEmitter(_ilFile);

            _outputFile = outputFile;
            _flags = flags;
        }
 protected CompilerContext(string filePath, StreamReader inputReader, Importer importer, IEmitter emitter, CompilationFlags flags)
 {
     FilePath = filePath;
     Flags = flags;
     Emitter = emitter;
     CompileErrors = new ErrorList();
     Importer = importer;
     SymbolTable = new SymbolTable();
     Lexer = Lexer.Create(inputReader, CompileErrors);
 }
 private TestCompilerContext(
     MemoryStream input,
     StreamReader reader,
     MemoryStream output,
     IEmitter emitter,
     CompilationFlags flags)
     : base("FakeFile.iris", reader, emitter, flags)
 {
     _input = input;
     _reader = reader;
     _output = output;
 }
 protected CmdLineCompilerContext(
     string sourcePath,
     Stream inputFile,
     StreamReader sourceReader,
     IEmitter emitter,
     CompilationFlags flags)
     : base(sourcePath, sourceReader, emitter, flags)
 {
     _inputFile = inputFile;
     _reader = sourceReader;
     _emitter = emitter;
 }
        private void EmitThrow(UnaryExpression expr, CompilationFlags flags) {
            if (expr.Operand == null) {
                CheckRethrow();

                _ilg.Emit(OpCodes.Rethrow);
            } else {
                EmitExpression(expr.Operand);
                _ilg.Emit(OpCodes.Throw);
            }

            EmitUnreachable(expr, flags);
        }
        private void Emit(BlockExpression node, CompilationFlags flags) {
            EnterScope(node);

            CompilationFlags emitAs = flags & CompilationFlags.EmitAsTypeMask;

            int count = node.ExpressionCount;
            CompilationFlags tailCall = flags & CompilationFlags.EmitAsTailCallMask;
            CompilationFlags middleTailCall = tailCall == CompilationFlags.EmitAsNoTail ? CompilationFlags.EmitAsNoTail : CompilationFlags.EmitAsMiddle;

            for (int index = 0; index < count - 1; index++) {
                var e = node.GetExpression(index);
                var next = node.GetExpression(index + 1);

                if (EmitDebugSymbols) {
                    // No need to emit a clearance if the next expression in the block is also a
                    // DebugInfoExprssion.
                    var debugInfo = e as DebugInfoExpression;
                    if (debugInfo != null && debugInfo.IsClear && next is DebugInfoExpression) {
                        continue;
                    }
                }
                // In the middle of the block.
                // We may do better here by marking it as Tail if the following expressions are not going to emit any IL.
                var tailCallFlag = middleTailCall;

                var g = next as GotoExpression;
                if (g != null && (g.Value == null || !Significant(g.Value))) {
                    var labelInfo = ReferenceLabel(g.Target);
                    if (labelInfo.CanReturn) {
                        // Since tail call flags are not passed into EmitTryExpression, CanReturn means the goto will be emitted
                        // as Ret. Therefore we can emit the current expression with tail call.
                        tailCallFlag = CompilationFlags.EmitAsTail;
                    }
                }
                flags = UpdateEmitAsTailCallFlag(flags, tailCallFlag);
                EmitExpressionAsVoid(e, flags);
            }

            // if the type of Block it means this is not a Comma
            // so we will force the last expression to emit as void.
            // We don't need EmitAsType flag anymore, should only pass
            // the EmitTailCall field in flags to emitting the last expression.
            if (emitAs == CompilationFlags.EmitAsVoidType || node.Type == typeof(void)) {
                EmitExpressionAsVoid(node.GetExpression(count - 1), tailCall);
            } else {
                EmitExpressionAsType(node.GetExpression(count - 1), node.Type, tailCall);
            }

            ExitScope(node);
        }
        private void EmitBinaryExpression(Expression expr, CompilationFlags flags)
        {
            BinaryExpression b = (BinaryExpression)expr;

            Debug.Assert(b.NodeType != ExpressionType.AndAlso && b.NodeType != ExpressionType.OrElse && b.NodeType != ExpressionType.Coalesce);

            if (b.Method != null)
            {
                EmitBinaryMethod(b, flags);
                return;
            }

            // For EQ and NE, if there is a user-specified method, use it.
            // Otherwise implement the C# semantics that allow equality
            // comparisons on non-primitive nullable structs that don't
            // overload "=="
            if ((b.NodeType == ExpressionType.Equal || b.NodeType == ExpressionType.NotEqual) &&
                (b.Type == typeof(bool) || b.Type == typeof(bool?)))
            {
                // If we have x==null, x!=null, null==x or null!=x where x is
                // nullable but not null, then generate a call to x.HasValue.
                Debug.Assert(!b.IsLiftedToNull || b.Type == typeof(bool?));
                if (ConstantCheck.IsNull(b.Left) && !ConstantCheck.IsNull(b.Right) && TypeHelper.IsNullableType(b.Right.Type))
                {
                    EmitNullEquality(b.NodeType, b.Right, b.IsLiftedToNull);
                    return;
                }
                if (ConstantCheck.IsNull(b.Right) && !ConstantCheck.IsNull(b.Left) && TypeHelper.IsNullableType(b.Left.Type))
                {
                    EmitNullEquality(b.NodeType, b.Left, b.IsLiftedToNull);
                    return;
                }

                // For EQ and NE, we can avoid some conversions if we're
                // ultimately just comparing two managed pointers.
                EmitExpression(GetEqualityOperand(b.Left));
                EmitExpression(GetEqualityOperand(b.Right));
            }
            else
            {
                // Otherwise generate it normally
                EmitExpression(b.Left);
                EmitExpression(b.Right);
            }

            EmitBinaryOperator(b.NodeType, b.Left.Type, b.Right.Type, b.Type, b.IsLiftedToNull);
        }
        public static TestCompilerContext Create(string compiland, GlobalSymbolList globals, CompilationFlags flags)
        {
            byte[] buffer = Encoding.Default.GetBytes(compiland);
            MemoryStream input = new MemoryStream(buffer);
            StreamReader reader = new StreamReader(input);
            MemoryStream output = new MemoryStream();
            TextEmitter emitter = new TextEmitter(output);

            TestCompilerContext testContext = new TestCompilerContext(input, reader, output, emitter, flags);
            if (globals != null)
            {
                foreach (var symbol in globals.Items)
                    testContext.SymbolTable.Add(symbol.Item1, symbol.Item2, StorageClass.Global, null);
            }

            return testContext;
        }
Example #13
0
 private void EmitUnary(UnaryExpression node, CompilationFlags flags) {
     if (node.Method != null) {
         EmitUnaryMethod(node, flags);
     } else if (node.NodeType == ExpressionType.NegateChecked && TypeUtils.IsInteger(node.Operand.Type)) {
         EmitExpression(node.Operand);
         LocalBuilder loc = GetLocal(node.Operand.Type);
         _ilg.Emit(OpCodes.Stloc, loc);
         _ilg.EmitInt(0);
         _ilg.EmitConvertToType(typeof(int), node.Operand.Type, false);
         _ilg.Emit(OpCodes.Ldloc, loc);
         FreeLocal(loc);
         EmitBinaryOperator(ExpressionType.SubtractChecked, node.Operand.Type, node.Operand.Type, node.Type, false);
     } else {
         EmitExpression(node.Operand);
         EmitUnaryOperator(node.NodeType, node.Operand.Type, node.Type);
     }
 }
        private void EmitLabelExpression(Expression expr, CompilationFlags flags)
        {
            var node = (LabelExpression)expr;
            Debug.Assert(node.Target != null);

            // If we're an immediate child of a block, our label will already
            // be defined. If not, we need to define our own block so this
            // label isn't exposed except to its own child expression.
            LabelInfo label = null;

            if (_labelBlock.Kind == LabelScopeKind.Block)
            {
                _labelBlock.TryGetLabelInfo(node.Target, out label);

                // We're in a block but didn't find our label, try switch
                if (label == null && _labelBlock.Parent.Kind == LabelScopeKind.Switch)
                {
                    _labelBlock.Parent.TryGetLabelInfo(node.Target, out label);
                }

                // if we're in a switch or block, we should've found the label
                Debug.Assert(label != null);
            }

            if (label == null)
            {
                label = DefineLabel(node.Target);
            }

            if (node.DefaultValue != null)
            {
                if (node.Target.Type == typeof(void))
                {
                    EmitExpressionAsVoid(node.DefaultValue, flags);
                }
                else
                {
                    flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart);
                    EmitExpression(node.DefaultValue, flags);
                }
            }

            label.Mark();
        }
        // We don't want "ref" parameters to modify values of expressions
        // except where it would in IL: locals, args, fields, and array elements
        // (Unbox is an exception, it's intended to emit a ref to the original
        // boxed value)
        private void EmitAddress(Expression node, Type type, CompilationFlags flags)
        {
            Debug.Assert(node != null);
            bool emitStart = (flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart;
            CompilationFlags startEmitted = emitStart ? EmitExpressionStart(node) : CompilationFlags.EmitNoExpressionStart;

            switch (node.NodeType)
            {
                default:
                    EmitExpressionAddress(node, type);
                    break;

                case ExpressionType.ArrayIndex:
                    AddressOf((BinaryExpression)node, type);
                    break;

                case ExpressionType.Parameter:
                    AddressOf((ParameterExpression)node, type);
                    break;

                case ExpressionType.MemberAccess:
                    AddressOf((MemberExpression)node, type);
                    break;

                case ExpressionType.Unbox:
                    AddressOf((UnaryExpression)node, type);
                    break;

                case ExpressionType.Call:
                    AddressOf((MethodCallExpression)node, type);
                    break;

                case ExpressionType.Index:
                    AddressOf((IndexExpression)node, type);
                    break;
            }

            if (emitStart)
            {
                EmitExpressionEnd(startEmitted);
            }
        }
        public static CmdLineCompilerContext Create(string sourcePath, CompilationFlags flags)
        {
            string outputFile;
            IEmitter emitter;

            if (flags.HasFlag(CompilationFlags.Assembly))
            {
                outputFile = Path.ChangeExtension(sourcePath, "il");
                emitter = new TextEmitter(outputFile);
            }
            else
            {
                outputFile = Path.ChangeExtension(sourcePath, "exe");
                emitter = new PeEmitter(outputFile, flags);
            }

            Stream inputFile = File.Open(sourcePath, FileMode.Open, FileAccess.Read);
            StreamReader reader = new StreamReader(inputFile);

            return new CmdLineCompilerContext(sourcePath, inputFile, reader, emitter, flags);
        }
 private void EmitExpressionAsType(Expression node, Type type, CompilationFlags flags)
 {
     if (type == typeof(void))
     {
         EmitExpressionAsVoid(node, flags);
     }
     else
     {
         // if the node is emitted as a different type, CastClass IL is emitted at the end,
         // should not emit with tail calls.
         if (!TypeUtils.AreEquivalent(node.Type, type))
         {
             EmitExpression(node);
             Debug.Assert(TypeUtils.AreReferenceAssignable(type, node.Type));
             _ilg.Emit(OpCodes.Castclass, type);
         }
         else
         {
             // emit the node with the flags and emit expression start
             EmitExpression(node, UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart));
         }
     }
 }
        private void Emit(BlockExpression node, CompilationFlags flags)
        {
            int count = node.ExpressionCount;

            if (count == 0)
            {
                return;
            }

            EnterScope(node);

            CompilationFlags emitAs = flags & CompilationFlags.EmitAsTypeMask;

            CompilationFlags tailCall = flags & CompilationFlags.EmitAsTailCallMask;

            for (int index = 0; index < count - 1; index++)
            {
                var e    = node.GetExpression(index);
                var next = node.GetExpression(index + 1);

                CompilationFlags tailCallFlag;
                if (tailCall != CompilationFlags.EmitAsNoTail)
                {
                    var g = next as GotoExpression;
                    if (g != null && (g.Value == null || !Significant(g.Value)) && ReferenceLabel(g.Target).CanReturn)
                    {
                        // Since tail call flags are not passed into EmitTryExpression, CanReturn means the goto will be emitted
                        // as Ret. Therefore we can emit the current expression with tail call.
                        tailCallFlag = CompilationFlags.EmitAsTail;
                    }
                    else
                    {
                        // In the middle of the block.
                        // We may do better here by marking it as Tail if the following expressions are not going to emit any IL.
                        tailCallFlag = CompilationFlags.EmitAsMiddle;
                    }
                }
                else
                {
                    tailCallFlag = CompilationFlags.EmitAsNoTail;
                }

                flags = UpdateEmitAsTailCallFlag(flags, tailCallFlag);
                EmitExpressionAsVoid(e, flags);
            }

            // if the type of Block it means this is not a Comma
            // so we will force the last expression to emit as void.
            // We don't need EmitAsType flag anymore, should only pass
            // the EmitTailCall field in flags to emitting the last expression.
            if (emitAs == CompilationFlags.EmitAsVoidType || node.Type == typeof(void))
            {
                EmitExpressionAsVoid(node.GetExpression(count - 1), tailCall);
            }
            else
            {
                EmitExpressionAsType(node.GetExpression(count - 1), node.Type, tailCall);
            }

            ExitScope(node);
        }
 private void EmitBlockExpression(Expression expr, CompilationFlags flags)
 {
     // emit body
     Emit((BlockExpression)expr, UpdateEmitAsTypeFlag(flags, CompilationFlags.EmitAsDefaultType));
 }
Example #20
0
        // assumes 'object' of non-static call is already on stack
        private void EmitMethodCall(MethodInfo mi, IArgumentProvider args, Type?objectType, CompilationFlags flags)
        {
            // Emit arguments
            List <WriteBack>?wb = EmitArguments(mi, args);

            // Emit the actual call
            OpCode callOp = UseVirtual(mi) ? OpCodes.Callvirt : OpCodes.Call;

            if (callOp == OpCodes.Callvirt && objectType !.IsValueType)
            {
                // This automatically boxes value types if necessary.
                _ilg.Emit(OpCodes.Constrained, objectType);
            }
            // The method call can be a tail call if
            // 1) the method call is the last instruction before Ret
            // 2) the method does not have any ByRef parameters, refer to ECMA-335 Partition III Section 2.4.
            //    "Verification requires that no managed pointers are passed to the method being called, since
            //    it does not track pointers into the current frame."
            if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail && !MethodHasByRefParameter(mi))
            {
                _ilg.Emit(OpCodes.Tailcall);
            }
            if (mi.CallingConvention == CallingConventions.VarArgs)
            {
                int    count = args.ArgumentCount;
                Type[] types = new Type[count];
                for (int i = 0; i < count; i++)
                {
                    types[i] = args.GetArgument(i).Type;
                }

                _ilg.EmitCall(callOp, mi, types);
            }
            else
            {
                _ilg.Emit(callOp, mi);
            }

            // Emit write-backs for properties passed as "ref" arguments
            EmitWriteBack(wb);
        }
 /// <summary>
 /// Update the flag with a new EmitAsType flag
 /// </summary>
 private static CompilationFlags UpdateEmitAsTypeFlag(CompilationFlags flags, CompilationFlags newValue)
 {
     Debug.Assert(newValue == CompilationFlags.EmitAsDefaultType || newValue == CompilationFlags.EmitAsVoidType);
     var oldValue = flags & CompilationFlags.EmitAsTypeMask;
     return flags ^ oldValue | newValue;
 }
        private void EmitMethodCallExpression(Expression expr, CompilationFlags flags)
        {
            MethodCallExpression node = (MethodCallExpression)expr;

            EmitMethodCall(node.Object, node.Method, node, flags);
        }
Example #23
0
        private void EmitExpression(Expression node, CompilationFlags flags)
        {
            // When compiling deep trees, we run the risk of triggering a terminating StackOverflowException,
            // so we use the StackGuard utility here to probe for sufficient stack and continue the work on
            // another thread when we run out of stack space.
            if (!_guard.TryEnterOnCurrentStack())
            {
                _guard.RunOnEmptyStack((@this, n, f) => @this.EmitExpression(n, f), this, node, flags);
                return;
            }

            var emitStart            = (flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart;
            var labelScopeChangeInfo = GetLabelScopeChangeInfo(emitStart, _labelBlock, node);

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = new LabelScopeInfo(labelScopeChangeInfo.Value.parent, labelScopeChangeInfo.Value.kind);
                DefineBlockLabels(labelScopeChangeInfo.Value.nodes);
            }

            // only pass tail call flags to emit the expression
            flags &= CompilationFlags.EmitAsTailCallMask;

            switch (node.NodeType)
            {
            case ExpressionType.Add:
            case ExpressionType.AddChecked:
            case ExpressionType.And:
            case ExpressionType.ArrayIndex:
            case ExpressionType.Divide:
            case ExpressionType.Equal:
            case ExpressionType.ExclusiveOr:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.LeftShift:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.Modulo:
            case ExpressionType.Multiply:
            case ExpressionType.MultiplyChecked:
            case ExpressionType.NotEqual:
            case ExpressionType.Or:
            case ExpressionType.Power:
            case ExpressionType.RightShift:
            case ExpressionType.Subtract:
            case ExpressionType.SubtractChecked:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.AndAlso:
                EmitAndAlsoBinaryExpression(node, flags);
                break;

            case ExpressionType.OrElse:
                EmitOrElseBinaryExpression(node, flags);
                break;

            case ExpressionType.Coalesce:
                EmitCoalesceBinaryExpression(node);
                break;

            case ExpressionType.Assign:
                EmitAssignBinaryExpression(node);
                break;

            case ExpressionType.ArrayLength:
            case ExpressionType.Decrement:
            case ExpressionType.Increment:
            case ExpressionType.IsFalse:
            case ExpressionType.IsTrue:
            case ExpressionType.Negate:
            case ExpressionType.NegateChecked:
            case ExpressionType.Not:
            case ExpressionType.OnesComplement:
            case ExpressionType.TypeAs:
            case ExpressionType.UnaryPlus:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.Convert:
            case ExpressionType.ConvertChecked:
                EmitConvertUnaryExpression(node, flags);
                break;

            case ExpressionType.Quote:
                EmitQuoteUnaryExpression(node);
                break;

            case ExpressionType.Throw:
                EmitThrowUnaryExpression(node);
                break;

            case ExpressionType.Unbox:
                EmitUnboxUnaryExpression(node);
                break;

            case ExpressionType.Call:
                EmitMethodCallExpression(node, flags);
                break;

            case ExpressionType.Conditional:
                EmitConditionalExpression(node, flags);
                break;

            case ExpressionType.Constant:
                EmitConstantExpression(node);
                break;

            case ExpressionType.Invoke:
                EmitInvocationExpression(node, flags);
                break;

            case ExpressionType.Lambda:
                EmitLambdaExpression(node);
                break;

            case ExpressionType.ListInit:
                EmitListInitExpression(node);
                break;

            case ExpressionType.MemberAccess:
                EmitMemberExpression(node);
                break;

            case ExpressionType.MemberInit:
                EmitMemberInitExpression(node);
                break;

            case ExpressionType.New:
                EmitNewExpression(node);
                break;

            case ExpressionType.NewArrayInit:
            case ExpressionType.NewArrayBounds:
                EmitNewArrayExpression(node);
                break;

            case ExpressionType.Parameter:
                EmitParameterExpression(node);
                break;

            case ExpressionType.TypeEqual:
            case ExpressionType.TypeIs:
                EmitTypeBinaryExpression(node);
                break;

            case ExpressionType.Block:
                EmitBlockExpression(node, flags);
                break;

            case ExpressionType.DebugInfo:
                EmitDebugInfoExpression(node);
                break;

            case ExpressionType.Dynamic:
                EmitDynamicExpression(node);
                break;

            case ExpressionType.Default:
                EmitDefaultExpression(node);
                break;

            case ExpressionType.Goto:
                EmitGotoExpression(node, flags);
                break;

            case ExpressionType.Index:
                EmitIndexExpression(node);
                break;

            case ExpressionType.Label:
                EmitLabelExpression(node, flags);
                break;

            case ExpressionType.RuntimeVariables:
                EmitRuntimeVariablesExpression(node);
                break;

            case ExpressionType.Loop:
                EmitLoopExpression(node);
                break;

            case ExpressionType.Switch:
                EmitSwitchExpression(node, flags);
                break;

            case ExpressionType.Try:
                EmitTryExpression(node);
                break;

            default:
                break;
            }

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = labelScopeChangeInfo.Value.parent;
            }
        }
        private static bool TryParseArgs(string[] args, out string sourceFile, out CompilationFlags flags)
        {
            sourceFile = null;
            flags      = 0;
            if (args.Length < 1)
            {
                return(false);
            }

            foreach (string arg in args)
            {
                string normalizedArg = arg.ToUpper();
                switch (normalizedArg)
                {
                case "/32":
                    flags |= CompilationFlags.Platform32;
                    break;

                case "/64":
                    flags |= CompilationFlags.Platform64;
                    break;

                case "/NODEBUG":
                    flags |= CompilationFlags.NoDebug;
                    break;

                case "/ASM":
                    flags |= CompilationFlags.Assembly;
                    break;

                default:
                    if (normalizedArg.StartsWith("/"))
                    {
                        Console.WriteLine("Unrecognized option {0}", normalizedArg);
                        return(false);
                    }
                    if (!File.Exists(arg))
                    {
                        Console.WriteLine("Source file '{0}' not found", arg);
                        return(false);
                    }
                    if (sourceFile != null)
                    {
                        Console.WriteLine("Multiple source files specified.  Only one file is supported");
                        return(false);
                    }
                    sourceFile = arg;
                    break;
                }
            }

            if (flags.HasFlag(CompilationFlags.Platform32) && flags.HasFlag(CompilationFlags.Platform64))
            {
                Console.WriteLine("Both 32-bit and 64-bit platforms specified.  Only one platform is supported");
                return(false);
            }

            if (!flags.HasFlag(CompilationFlags.Platform32) && !flags.HasFlag(CompilationFlags.Platform64))
            {
                flags |= CompilationFlags.Platform32;
            }

            if (sourceFile == null)
            {
                return(false);
            }

// NOTE: Currently this project is always compiled for .NET Core, so this #if will always be true. But leaving
// in case one wants to modify the project to run on desktop. Note that currently this compiler uses the assemblies
// that it is running on as reference assemblies. So to produce .NET Framework assemblies it needs to be running
// on the .NET Framework.
#if NETCOREAPP
            flags |= CompilationFlags.NetCore;
            flags |= CompilationFlags.WriteDll; // force running application through dotnet
#endif

            return(true);
        }
Example #25
0
 protected CompilerContext(string filePath, StreamReader inputReader, Importer importer, IEmitter emitter, CompilationFlags flags)
 {
     FilePath      = filePath;
     Flags         = flags;
     Emitter       = emitter;
     CompileErrors = new ErrorList();
     Importer      = importer;
     SymbolTable   = new SymbolTable();
     Lexer         = Lexer.Create(inputReader, CompileErrors);
 }
Example #26
0
 protected CompilerContext(string filePath, StreamReader inputReader, IEmitter emitter, CompilationFlags flags)
     : this(filePath, inputReader, new Importer(), emitter, flags)
 {
     _ownsImporter = true;
 }
 /// <summary>
 /// Initializes a new instance of the PeEmitter class.
 /// Use this constructor to when generating an in-memory PE file
 /// </summary>
 /// <param name="flags">Compiler flags</param>
 public PeEmitter(CompilationFlags flags)
     : this(GetPathToTempFile(flags.HasFlag(CompilationFlags.WriteDll) ? "dll" : "exe"), flags)
 {
     _deleteOutputOnClose = true;
 }
        private void EmitInvocationExpression(Expression expr, CompilationFlags flags)
        {
            InvocationExpression node = (InvocationExpression)expr;

            // Optimization: inline code for literal lambda's directly
            //
            // This is worth it because otherwise we end up with a extra call
            // to DynamicMethod.CreateDelegate, which is expensive.
            //
            if (node.LambdaOperand != null)
            {
                EmitInlinedInvoke(node, flags);
                return;
            }

            expr = node.Expression;
            if (typeof(LambdaExpression).IsAssignableFrom(expr.Type))
            {
                // if the invoke target is a lambda expression tree, first compile it into a delegate
                expr = Expression.Call(expr, expr.Type.GetMethod("Compile", Array.Empty<Type>()));
            }
            expr = Expression.Call(expr, expr.Type.GetMethod("Invoke"), node.Arguments);

            EmitExpression(expr);
        }
        private void EmitIndexAssignment(BinaryExpression node, CompilationFlags flags)
        {
            var index = (IndexExpression)node.Left;

            var emitAs = flags & CompilationFlags.EmitAsTypeMask;

            // Emit instance, if calling an instance method
            Type objectType = null;
            if (index.Object != null)
            {
                EmitInstance(index.Object, objectType = index.Object.Type);
            }

            // Emit indexes. We don't allow byref args, so no need to worry
            // about write-backs or EmitAddress
            foreach (var arg in index.Arguments)
            {
                EmitExpression(arg);
            }

            // Emit value
            EmitExpression(node.Right);

            // Save the expression value, if needed
            LocalBuilder temp = null;
            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Stloc, temp = GetLocal(node.Type));
            }

            EmitSetIndexCall(index, objectType);

            // Restore the value
            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                _ilg.Emit(OpCodes.Ldloc, temp);
                FreeLocal(temp);
            }
        }
Example #30
0
        private void EmitMethodCallExpression(Expression expr, CompilationFlags flags = CompilationFlags.EmitAsNoTail)
        {
            var node = (MethodCallExpression)expr;

            EmitMethodCall(node.Object, node.Method, node, flags);
        }
        // assumes 'object' of non-static call is already on stack
        private void EmitMethodCall(MethodInfo mi, IArgumentProvider args, Type objectType, CompilationFlags flags)
        {
            // Emit arguments
            List<WriteBack> wb = EmitArguments(mi, args);

            // Emit the actual call
            OpCode callOp = UseVirtual(mi) ? OpCodes.Callvirt : OpCodes.Call;
            if (callOp == OpCodes.Callvirt && objectType.GetTypeInfo().IsValueType)
            {
                // This automatically boxes value types if necessary.
                _ilg.Emit(OpCodes.Constrained, objectType);
            }
            // The method call can be a tail call if 
            // 1) the method call is the last instruction before Ret
            // 2) the method does not have any ByRef parameters, refer to ECMA-335 Partition III Section 2.4.
            //    "Verification requires that no managed pointers are passed to the method being called, since
            //    it does not track pointers into the current frame."
            if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail && !MethodHasByRefParameter(mi))
            {
                _ilg.Emit(OpCodes.Tailcall);
            }
            if (mi.CallingConvention == CallingConventions.VarArgs)
            {
                int count = args.ArgumentCount;
                Type[] types = new Type[count];
                for (int i = 0; i < count; i++)
                {
                    types[i] = args.GetArgument(i).Type;
                }

                _ilg.EmitCall(callOp, mi, types);
            }
            else
            {
                _ilg.Emit(callOp, mi);
            }

            // Emit write-backs for properties passed as "ref" arguments
            EmitWriteBack(wb);
        }
Example #32
0
        private void EmitMethodCall(Expression?obj, MethodInfo method, IArgumentProvider methodCallExpr, CompilationFlags flags = CompilationFlags.EmitAsNoTail)
        {
            // Emit instance, if calling an instance method
            Type?objectType = null;

            if (!method.IsStatic)
            {
                if (obj == null)
                {
                    throw new ArgumentNullException(nameof(obj));
                }

                EmitInstance(obj, out objectType);
            }

            // if the obj has a value type, its address is passed to the method call so we cannot destroy the
            // stack by emitting a tail call
            if (obj?.Type.IsValueType == true)
            {
                EmitMethodCall(method, methodCallExpr, objectType);
            }
            else
            {
                EmitMethodCall(method, methodCallExpr, objectType, flags);
            }
        }
 private DebugCompilerContext(Importer importer, StreamReader inputReader, CompilationFlags flags)
     : base("fake.iris", inputReader, importer, new PeEmitter(flags), flags)
 {
 }
Example #34
0
        private bool TryEmitHashtableSwitch(SwitchExpression node, CompilationFlags flags)
        {
            // If we have a comparison other than string equality, bail
            MethodInfo equality = String_op_Equality_String_String;

            if (equality != null && !equality.IsStatic)
            {
                equality = null;
            }

            if (node.Comparison != equality)
            {
                return(false);
            }

            // All test values must be constant.
            int tests = 0;

            foreach (SwitchCase c in node.Cases)
            {
                foreach (Expression t in c.TestValues)
                {
                    if (!(t is ConstantExpression))
                    {
                        return(false);
                    }
                    tests++;
                }
            }

            // Must have >= 7 labels for it to be worth it.
            if (tests < 7)
            {
                return(false);
            }

            // If we're in a DynamicMethod, we could just build the dictionary
            // immediately. But that would cause the two code paths to be more
            // different than they really need to be.
            var initializers = new List <ElementInit>(tests);
            var cases        = new ArrayBuilder <SwitchCase>(node.Cases.Count);

            int        nullCase = -1;
            MethodInfo add      = DictionaryOfStringInt32_Add_String_Int32;

            for (int i = 0, n = node.Cases.Count; i < n; i++)
            {
                foreach (ConstantExpression t in node.Cases[i].TestValues)
                {
                    if (t.Value != null)
                    {
                        initializers.Add(Expression.ElementInit(add, new TrueReadOnlyCollection <Expression>(t, Utils.Constant(i))));
                    }
                    else
                    {
                        nullCase = i;
                    }
                }
                cases.UncheckedAdd(Expression.SwitchCase(node.Cases[i].Body, new TrueReadOnlyCollection <Expression>(Utils.Constant(i))));
            }

            // Create the field to hold the lazily initialized dictionary
            MemberExpression dictField = CreateLazyInitializedField <Dictionary <string, int> >("dictionarySwitch");

            // If we happen to initialize it twice (multithreaded case), it's
            // not the end of the world. The C# compiler does better here by
            // emitting a volatile access to the field.
            Expression dictInit = Expression.Condition(
                Expression.Equal(dictField, Expression.Constant(null, dictField.Type)),
                Expression.Assign(
                    dictField,
                    Expression.ListInit(
                        Expression.New(
                            DictionaryOfStringInt32_Ctor_Int32,
                            new TrueReadOnlyCollection <Expression>(
                                Utils.Constant(initializers.Count)
                                )
                            ),
                        initializers
                        )
                    ),
                dictField
                );

            //
            // Create a tree like:
            //
            // switchValue = switchValueExpression;
            // if (switchValue == null) {
            //     switchIndex = nullCase;
            // } else {
            //     if (_dictField == null) {
            //         _dictField = new Dictionary<string, int>(count) { { ... }, ... };
            //     }
            //     if (!_dictField.TryGetValue(switchValue, out switchIndex)) {
            //         switchIndex = -1;
            //     }
            // }
            // switch (switchIndex) {
            //     case 0: ...
            //     case 1: ...
            //     ...
            //     default:
            // }
            //
            ParameterExpression switchValue = Expression.Variable(typeof(string), "switchValue");
            ParameterExpression switchIndex = Expression.Variable(typeof(int), "switchIndex");
            BlockExpression     reduced     = Expression.Block(
                new TrueReadOnlyCollection <ParameterExpression>(switchIndex, switchValue),
                new TrueReadOnlyCollection <Expression>(
                    Expression.Assign(switchValue, node.SwitchValue),
                    Expression.IfThenElse(
                        Expression.Equal(switchValue, Expression.Constant(null, typeof(string))),
                        Expression.Assign(switchIndex, Utils.Constant(nullCase)),
                        Expression.IfThenElse(
                            Expression.Call(dictInit, "TryGetValue", null, switchValue, switchIndex),
                            Utils.Empty,
                            Expression.Assign(switchIndex, Utils.Constant(-1))
                            )
                        ),
                    Expression.Switch(node.Type, switchIndex, node.DefaultBody, null, cases.ToReadOnly())
                    )
                );

            EmitExpression(reduced, flags);
            return(true);
        }
Example #35
0
        /// <summary>
        /// Update the flag with a new EmitExpressionStart flag
        /// </summary>
        private static CompilationFlags UpdateEmitExpressionStartFlag(CompilationFlags flags, CompilationFlags newValue)
        {
            Debug.Assert(newValue == CompilationFlags.EmitExpressionStart || newValue == CompilationFlags.EmitNoExpressionStart);
            CompilationFlags oldValue = flags & CompilationFlags.EmitExpressionStartMask;

            return(flags ^ oldValue | newValue);
        }
Example #36
0
        private void EmitSwitchCases(SwitchExpression node, Label[] labels, bool[] isGoto, Label @default, Label end, CompilationFlags flags)
        {
            // Jump to default (to handle the fallthrough case)
            _ilg.Emit(OpCodes.Br, @default);

            // Emit the cases
            for (int i = 0, n = node.Cases.Count; i < n; i++)
            {
                // If the body is a goto, we already emitted an optimized
                // branch directly to it. No need to emit anything else.
                if (isGoto[i])
                {
                    continue;
                }

                _ilg.MarkLabel(labels[i]);
                EmitExpressionAsType(node.Cases[i].Body, node.Type, flags);

                // Last case doesn't need branch
                if (node.DefaultBody != null || i < n - 1)
                {
                    if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail)
                    {
                        //The switch case is at the tail of the lambda so
                        //it is safe to emit a Ret.
                        _ilg.Emit(OpCodes.Ret);
                    }
                    else
                    {
                        _ilg.Emit(OpCodes.Br, end);
                    }
                }
            }

            // Default value
            if (node.DefaultBody != null)
            {
                _ilg.MarkLabel(@default);
                EmitExpressionAsType(node.DefaultBody, node.Type, flags);
            }

            _ilg.MarkLabel(end);
        }
        private void EmitSwitchExpression(Expression expr, CompilationFlags flags)
        {
            SwitchExpression node = (SwitchExpression)expr;

            if (node.Cases.Count == 0)
            {
                // Emit the switch value in case it has side-effects, but as void
                // since the value is ignored.
                EmitExpressionAsVoid(node.SwitchValue);

                // Now if there is a default body, it happens unconditionally.
                if (node.DefaultBody != null)
                {
                    EmitExpressionAsType(node.DefaultBody, node.Type, flags);
                }
                else
                {
                    // If there are no cases and no default then the type must be void.
                    // Assert that earlier validation caught any exceptions to that.
                    Debug.Assert(node.Type == typeof(void));
                }

                return;
            }

            // Try to emit it as an IL switch. Works for integer types.
            if (TryEmitSwitchInstruction(node, flags))
            {
                return;
            }

            // Try to emit as a hashtable lookup. Works for strings.
            if (TryEmitHashtableSwitch(node, flags))
            {
                return;
            }

            //
            // Fall back to a series of tests. We need to IL gen instead of
            // transform the tree to avoid stack overflow on a big switch.
            //

            var switchValue = Expression.Parameter(node.SwitchValue.Type, "switchValue");
            var testValue   = Expression.Parameter(GetTestValueType(node), "testValue");

            _scope.AddLocal(this, switchValue);
            _scope.AddLocal(this, testValue);

            EmitExpression(node.SwitchValue);
            _scope.EmitSet(switchValue);

            // Emit tests
            var labels = new Label[node.Cases.Count];
            var isGoto = new bool[node.Cases.Count];

            for (int i = 0, n = node.Cases.Count; i < n; i++)
            {
                DefineSwitchCaseLabel(node.Cases[i], out labels[i], out isGoto[i]);
                foreach (Expression test in node.Cases[i].TestValues)
                {
                    // Pull the test out into a temp so it runs on the same
                    // stack as the switch. This simplifies spilling.
                    EmitExpression(test);
                    _scope.EmitSet(testValue);
                    Debug.Assert(TypeUtils.AreReferenceAssignable(testValue.Type, test.Type));
                    EmitExpressionAndBranch(true, Expression.Equal(switchValue, testValue, false, node.Comparison), labels[i]);
                }
            }

            // Define labels
            Label end      = _ilg.DefineLabel();
            Label @default = (node.DefaultBody == null) ? end : _ilg.DefineLabel();

            // Emit the case and default bodies
            EmitSwitchCases(node, labels, isGoto, @default, end, flags);
        }
Example #38
0
        private bool TryEmitHashtableSwitch(SwitchExpression node, CompilationFlags flags)
        {
            // If we have a comparison other than string equality, bail
            if (node.Comparison != typeof(string).GetMethod("op_Equality", BindingFlags.Public | BindingFlags.Static | BindingFlags.ExactBinding, null, new[] { typeof(string), typeof(string) }, null))
            {
                return(false);
            }

            // All test values must be constant.
            int tests = 0;

            foreach (SwitchCase c in node.Cases)
            {
                foreach (Expression t in c.TestValues)
                {
                    if (!(t is ConstantExpression))
                    {
                        return(false);
                    }
                    tests++;
                }
            }

            // Must have >= 7 labels for it to be worth it.
            if (tests < 7)
            {
                return(false);
            }

            // If we're in a DynamicMethod, we could just build the dictionary
            // immediately. But that would cause the two code paths to be more
            // different than they really need to be.
            var initializers = new List <ElementInit>(tests);
            var cases        = new List <SwitchCase>(node.Cases.Count);

            int        nullCase = -1;
            MethodInfo add      = typeof(Dictionary <string, int>).GetMethod("Add", new[] { typeof(string), typeof(int) });

            for (int i = 0, n = node.Cases.Count; i < n; i++)
            {
                foreach (ConstantExpression t in node.Cases[i].TestValues)
                {
                    if (t.Value != null)
                    {
                        initializers.Add(Expression.ElementInit(add, t, Expression.Constant(i)));
                    }
                    else
                    {
                        nullCase = i;
                    }
                }
                cases.Add(Expression.SwitchCase(node.Cases[i].Body, Expression.Constant(i)));
            }

            // Create the field to hold the lazily initialized dictionary
            MemberExpression dictField = CreateLazyInitializedField <Dictionary <string, int> >("dictionarySwitch");

            // If we happen to initialize it twice (multithreaded case), it's
            // not the end of the world. The C# compiler does better here by
            // emitting a volatile access to the field.
            Expression dictInit = Expression.Condition(
                Expression.Equal(dictField, Expression.Constant(null, dictField.Type)),
                Expression.Assign(
                    dictField,
                    Expression.ListInit(
                        Expression.New(
                            typeof(Dictionary <string, int>).GetConstructor(new[] { typeof(int) }),
                            Expression.Constant(initializers.Count)
                            ),
                        initializers
                        )
                    ),
                dictField
                );

            //
            // Create a tree like:
            //
            // switchValue = switchValueExpression;
            // if (switchValue == null) {
            //     switchIndex = nullCase;
            // } else {
            //     if (_dictField == null) {
            //         _dictField = new Dictionary<string, int>(count) { { ... }, ... };
            //     }
            //     if (!_dictField.TryGetValue(switchValue, out switchIndex)) {
            //         switchIndex = -1;
            //     }
            // }
            // switch (switchIndex) {
            //     case 0: ...
            //     case 1: ...
            //     ...
            //     default:
            // }
            //
            var switchValue = Expression.Variable(typeof(string), "switchValue");
            var switchIndex = Expression.Variable(typeof(int), "switchIndex");
            var reduced     = Expression.Block(
                new[] { switchIndex, switchValue },
                Expression.Assign(switchValue, node.SwitchValue),
                Expression.IfThenElse(
                    Expression.Equal(switchValue, Expression.Constant(null, typeof(string))),
                    Expression.Assign(switchIndex, Expression.Constant(nullCase)),
                    Expression.IfThenElse(
                        Expression.Call(dictInit, "TryGetValue", null, switchValue, switchIndex),
                        Expression.Empty(),
                        Expression.Assign(switchIndex, Expression.Constant(-1))
                        )
                    ),
                Expression.Switch(node.Type, switchIndex, node.DefaultBody, null, cases)
                );

            EmitExpression(reduced, flags);
            return(true);
        }
        // Tries to emit switch as a jmp table
        private bool TryEmitSwitchInstruction(SwitchExpression node, CompilationFlags flags)
        {
            // If we have a comparison, bail
            if (node.Comparison != null)
            {
                return(false);
            }

            // Make sure the switch value type and the right side type
            // are types we can optimize
            Type type = node.SwitchValue.Type;

            if (!CanOptimizeSwitchType(type) ||
                !TypeUtils.AreEquivalent(type, node.Cases[0].TestValues[0].Type))
            {
                return(false);
            }

            // Make sure all test values are constant, or we can't emit the
            // jump table.
            if (!node.Cases.All(c => c.TestValues.All(t => t is ConstantExpression)))
            {
                return(false);
            }

            //
            // We can emit the optimized switch, let's do it.
            //

            // Build target labels, collect keys.
            var labels = new Label[node.Cases.Count];
            var isGoto = new bool[node.Cases.Count];

            var uniqueKeys = new HashSet <decimal>();
            var keys       = new List <SwitchLabel>();

            for (int i = 0; i < node.Cases.Count; i++)
            {
                DefineSwitchCaseLabel(node.Cases[i], out labels[i], out isGoto[i]);

                foreach (ConstantExpression test in node.Cases[i].TestValues)
                {
                    // Guaranteed to work thanks to CanOptimizeSwitchType.
                    //
                    // Use decimal because it can hold Int64 or UInt64 without
                    // precision loss or signed/unsigned conversions.
                    decimal key = ConvertSwitchValue(test.Value);

                    // Only add each key once. If it appears twice, it's
                    // allowed, but can't be reached.
                    if (uniqueKeys.Add(key))
                    {
                        keys.Add(new SwitchLabel(key, test.Value, labels[i]));
                    }
                }
            }

            // Sort the keys, and group them into buckets.
            keys.Sort((x, y) => Math.Sign(x.Key - y.Key));
            var buckets = new List <List <SwitchLabel> >();

            foreach (var key in keys)
            {
                AddToBuckets(buckets, key);
            }

            // Emit the switchValue
            LocalBuilder value = GetLocal(node.SwitchValue.Type);

            EmitExpression(node.SwitchValue);
            _ilg.Emit(OpCodes.Stloc, value);

            // Create end label, and default label if needed
            Label end      = _ilg.DefineLabel();
            Label @default = (node.DefaultBody == null) ? end : _ilg.DefineLabel();

            // Emit the switch
            var info = new SwitchInfo(node, value, @default);

            EmitSwitchBuckets(info, buckets, 0, buckets.Count - 1);

            // Emit the case bodies and default
            EmitSwitchCases(node, labels, isGoto, @default, end, flags);

            FreeLocal(value);
            return(true);
        }
        private void EmitExpression(Expression node, CompilationFlags flags)
        {
            Debug.Assert(node != null);

            bool emitStart = (flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart;

            CompilationFlags startEmitted = emitStart ? EmitExpressionStart(node) : CompilationFlags.EmitNoExpressionStart;

            // only pass tail call flags to emit the expression
            flags = flags & CompilationFlags.EmitAsTailCallMask;

            switch (node.NodeType)
            {
                #region Generated Expression Compiler

            // *** BEGIN GENERATED CODE ***
            // generated by function: gen_compiler from: generate_tree.py

            case ExpressionType.Add:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.AddChecked:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.And:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.AndAlso:
                EmitAndAlsoBinaryExpression(node, flags);
                break;

            case ExpressionType.ArrayLength:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.ArrayIndex:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Call:
                EmitMethodCallExpression(node, flags);
                break;

            case ExpressionType.Coalesce:
                EmitCoalesceBinaryExpression(node);
                break;

            case ExpressionType.Conditional:
                EmitConditionalExpression(node, flags);
                break;

            case ExpressionType.Constant:
                EmitConstantExpression(node);
                break;

            case ExpressionType.Convert:
                EmitConvertUnaryExpression(node, flags);
                break;

            case ExpressionType.ConvertChecked:
                EmitConvertUnaryExpression(node, flags);
                break;

            case ExpressionType.Divide:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Equal:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.ExclusiveOr:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.GreaterThan:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.GreaterThanOrEqual:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Invoke:
                EmitInvocationExpression(node, flags);
                break;

            case ExpressionType.Lambda:
                EmitLambdaExpression(node);
                break;

            case ExpressionType.LeftShift:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.LessThan:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.LessThanOrEqual:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.ListInit:
                EmitListInitExpression(node);
                break;

            case ExpressionType.MemberAccess:
                EmitMemberExpression(node);
                break;

            case ExpressionType.MemberInit:
                EmitMemberInitExpression(node);
                break;

            case ExpressionType.Modulo:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Multiply:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.MultiplyChecked:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Negate:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.UnaryPlus:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.NegateChecked:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.New:
                EmitNewExpression(node);
                break;

            case ExpressionType.NewArrayInit:
                EmitNewArrayExpression(node);
                break;

            case ExpressionType.NewArrayBounds:
                EmitNewArrayExpression(node);
                break;

            case ExpressionType.Not:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.NotEqual:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Or:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.OrElse:
                EmitOrElseBinaryExpression(node, flags);
                break;

            case ExpressionType.Parameter:
                EmitParameterExpression(node);
                break;

            case ExpressionType.Power:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Quote:
                EmitQuoteUnaryExpression(node);
                break;

            case ExpressionType.RightShift:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Subtract:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.SubtractChecked:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.TypeAs:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.TypeIs:
                EmitTypeBinaryExpression(node);
                break;

            case ExpressionType.Assign:
                EmitAssignBinaryExpression(node);
                break;

            case ExpressionType.Block:
                EmitBlockExpression(node, flags);
                break;

            case ExpressionType.DebugInfo:
                EmitDebugInfoExpression(node);
                break;

            case ExpressionType.Decrement:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.Dynamic:
                EmitDynamicExpression(node);
                break;

            case ExpressionType.Default:
                EmitDefaultExpression(node);
                break;

            case ExpressionType.Extension:
                EmitExtensionExpression(node);
                break;

            case ExpressionType.Goto:
                EmitGotoExpression(node, flags);
                break;

            case ExpressionType.Increment:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.Index:
                EmitIndexExpression(node);
                break;

            case ExpressionType.Label:
                EmitLabelExpression(node, flags);
                break;

            case ExpressionType.RuntimeVariables:
                EmitRuntimeVariablesExpression(node);
                break;

            case ExpressionType.Loop:
                EmitLoopExpression(node);
                break;

            case ExpressionType.Switch:
                EmitSwitchExpression(node, flags);
                break;

            case ExpressionType.Throw:
                EmitThrowUnaryExpression(node);
                break;

            case ExpressionType.Try:
                EmitTryExpression(node);
                break;

            case ExpressionType.Unbox:
                EmitUnboxUnaryExpression(node);
                break;

            case ExpressionType.TypeEqual:
                EmitTypeBinaryExpression(node);
                break;

            case ExpressionType.OnesComplement:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.IsTrue:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.IsFalse:
                EmitUnaryExpression(node, flags);
                break;

                // *** END GENERATED CODE ***

                #endregion

            default:
                throw ContractUtils.Unreachable;
            }

            if (emitStart)
            {
                EmitExpressionEnd(startEmitted);
            }
        }
 private void EmitAssign(BinaryExpression node, CompilationFlags emitAs)
 {
     switch (node.Left.NodeType)
     {
         case ExpressionType.Index:
             EmitIndexAssignment(node, emitAs);
             return;
         case ExpressionType.MemberAccess:
             EmitMemberAssignment(node, emitAs);
             return;
         case ExpressionType.Parameter:
             EmitVariableAssignment(node, emitAs);
             return;
         default:
             throw Error.InvalidLvalue(node.Left.NodeType);
     }
 }
Example #42
0
        public static TestCompilerContext Create(string compiland, GlobalSymbolList globals, CompilationFlags flags)
        {
#if NETCOREAPP
            flags |= CompilationFlags.NetCore;
#endif

            byte[]       buffer  = Encoding.Default.GetBytes(compiland);
            MemoryStream input   = new MemoryStream(buffer);
            StreamReader reader  = new StreamReader(input);
            MemoryStream output  = new MemoryStream();
            TextEmitter  emitter = new TextEmitter(output);

            TestCompilerContext testContext = new TestCompilerContext(input, reader, output, emitter, flags);
            if (globals != null)
            {
                foreach (var symbol in globals.Items)
                {
                    testContext.SymbolTable.Add(symbol.Item1, symbol.Item2, StorageClass.Global, null);
                }
            }

            return(testContext);
        }
 private void EmitExpressionEnd(CompilationFlags flags)
 {
     if ((flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart)
     {
         PopLabelBlock(_labelBlock.Kind);
     }
 }
Example #44
0
 private void EmitUnaryExpression(Expression expr, CompilationFlags flags)
 {
     EmitUnary((UnaryExpression)expr, flags);
 }
        private void EmitInlinedInvoke(InvocationExpression invoke, CompilationFlags flags)
        {
            var lambda = invoke.LambdaOperand;

            // This is tricky: we need to emit the arguments outside of the
            // scope, but set them inside the scope. Fortunately, using the IL
            // stack it is entirely doable.

            // 1. Emit invoke arguments
            List<WriteBack> wb = EmitArguments(lambda.Type.GetMethod("Invoke"), invoke);

            // 2. Create the nested LambdaCompiler
            var inner = new LambdaCompiler(this, lambda, invoke);

            // 3. Emit the body
            // if the inlined lambda is the last expression of the whole lambda,
            // tail call can be applied.
            if (wb.Count != 0)
            {
                flags = UpdateEmitAsTailCallFlag(flags, CompilationFlags.EmitAsNoTail);
            }
            inner.EmitLambdaBody(_scope, true, flags);

            // 4. Emit write-backs if needed
            EmitWriteBack(wb);
        }
Example #46
0
        private void EmitConvert(UnaryExpression node, CompilationFlags flags)
        {
            if (node.Method != null)
            {
                // User-defined conversions are only lifted if both source and
                // destination types are value types.  The C# compiler gets this wrong.
                // In C#, if you have an implicit conversion from int->MyClass and you
                // "lift" the conversion to int?->MyClass then a null int? goes to a
                // null MyClass.  This is contrary to the specification, which states
                // that the correct behaviour is to unwrap the int?, throw an exception
                // if it is null, and then call the conversion.
                //
                // We cannot fix this in C# but there is no reason why we need to
                // propagate this behavior into the expression tree API.  Unfortunately
                // this means that when the C# compiler generates the lambda
                // (int? i)=>(MyClass)i, we will get different results for converting
                // that lambda to a delegate directly and converting that lambda to
                // an expression tree and then compiling it.  We can live with this
                // discrepancy however.

                if (node.IsLifted && (!node.Type.IsValueType || !node.Operand.Type.IsValueType))
                {
                    var pis = node.Method.GetParameters();
                    Debug.Assert(pis.Length == 1);
                    var paramType = pis[0].ParameterType;
                    if (paramType.IsByRef)
                    {
                        paramType = paramType.GetElementType();
                    }

                    var operand = Expression.Convert(node.Operand, paramType);
                    Debug.Assert(operand.Method == null);

                    node = Expression.Convert(Expression.Call(node.Method, operand), node.Type);

                    Debug.Assert(node.Method == null);
                }
                else
                {
                    EmitUnaryMethod(node, flags);
                    return;
                }
            }

            if (node.Type == typeof(void))
            {
                EmitExpressionAsVoid(node.Operand, flags);
            }
            else
            {
                if (TypeUtils.AreEquivalent(node.Operand.Type, node.Type))
                {
                    EmitExpression(node.Operand, flags);
                }
                else
                {
                    // A conversion is emitted after emitting the operand, no tail call is emitted
                    EmitExpression(node.Operand);
                    IL.EmitConvertToType(node.Operand.Type, node.Type, node.NodeType == ExpressionType.ConvertChecked, this);
                }
            }
        }
 /// <summary>
 /// Update the flag with a new EmitAsTailCall flag
 /// </summary>
 private static CompilationFlags UpdateEmitAsTailCallFlag(CompilationFlags flags, CompilationFlags newValue)
 {
     Debug.Assert(newValue == CompilationFlags.EmitAsTail || newValue == CompilationFlags.EmitAsMiddle || newValue == CompilationFlags.EmitAsNoTail);
     var oldValue = flags & CompilationFlags.EmitAsTailCallMask;
     return flags ^ oldValue | newValue;
 }
Example #48
0
        /// <summary>
        /// Update the flag with a new EmitAsTailCall flag
        /// </summary>
        private static CompilationFlags UpdateEmitAsTailCallFlag(CompilationFlags flags, CompilationFlags newValue)
        {
            Debug.Assert(newValue == CompilationFlags.EmitAsTail || newValue == CompilationFlags.EmitAsMiddle || newValue == CompilationFlags.EmitAsNoTail);
            CompilationFlags oldValue = flags & CompilationFlags.EmitAsTailCallMask;

            return(flags ^ oldValue | newValue);
        }
 private void EmitMethodCall(Expression obj, MethodInfo method, IArgumentProvider methodCallExpr, CompilationFlags flags)
 {
     // Emit instance, if calling an instance method
     Type objectType = null;
     if (!method.IsStatic)
     {
         EmitInstance(obj, objectType = obj.Type);
     }
     // if the obj has a value type, its address is passed to the method call so we cannot destroy the 
     // stack by emitting a tail call
     if (obj != null && obj.Type.GetTypeInfo().IsValueType)
     {
         EmitMethodCall(method, methodCallExpr, objectType);
     }
     else
     {
         EmitMethodCall(method, methodCallExpr, objectType, flags);
     }
 }
Example #50
0
        private void EmitMethodCallExpression(Expression expr, CompilationFlags flags)
        {
            MethodCallExpression node = (MethodCallExpression)expr;

            EmitMethodCall(node.Object, node.Method, node, flags);
        }
 /// <summary>
 /// Update the flag with a new EmitExpressionStart flag
 /// </summary>
 private static CompilationFlags UpdateEmitExpressionStartFlag(CompilationFlags flags, CompilationFlags newValue)
 {
     Debug.Assert(newValue == CompilationFlags.EmitExpressionStart || newValue == CompilationFlags.EmitNoExpressionStart);
     var oldValue = flags & CompilationFlags.EmitExpressionStartMask;
     return flags ^ oldValue | newValue;
 }
Example #52
0
        private void EmitMethodCall(Expression?obj, MethodInfo method, IArgumentProvider methodCallExpr, CompilationFlags flags)
        {
            // Emit instance, if calling an instance method
            Type?objectType = null;

            if (!method.IsStatic)
            {
                Debug.Assert(obj != null);
                EmitInstance(obj, out objectType);
            }
            // if the obj has a value type, its address is passed to the method call so we cannot destroy the
            // stack by emitting a tail call
            if (obj != null && obj.Type.IsValueType)
            {
                EmitMethodCall(method, methodCallExpr, objectType);
            }
            else
            {
                EmitMethodCall(method, methodCallExpr, objectType, flags);
            }
        }
        private void EmitVariableAssignment(BinaryExpression node, CompilationFlags flags)
        {
            var variable = (ParameterExpression)node.Left;
            var emitAs = flags & CompilationFlags.EmitAsTypeMask;

            EmitExpression(node.Right);
            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                _ilg.Emit(OpCodes.Dup);
            }

            if (variable.IsByRef)
            {
                // Note: the stloc/ldloc pattern is a bit suboptimal, but it
                // saves us from having to spill stack when assigning to a
                // byref parameter. We already make this same trade-off for
                // hoisted variables, see ElementStorage.EmitStore

                LocalBuilder value = GetLocal(variable.Type);
                _ilg.Emit(OpCodes.Stloc, value);
                _scope.EmitGet(variable);
                _ilg.Emit(OpCodes.Ldloc, value);
                FreeLocal(value);
                _ilg.EmitStoreValueIndirect(variable.Type);
            }
            else
            {
                _scope.EmitSet(variable);
            }
        }
        private void EmitExpression(Expression node, CompilationFlags flags)
        {
            // When compling deep trees, we run the risk of triggering a terminating StackOverflowException,
            // so we use the StackGuard utility here to probe for sufficient stack and continue the work on
            // another thread when we run out of stack space.
            if (!_guard.TryEnterOnCurrentStack())
            {
                _guard.RunOnEmptyStack((LambdaCompiler @this, Expression n, CompilationFlags f) => @this.EmitExpression(n, f), this, node, flags);
                return;
            }

            Debug.Assert(node != null);

            bool emitStart = (flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart;

            CompilationFlags startEmitted = emitStart ? EmitExpressionStart(node) : CompilationFlags.EmitNoExpressionStart;

            // only pass tail call flags to emit the expression
            flags = flags & CompilationFlags.EmitAsTailCallMask;

            switch (node.NodeType)
            {
                #region Generated Expression Compiler

            // *** BEGIN GENERATED CODE ***
            // generated by function: gen_compiler from: generate_tree.py

            case ExpressionType.Add:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.AddChecked:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.And:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.AndAlso:
                EmitAndAlsoBinaryExpression(node, flags);
                break;

            case ExpressionType.ArrayLength:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.ArrayIndex:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Call:
                EmitMethodCallExpression(node, flags);
                break;

            case ExpressionType.Coalesce:
                EmitCoalesceBinaryExpression(node);
                break;

            case ExpressionType.Conditional:
                EmitConditionalExpression(node, flags);
                break;

            case ExpressionType.Constant:
                EmitConstantExpression(node);
                break;

            case ExpressionType.Convert:
                EmitConvertUnaryExpression(node, flags);
                break;

            case ExpressionType.ConvertChecked:
                EmitConvertUnaryExpression(node, flags);
                break;

            case ExpressionType.Divide:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Equal:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.ExclusiveOr:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.GreaterThan:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.GreaterThanOrEqual:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Invoke:
                EmitInvocationExpression(node, flags);
                break;

            case ExpressionType.Lambda:
                EmitLambdaExpression(node);
                break;

            case ExpressionType.LeftShift:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.LessThan:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.LessThanOrEqual:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.ListInit:
                EmitListInitExpression(node);
                break;

            case ExpressionType.MemberAccess:
                EmitMemberExpression(node);
                break;

            case ExpressionType.MemberInit:
                EmitMemberInitExpression(node);
                break;

            case ExpressionType.Modulo:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Multiply:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.MultiplyChecked:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Negate:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.UnaryPlus:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.NegateChecked:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.New:
                EmitNewExpression(node);
                break;

            case ExpressionType.NewArrayInit:
                EmitNewArrayExpression(node);
                break;

            case ExpressionType.NewArrayBounds:
                EmitNewArrayExpression(node);
                break;

            case ExpressionType.Not:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.NotEqual:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Or:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.OrElse:
                EmitOrElseBinaryExpression(node, flags);
                break;

            case ExpressionType.Parameter:
                EmitParameterExpression(node);
                break;

            case ExpressionType.Power:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Quote:
                EmitQuoteUnaryExpression(node);
                break;

            case ExpressionType.RightShift:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.Subtract:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.SubtractChecked:
                EmitBinaryExpression(node, flags);
                break;

            case ExpressionType.TypeAs:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.TypeIs:
                EmitTypeBinaryExpression(node);
                break;

            case ExpressionType.Assign:
                EmitAssignBinaryExpression(node);
                break;

            case ExpressionType.Block:
                EmitBlockExpression(node, flags);
                break;

            case ExpressionType.DebugInfo:
                EmitDebugInfoExpression(node);
                break;

            case ExpressionType.Decrement:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.Dynamic:
                EmitDynamicExpression(node);
                break;

            case ExpressionType.Default:
                EmitDefaultExpression(node);
                break;

            case ExpressionType.Extension:
                EmitExtensionExpression(node);
                break;

            case ExpressionType.Goto:
                EmitGotoExpression(node, flags);
                break;

            case ExpressionType.Increment:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.Index:
                EmitIndexExpression(node);
                break;

            case ExpressionType.Label:
                EmitLabelExpression(node, flags);
                break;

            case ExpressionType.RuntimeVariables:
                EmitRuntimeVariablesExpression(node);
                break;

            case ExpressionType.Loop:
                EmitLoopExpression(node);
                break;

            case ExpressionType.Switch:
                EmitSwitchExpression(node, flags);
                break;

            case ExpressionType.Throw:
                EmitThrowUnaryExpression(node);
                break;

            case ExpressionType.Try:
                EmitTryExpression(node);
                break;

            case ExpressionType.Unbox:
                EmitUnboxUnaryExpression(node);
                break;

            case ExpressionType.TypeEqual:
                EmitTypeBinaryExpression(node);
                break;

            case ExpressionType.OnesComplement:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.IsTrue:
                EmitUnaryExpression(node, flags);
                break;

            case ExpressionType.IsFalse:
                EmitUnaryExpression(node, flags);
                break;

                // *** END GENERATED CODE ***

                #endregion

            default:
                throw ContractUtils.Unreachable;
            }

            if (emitStart)
            {
                EmitExpressionEnd(startEmitted);
            }
        }
        private void EmitMemberAssignment(BinaryExpression node, CompilationFlags flags)
        {
            MemberExpression lvalue = (MemberExpression)node.Left;
            MemberInfo member = lvalue.Member;

            // emit "this", if any
            Type objectType = null;
            if (lvalue.Expression != null)
            {
                EmitInstance(lvalue.Expression, objectType = lvalue.Expression.Type);
            }

            // emit value
            EmitExpression(node.Right);

            LocalBuilder temp = null;
            var emitAs = flags & CompilationFlags.EmitAsTypeMask;
            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                // save the value so we can return it
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Stloc, temp = GetLocal(node.Type));
            }

            var fld = member as FieldInfo;
            if ((object)fld != null)
            {
                _ilg.EmitFieldSet((FieldInfo)member);
            }
            else
            {
                var prop = member as PropertyInfo;
                if ((object)prop != null)
                {
                    EmitCall(objectType, prop.GetSetMethod(true));
                }
                else
                {
                    throw Error.InvalidMemberType(member);
                }
            }

            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                _ilg.Emit(OpCodes.Ldloc, temp);
                FreeLocal(temp);
            }
        }
        private static bool TryParseArgs(string[] args, out string sourceFile, out CompilationFlags flags)
        {
            sourceFile = null;
            flags      = 0;
            if (args.Length < 1)
            {
                return(false);
            }

            foreach (string arg in args)
            {
                string normalizedArg = arg.ToUpper();
                switch (normalizedArg)
                {
                case "/32":
                    flags |= CompilationFlags.Platform32;
                    break;

                case "/64":
                    flags |= CompilationFlags.Platform64;
                    break;

                case "/NODEBUG":
                    flags |= CompilationFlags.NoDebug;
                    break;

                case "/ASM":
                    flags |= CompilationFlags.Assembly;
                    break;

                default:
                    if (normalizedArg.StartsWith("/"))
                    {
                        Console.WriteLine("Unrecognized option {0}", normalizedArg);
                        return(false);
                    }
                    if (!File.Exists(arg))
                    {
                        Console.WriteLine("Source file '{0}' not found", arg);
                        return(false);
                    }
                    if (sourceFile != null)
                    {
                        Console.WriteLine("Multiple source files specified.  Only one file is supported");
                        return(false);
                    }
                    sourceFile = arg;
                    break;
                }
            }

            if (flags.HasFlag(CompilationFlags.Platform32) && flags.HasFlag(CompilationFlags.Platform64))
            {
                Console.WriteLine("Both 32-bit and 64-bit platforms specified.  Only one platform is supported");
                return(false);
            }

            if (!flags.HasFlag(CompilationFlags.Platform32) && !flags.HasFlag(CompilationFlags.Platform64))
            {
                flags |= CompilationFlags.Platform32;
            }

            if (sourceFile == null)
            {
                return(false);
            }

            return(true);
        }