示例#1
0
            internal override Expression AsExpression(Expression target)
            {
                RequireNoValueProperty();

                Expression member     = MemberExpression.Make(target, _binding.Member);
                Expression memberTemp = _spiller.MakeTemp(member.Type);

                int count = _inits.Count;

                Expression[] block = new Expression[count + 2];
                block[0] = new AssignBinaryExpression(memberTemp, member);

                for (int i = 0; i < count; i++)
                {
                    ChildRewriter cr  = _childRewriters[i];
                    Result        add = cr.Finish(new InstanceMethodCallExpressionN(_inits[i].AddMethod, memberTemp, cr[0, -1]));
                    block[i + 1] = add.Node;
                }

                // We need to copy back value types
                if (memberTemp.Type.IsValueType)
                {
                    block[count + 1] = Expression.Block(
                        typeof(void),
                        new AssignBinaryExpression(MemberExpression.Make(target, _binding.Member), memberTemp)
                        );
                }
                else
                {
                    block[count + 1] = Utils.Empty;
                }

                return(MakeBlock(block));
            }
示例#2
0
            internal override Expression AsExpression(Expression target)
            {
                RequireNoValueProperty();

                Expression member     = MemberExpression.Make(target, _binding.Member);
                Expression memberTemp = _spiller.MakeTemp(member.Type);

                int count = _bindings.Count;

                Expression[] block = new Expression[count + 2];
                block[0] = new AssignBinaryExpression(memberTemp, member);

                for (int i = 0; i < count; i++)
                {
                    BindingRewriter br = _bindingRewriters[i];
                    block[i + 1] = br.AsExpression(memberTemp);
                }

                // We need to copy back value types.
                if (memberTemp.Type.IsValueType)
                {
                    block[count + 1] = Expression.Block(
                        typeof(void),
                        new AssignBinaryExpression(MemberExpression.Make(target, _binding.Member), memberTemp)
                        );
                }
                else
                {
                    block[count + 1] = Utils.Empty;
                }

                return(MakeBlock(block));
            }
示例#3
0
        private Result RewriteIndexAssignment(BinaryExpression node, Stack stack)
        {
            var index = (IndexExpression)node.Left;

            var cr = new ChildRewriter(this, stack, 2 + index.ArgumentCount);

            cr.Add(index.Object);
            cr.AddArguments(index);
            cr.Add(node.Right);

            if (cr.Action == RewriteAction.SpillStack)
            {
                cr.MarkRefInstance(index.Object);
            }

            if (cr.Rewrite)
            {
                node = new AssignBinaryExpression(
                    new IndexExpression(
                        cr[0],                              // Object
                        index.Indexer,
                        cr[1, -2]                           // arguments
                        ),
                    cr[-1]                                  // value
                    );
            }

            return(cr.Finish(node));
        }
示例#4
0
        private Result RewriteMemberInitExpression(Expression expr, Stack stack)
        {
            var node = (MemberInitExpression)expr;

            // Constructor runs on initial stack.
            Result        result       = RewriteExpression(node.NewExpression, stack);
            Expression    rewrittenNew = result.Node;
            RewriteAction action       = result.Action;

            ReadOnlyCollection <MemberBinding> bindings = node.Bindings;

            BindingRewriter[] bindingRewriters = new BindingRewriter[bindings.Count];

            for (int i = 0; i < bindings.Count; i++)
            {
                MemberBinding binding = bindings[i];

                // Bindings run on non-empty stack (the object instance is on it).
                BindingRewriter rewriter = BindingRewriter.Create(binding, this, Stack.NonEmpty);
                bindingRewriters[i] = rewriter;

                action |= rewriter.Action;
            }

            switch (action)
            {
            case RewriteAction.None:
                break;

            case RewriteAction.Copy:
                MemberBinding[] newBindings = new MemberBinding[bindings.Count];
                for (int i = 0; i < bindings.Count; i++)
                {
                    newBindings[i] = bindingRewriters[i].AsBinding();
                }
                expr = new MemberInitExpression((NewExpression)rewrittenNew, new TrueReadOnlyCollection <MemberBinding>(newBindings));
                break;

            case RewriteAction.SpillStack:
                RequireNotRefInstance(node.NewExpression);

                ParameterExpression tempNew = MakeTemp(rewrittenNew.Type);
                Expression[]        comma   = new Expression[bindings.Count + 2];
                comma[0] = new AssignBinaryExpression(tempNew, rewrittenNew);
                for (int i = 0; i < bindings.Count; i++)
                {
                    BindingRewriter cr       = bindingRewriters[i];
                    Expression      initExpr = cr.AsExpression(tempNew);
                    comma[i + 1] = initExpr;
                }
                comma[bindings.Count + 1] = tempNew;
                expr = MakeBlock(comma);
                break;

            default:
                throw ContractUtils.Unreachable;
            }
            return(new Result(action, expr));
        }
示例#5
0
        private Result RewriteExtensionAssignment(BinaryExpression node, Stack stack)
        {
            node = new AssignBinaryExpression(node.Left.ReduceExtensions(), node.Right);
            Result result = RewriteAssignBinaryExpression(node, stack);

            // it's at least Copy because we reduced the node
            return(new Result(result.Action | RewriteAction.Copy, result.Node));
        }
示例#6
0
        /// <summary>
        ///     Creates and returns a temporary variable to store the result of evaluating
        ///     the specified <paramref name="expression" />.
        /// </summary>
        /// <param name="expression">The expression to store in a temporary variable.</param>
        /// <param name="save">An expression that assigns the <paramref name="expression" /> to the created temporary variable.</param>
        /// <param name="byRef">Indicates whether the <paramref name="expression" /> represents a ByRef value.</param>
        /// <returns>The temporary variable holding the result of evaluating <paramref name="expression" />.</returns>
        private ParameterExpression ToTemp(Expression expression, out Expression save, bool byRef)
        {
            var tempType = byRef ? expression.Type.MakeByRefType() : expression.Type;
            var temp     = MakeTemp(tempType);

            save = AssignBinaryExpression.Make(temp, expression, byRef);
            return(temp);
        }
示例#7
0
        // variable assignment
        private Result RewriteVariableAssignment(BinaryExpression node, Stack stack)
        {
            // Expression is evaluated on a stack in current state
            Result right = RewriteExpression(node.Right, stack);

            if (right.Action != RewriteAction.None)
            {
                node = new AssignBinaryExpression(node.Left, right.Node);
            }
            return(new Result(right.Action, node));
        }
示例#8
0
        private void EmitMemberAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            Debug.Assert(!node.IsByRef);

            var lvalue = (MemberExpression)node.Left;
            var member = lvalue.Member;

            // emit "this", if any
            Type?objectType = null;

            if (lvalue.Expression != null)
            {
                EmitInstance(lvalue.Expression, out objectType);
            }

            // 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
                IL.Emit(OpCodes.Dup);
                temp = GetLocal(node.Type);
                IL.Emit(OpCodes.Stloc, temp);
            }

            if (member is FieldInfo info)
            {
                IL.EmitFieldSet(info);
            }
            else
            {
                // MemberExpression.Member can only be a FieldInfo or a PropertyInfo
                Debug.Assert(member is PropertyInfo);
                var prop = (PropertyInfo)member;
                EmitCall(objectType, prop.GetSetMethod(true));
            }

            if (temp == null)
            {
                return;
            }

            IL.Emit(OpCodes.Ldloc, temp);
            FreeLocal(temp);
        }
示例#9
0
        private void EmitIndexAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            Debug.Assert(!node.IsByRef);

            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, out objectType);
            }

            // Emit indexes. We don't allow byref args, so no need to worry
            // about writebacks or EmitAddress
            for (int i = 0, n = index.ArgumentCount; i < n; i++)
            {
                var arg = index.GetArgument(i);
                EmitExpression(arg);
            }

            // Emit value
            EmitExpression(node.Right);

            // Save the expression value, if needed
            LocalBuilder?temp = null;

            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                IL.Emit(OpCodes.Dup);
                temp = GetLocal(node.Type);
                IL.Emit(OpCodes.Stloc, temp);
            }

            EmitSetIndexCall(index, objectType);

            // Restore the value
            if (temp == null)
            {
                return;
            }

            IL.Emit(OpCodes.Ldloc, temp);
            FreeLocal(temp);
        }
示例#10
0
        private void EmitMemberAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            Debug.Assert(!node.IsByRef);

            MemberExpression lvalue = (MemberExpression)node.Left;
            MemberInfo       member = lvalue.Member;

            // emit "this", if any
            Type objectType = null;

            if (lvalue.Expression != null)
            {
                EmitInstance(lvalue.Expression, out objectType);
            }

            // emit value
            EmitExpression(node.Right);

            LocalBuilder     temp   = null;
            CompilationFlags 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));
            }

            if (member is FieldInfo info)
            {
                _ilg.EmitFieldSet(info);
            }
            else
            {
                // MemberExpression.Member can only be a FieldInfo or a PropertyInfo
                Debug.Assert(member is PropertyInfo);
                var prop = (PropertyInfo)member;
                EmitCall(objectType, prop.GetSetMethod(nonPublic: true));
            }

            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                // ReSharper disable once AssignNullToNotNullAttribute
                _ilg.Emit(OpCodes.Ldloc, temp);
                FreeLocal(temp);
            }
        }
示例#11
0
        private void EmitAssign(AssignBinaryExpression 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);
            }
        }
示例#12
0
        private void EmitAssign(AssignBinaryExpression 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 ContractUtils.Unreachable;
            }
        }
示例#13
0
        private void EmitVariableAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            var variable            = (ParameterExpression)node.Left;
            CompilationFlags emitAs = flags & CompilationFlags.EmitAsTypeMask;

            if (node.IsByRef)
            {
                EmitAddress(node.Right, node.Right.Type);
            }
            else
            {
                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);
            }
        }
示例#14
0
        private Result RewriteIndexAssignment(BinaryExpression node, Stack stack)
        {
            IndexExpression index = (IndexExpression)node.Left;

            ChildRewriter cr = new ChildRewriter(this, stack, 2 + index.Arguments.Count);

            cr.Add(index.Object);
            cr.Add(index.Arguments);
            cr.Add(node.Right);

            if (cr.Rewrite)
            {
                node = new AssignBinaryExpression(
                    new IndexExpression(
                        cr[0],                              // Object
                        index.Indexer,
                        cr[1, -2]                           // arguments
                        ),
                    cr[-1]                                  // value
                    );
            }

            return(cr.Finish(node));
        }
示例#15
0
        private Result RewriteArrayIndexAssignment(BinaryExpression node, Stack stack)
        {
            Debug.Assert(node.NodeType == ExpressionType.ArrayIndex);
            BinaryExpression arrayIndex = (BinaryExpression)node.Left;

            ChildRewriter cr = new ChildRewriter(this, stack, 3);

            cr.Add(arrayIndex.Left);
            cr.Add(arrayIndex.Right);
            cr.Add(node.Right);

            if (cr.Rewrite)
            {
                node = new AssignBinaryExpression(
                    Expression.ArrayIndex(
                        cr[0],   // array
                        cr[1]    // index
                        ),
                    cr[2]        // value
                    );
            }

            return(cr.Finish(node));
        }
示例#16
0
 private void EmitAssign(AssignBinaryExpression 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);
     }
 }
示例#17
0
        private void EmitIndexAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            Debug.Assert(!node.IsByRef);

            var index = (IndexExpression)node.Left;

            CompilationFlags emitAs = flags & CompilationFlags.EmitAsTypeMask;

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

            // Emit indexes. We don't allow byref args, so no need to worry
            // about write-backs or EmitAddress
            for (int i = 0, n = index.ArgumentCount; i < n; i++)
            {
                Expression arg = index.GetArgument(i);
                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);
            }
        }
示例#18
0
        private void EmitMemberAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            Debug.Assert(!node.IsByRef);

            MemberExpression lvalue = (MemberExpression)node.Left;
            MemberInfo member = lvalue.Member;

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

            // emit value
            EmitExpression(node.Right);

            LocalBuilder temp = null;
            CompilationFlags 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
            {
                // MemberExpression.Member can only be a FieldInfo or a PropertyInfo
                Debug.Assert(member is PropertyInfo);
                var prop = (PropertyInfo)member;
                EmitCall(objectType, prop.GetSetMethod(nonPublic: true));
            }

            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                _ilg.Emit(OpCodes.Ldloc, temp);
                FreeLocal(temp);
            }
        }
示例#19
0
        // RewriteListInitExpression
        private Result RewriteListInitExpression(Expression expr, Stack stack)
        {
            ListInitExpression node = (ListInitExpression)expr;

            //ctor runs on initial stack
            Result        newResult    = RewriteExpression(node.NewExpression, stack);
            Expression    rewrittenNew = newResult.Node;
            RewriteAction action       = newResult.Action;

            ReadOnlyCollection <ElementInit> inits = node.Initializers;

            ChildRewriter[] cloneCrs = new ChildRewriter[inits.Count];

            for (int i = 0; i < inits.Count; i++)
            {
                ElementInit init = inits[i];

                //initializers all run on nonempty stack
                ChildRewriter cr = new ChildRewriter(this, Stack.NonEmpty, init.Arguments.Count);
                cr.Add(init.Arguments);

                action     |= cr.Action;
                cloneCrs[i] = cr;
            }

            switch (action)
            {
            case RewriteAction.None:
                break;

            case RewriteAction.Copy:
                ElementInit[] newInits = new ElementInit[inits.Count];
                for (int i = 0; i < inits.Count; i++)
                {
                    ChildRewriter cr = cloneCrs[i];
                    if (cr.Action == RewriteAction.None)
                    {
                        newInits[i] = inits[i];
                    }
                    else
                    {
                        newInits[i] = new ElementInit(inits[i].AddMethod, new TrueReadOnlyCollection <Expression>(cr[0, -1]));
                    }
                }
                expr = new ListInitExpression((NewExpression)rewrittenNew, new TrueReadOnlyCollection <ElementInit>(newInits));
                break;

            case RewriteAction.SpillStack:
                RequireNotRefInstance(node.NewExpression);

                ParameterExpression tempNew = MakeTemp(rewrittenNew.Type);
                Expression[]        comma   = new Expression[inits.Count + 2];
                comma[0] = new AssignBinaryExpression(tempNew, rewrittenNew);

                for (int i = 0; i < inits.Count; i++)
                {
                    ChildRewriter cr  = cloneCrs[i];
                    Result        add = cr.Finish(new InstanceMethodCallExpressionN(inits[i].AddMethod, tempNew, cr[0, -1]));
                    comma[i + 1] = add.Node;
                }
                comma[inits.Count + 1] = tempNew;
                expr = MakeBlock(comma);
                break;

            default:
                throw ContractUtils.Unreachable;
            }

            return(new Result(action, expr));
        }
示例#20
0
        private void EmitVariableAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            var variable = (ParameterExpression)node.Left;
            CompilationFlags emitAs = flags & CompilationFlags.EmitAsTypeMask;

            if (node.IsByRef)
            {
                EmitAddress(node.Right, node.Right.Type);
            }
            else
            {
                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);
            }
        }
            internal override Expression AsExpression(Expression target)
            {
                RequireNoValueProperty();
                RequireNotRefInstance(target);

                Expression member = MemberExpression.Make(target, _binding.Member);
                Expression memberTemp = _spiller.MakeTemp(member.Type);

                Expression[] block = new Expression[_inits.Count + 2];
                block[0] = new AssignBinaryExpression(memberTemp, member);

                for (int i = 0; i < _inits.Count; i++)
                {
                    ChildRewriter cr = _childRewriters[i];
                    Result add = cr.Finish(new InstanceMethodCallExpressionN(_inits[i].AddMethod, memberTemp, cr[0, -1]));
                    block[i + 1] = add.Node;
                }

                // We need to copy back value types
                if (memberTemp.Type.GetTypeInfo().IsValueType)
                {
                    block[_inits.Count + 1] = Expression.Block(
                        typeof(void),
                        new AssignBinaryExpression(MemberExpression.Make(target, _binding.Member), memberTemp)
                    );
                }
                else
                {
                    block[_inits.Count + 1] = Utils.Empty();
                }
                return MakeBlock(block);
            }
            internal override Expression AsExpression(Expression target)
            {
                RequireNoValueProperty();
                RequireNotRefInstance(target);

                Expression member = MemberExpression.Make(target, _binding.Member);
                Expression memberTemp = _spiller.MakeTemp(member.Type);

                Expression[] block = new Expression[_bindings.Count + 2];
                block[0] = new AssignBinaryExpression(memberTemp, member);

                for (int i = 0; i < _bindings.Count; i++)
                {
                    BindingRewriter br = _bindingRewriters[i];
                    block[i + 1] = br.AsExpression(memberTemp);
                }

                // We need to copy back value types
                if (memberTemp.Type.GetTypeInfo().IsValueType)
                {
                    block[_bindings.Count + 1] = Expression.Block(
                        typeof(void),
                        new AssignBinaryExpression(MemberExpression.Make(target, _binding.Member), memberTemp)
                    );
                }
                else
                {
                    block[_bindings.Count + 1] = Utils.Empty();
                }
                return MakeBlock(block);
            }