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.Action == RewriteAction.SpillStack) { #if LINQ RequireNotRefInstance(index.Object); #else MarkRefInstance(cr, index.Object); #endif } if (cr.Rewrite) { node = CreateAssignBinaryExpression( CreateIndexExpression( cr[0], // Object index.Indexer, cr[1, -2] // arguments ), cr[-1] // value ); } return(cr.Finish(node)); }
//RewriteIndexExpression private Result RewriteIndexExpression(Expression expr, Stack stack) { var node = (IndexExpression)expr; var cr = new ChildRewriter(this, stack, node.Arguments.Count + 1); // For instance methods, the instance executes on the // stack as is, but stays on the stack, making it non-empty. cr.Add(node.Object); cr.Add(node.Arguments); if (cr.Action == RewriteAction.SpillStack) { RequireNotRefInstance(node.Object); } if (cr.Rewrite) { expr = new IndexExpression( cr[0], node.Indexer, cr[1, -1] ); } return(cr.Finish(expr)); }
private Result RewriteMemberAssignment(BinaryExpression node, Stack stack) { var lvalue = (MemberExpression)node.Left; var cr = new ChildRewriter(this, stack, 2); // If there's an instance, it executes on the stack in current state // and rest is executed on non-empty stack. // Otherwise the stack is left unchanged. cr.Add(lvalue.Expression); cr.Add(node.Right); if (cr.Action == RewriteAction.SpillStack) { cr.MarkRefInstance(lvalue.Expression); } if (cr.Rewrite) { return(cr.Finish( new AssignBinaryExpression( MemberExpression.Make(cr[0], lvalue.Member), cr[1] ) )); } return(new Result(RewriteAction.None, node)); }
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)); }
private Result RewriteBinaryExpression(Expression expr, Stack stack) { var node = (BinaryExpression)expr; var cr = new ChildRewriter(this, stack, 3); // Left expression executes on the stack as left by parent cr.Add(node.Left); // Right expression always has non-empty stack (left is on it) cr.Add(node.Right); // conversion is a lambda, stack state will be ignored cr.Add(node.Conversion); if (cr.Action == RewriteAction.SpillStack) { RequireNoRefArgs(node.Method); } return(cr.Finish(cr.Rewrite ? BinaryExpression.Create( node.NodeType, cr[0] !, cr[1] !, node.Type, node.Method, (LambdaExpression?)cr[2]) : expr)); }
// InvocationExpression private Result RewriteInvocationExpression(Expression expr, Stack stack) { InvocationExpression node = (InvocationExpression)expr; ChildRewriter cr; #if LINQ // NB: Our compiler doesn't inline; this could still happen at a later stage in the LINQ compiler after lowering async lambdas to sync ones. // See if the lambda will be inlined LambdaExpression lambda = node.LambdaOperand(); if (lambda != null) { // Arguments execute on current stack cr = new ChildRewriter(this, stack, node.Arguments.Count); cr.Add(node.Arguments); if (cr.Action == RewriteAction.SpillStack) { RequireNoRefArgs(ExpressionStubs.GetInvokeMethod(node.Expression)); } // Lambda body also executes on current stack var spiller = new StackSpiller(stack); lambda = lambda.Accept(spiller); if (cr.Rewrite || spiller._lambdaRewrite != RewriteAction.None) { node = node.Rewrite(lambda, cr[0, -1]); } Result result = cr.Finish(node); return(new Result(result.Action | spiller._lambdaRewrite, result.Node)); } #endif cr = new ChildRewriter(this, stack, node.Arguments.Count + 1); // first argument starts on stack as provided cr.Add(node.Expression); // rest of arguments have non-empty stack (delegate instance on the stack) cr.Add(node.Arguments); if (cr.Action == RewriteAction.SpillStack) { #if LINQ RequireNoRefArgs(ExpressionStubs.GetInvokeMethod(node.Expression)); #else MarkRefArgs(cr, ExpressionStubs.GetInvokeMethod(node.Expression), 1); #endif } return(cr.Finish(cr.Rewrite ? node.Rewrite(cr[0], cr[1, -1]) : expr)); }
// MethodCallExpression // TODO: ref parameters!!! private Result RewriteMethodCallExpression(Expression expr, Stack stack) { MethodCallExpression node = (MethodCallExpression)expr; ChildRewriter cr = new ChildRewriter(this, stack, node.Arguments.Count + 1); // For instance methods, the instance executes on the // stack as is, but stays on the stack, making it non-empty. cr.Add(node.Object); cr.Add(node.Arguments); return(cr.Finish(cr.Rewrite ? node.Rewrite(cr[0], cr[1, -1]) : expr)); }
// InvocationExpression private Result RewriteInvocationExpression(Expression expr, Stack stack) { InvocationExpression node = (InvocationExpression)expr; // first argument starts on stack as provided ChildRewriter cr = new ChildRewriter(this, stack, node.Arguments.Count + 1); cr.Add(node.Expression); // rest of arguments have non-empty stack (delegate instance on the stack) cr.Add(node.Arguments); return(cr.Finish(cr.Rewrite ? new InvocationExpression(cr[0], cr[1, -1], node.Type) : expr)); }
// InvocationExpression private Result RewriteInvocationExpression(Expression expr, Stack stack) { var node = (InvocationExpression)expr; ChildRewriter cr; // See if the lambda will be inlined var lambda = node.LambdaOperand; if (lambda != null) { // Arguments execute on current stack cr = new ChildRewriter(this, stack, node.Arguments.Count); cr.Add(node.Arguments); if (cr.Action == RewriteAction.SpillStack) { RequireNoRefArgs(Expression.GetInvokeMethod(node.Expression)); } // Lambda body also executes on current stack var spiller = new StackSpiller(stack); lambda = lambda.Accept(spiller); if (cr.Rewrite || spiller._lambdaRewrite != RewriteAction.None) { node = new InvocationExpression(lambda, cr[0, -1], node.Type); } var result = cr.Finish(node); return(new Result(result.Action | spiller._lambdaRewrite, result.Node)); } cr = new ChildRewriter(this, stack, node.Arguments.Count + 1); // first argument starts on stack as provided cr.Add(node.Expression); // rest of arguments have non-empty stack (delegate instance on the stack) cr.Add(node.Arguments); if (cr.Action == RewriteAction.SpillStack) { RequireNoRefArgs(Expression.GetInvokeMethod(node.Expression)); } return(cr.Finish(cr.Rewrite ? new InvocationExpression(cr[0], cr[1, -1], node.Type) : expr)); }
// MethodCallExpression private Result RewriteMethodCallExpression(Expression expr, Stack stack) { MethodCallExpression node = (MethodCallExpression)expr; ChildRewriter cr = new ChildRewriter(this, stack, node.Arguments.Count + 1); // For instance methods, the instance executes on the // stack as is, but stays on the stack, making it non-empty. cr.Add(node.Object); cr.AddArguments(node); if (cr.Action == RewriteAction.SpillStack) { #if LINQ RequireNotRefInstance(node.Object); RequireNoRefArgs(node.Method); #else MarkRefInstance(cr, node.Object); MarkRefArgs(cr, node.Method, 1); #endif } return(cr.Finish(cr.Rewrite ? node.Rewrite(cr[0], cr[1, -1]) : expr)); }
private Result RewriteNewArrayExpression(Expression expr, Stack stack) { var node = (NewArrayExpression)expr; if (node.NodeType == ExpressionType.NewArrayInit) { // In a case of array construction with element initialization // the element expressions are never emitted on an empty stack because // the array reference and the index are on the stack. stack = Stack.NonEmpty; } else { // In a case of NewArrayBounds we make no modifications to the stack // before emitting bounds expressions. } var cr = new ChildRewriter(this, stack, node.Expressions.Count); cr.Add(node.Expressions); if (cr.Rewrite) { expr = NewArrayExpression.Make(node.NodeType, node.Type, new TrueReadOnlyCollection <Expression>(cr[0, -1])); } return(cr.Finish(expr)); }
private Result RewriteMethodCallExpression(Expression expr, Stack stack) { MethodCallExpression node = (MethodCallExpression)expr; var cr = new ChildRewriter(this, stack, node.ArgumentCount + 1); // For instance methods, the instance executes on the // stack as is, but stays on the stack, making it non-empty. cr.Add(node.Object); cr.AddArguments(node); if (cr.Action == RewriteAction.SpillStack) { cr.MarkRefInstance(node.Object); cr.MarkRefArgs(node.Method, startIndex: 1); } if (cr.Rewrite) { if (node.Object != null) { expr = new InstanceMethodCallExpressionN(node.Method, cr[0], cr[1, -1]); } else { expr = new MethodCallExpressionN(node.Method, cr[1, -1]); } } return(cr.Finish(expr)); }
private Result RewriteMemberExpression(Expression expr, Stack stack) { MemberExpression node = (MemberExpression)expr; ChildRewriter cr = new ChildRewriter(this, stack, 1); cr.Add(node.Expression); if (cr.Rewrite) { if (cr.Action == RewriteAction.SpillStack && node.Member is PropertyInfo) { // Only need to validate propreties because reading a field // is always side-effect free. #if LINQ RequireNotRefInstance(node.Expression); #else MarkRefInstance(cr, node.Expression); #endif } expr = MemberExpressionStubs.Make(cr[0], node.Member); } return(cr.Finish(expr)); }
// NewArrayExpression private Result RewriteNewArrayExpression(Expression expr, Stack stack) { var node = (NewArrayExpression)expr; if (node.NodeType == ExpressionType.NewArrayInit) { // In a case of array construction with element initialization // the element expressions are never emitted on an empty stack because // the array reference and the index are on the stack. stack = Stack.NonEmpty; } var cr = new ChildRewriter(this, stack, node.Expressions.Count); cr.Add(node.Expressions); if (cr.Rewrite) { var element = node.Type.GetElementType(); if (node.NodeType == ExpressionType.NewArrayInit) { expr = Expression.NewArrayInit(element, cr[0, -1]); } else { expr = Expression.NewArrayBounds(element, cr[0, -1]); } } return(cr.Finish(expr)); }
// NewExpression private Result RewriteNewExpression(Expression expr, Stack stack) { NewExpression node = (NewExpression)expr; // The first expression starts on a stack as provided by parent, // rest are definitely non-emtpy (which ChildRewriter guarantees) ChildRewriter cr = new ChildRewriter(this, stack, node.Arguments.Count); cr.Add(node.Arguments); return(cr.Finish(cr.Rewrite ? new NewExpression(node.Constructor, cr[0, -1], node.Members) : expr)); }
private Result RewriteAwaitExpression(Expression expr, Stack stack) { var node = (AwaitCSharpExpression)expr; ChildRewriter cr = new ChildRewriter(this, stack, 1); cr.Add(node.Operand); // NB: We always spill the stack for await, so unconditionally rewrite. var res = cr.Finish(node.Rewrite(cr[0])); return new Result(RewriteAction.SpillStack, res.Node); }
// BinaryExpression private Result RewriteBinaryExpression(Expression expr, Stack stack) { BinaryExpression node = (BinaryExpression)expr; ChildRewriter cr = new ChildRewriter(this, stack, 3); // Left expression executes on the stack as left by parent cr.Add(node.Left); // Right expression always has non-empty stack (left is on it) cr.Add(node.Right); // conversion is a lambda, stack state will be ignored cr.Add(node.Conversion); return(cr.Finish(cr.Rewrite ? BinaryExpression.Create( node.NodeType, cr[0], cr[1], node.Type, node.Method, (LambdaExpression)cr[2]) : expr)); }
private Result RewriteAwaitExpression(Expression expr, Stack stack) { var node = (AwaitCSharpExpression)expr; ChildRewriter cr = new ChildRewriter(this, stack, 1); cr.Add(node.Operand); // NB: We always spill the stack for await, so unconditionally rewrite. var res = cr.Finish(node.Rewrite(cr[0], node.Info)); return(new Result(RewriteAction.SpillStack, res.Node)); }
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)); }
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)); }
private Result RewriteDynamicExpression(Expression expr, Stack stack) { var node = (DynamicExpression)expr; // CallSite is on the stack IArgumentProvider argNode = (IArgumentProvider)node; int argCount = argNode.ArgumentCount; ChildRewriter cr = new ChildRewriter(this, Stack.NonEmpty, argCount); for (int i = 0; i < argCount; i++) { cr.Add(argNode.GetArgument(i)); } return(cr.Finish(cr.Rewrite ? node.Rewrite(cr[0, -1]) : expr)); }
internal ListBindingRewriter(MemberListBinding binding, StackSpiller spiller, Stack stack) : base(binding, spiller) { _inits = binding.Initializers; _childRewriters = new ChildRewriter[_inits.Count]; for (int i = 0; i < _inits.Count; i++) { ElementInit init = _inits[i]; ChildRewriter cr = new ChildRewriter(spiller, stack, init.Arguments.Count); cr.Add(init.Arguments); _action |= cr.Action; _childRewriters[i] = cr; } }
internal ListBindingRewriter(MemberListBinding memberBinding, StackSpiller stackSpiller, Stack stack) : base(memberBinding, stackSpiller) { _inits = memberBinding.Initializers; _childRewriters = new ChildRewriter[_inits.Count]; for (var i = 0; i < _inits.Count; i++) { var init = _inits[i]; var cr = new ChildRewriter(stackSpiller, stack, init.Arguments.Count); cr.Add(init.Arguments); RewriteAction |= cr.Action; _childRewriters[i] = cr; } }
internal ListBindingRewriter(MemberListBinding binding, StackSpiller spiller, Stack stack) : base(binding, spiller) { _initializers = binding.Initializers; var count = _initializers.Count; _childRewriters = new ChildRewriter[count]; for (var i = 0; i < count; i++) { var init = _initializers[i]; var cr = new ChildRewriter(spiller, stack, init.Arguments.Count); cr.Add(init.Arguments); Action |= cr.Action; _childRewriters[i] = cr; } }
private Result RewriteTypeBinaryExpression(Expression expr, Stack stack) { TypeBinaryExpression node = (TypeBinaryExpression)expr; ChildRewriter cr = new ChildRewriter(this, stack, 1); cr.Add(node.Expression); if (cr.Rewrite) { if (node.NodeType == ExpressionType.TypeIs) { expr = Expression.TypeIs(cr[0], node.TypeOperand); } else { expr = Expression.TypeEqual(cr[0], node.TypeOperand); } } return(cr.Finish(expr)); }
private Result RewriteUnaryExpression(Expression expr, Stack stack) { UnaryExpression node = (UnaryExpression)expr; Debug.Assert(node.NodeType != ExpressionType.Quote, "unexpected Quote"); Debug.Assert(node.NodeType != ExpressionType.Throw, "unexpected Throw"); ChildRewriter cr = new ChildRewriter(this, stack, 1); cr.Add(node.Operand); if (cr.Action == RewriteAction.SpillStack) { #if LINQ RequireNoRefArgs(node.Method); #else MarkRefArgs(cr, node.Method, 0); #endif } return(cr.Finish(cr.Rewrite ? CreateUnaryExpression(node.NodeType, cr[0], node.Type, node.Method) : expr)); }
private Result RewriteListInitExpression(Expression expr, Stack stack) { var node = (ListInitExpression)expr; // Constructor runs on initial stack. Result newResult = RewriteExpression(node.NewExpression, stack); Expression rewrittenNew = newResult.Node; RewriteAction action = newResult.Action; ReadOnlyCollection <ElementInit> inits = node.Initializers; int count = inits.Count; ChildRewriter[] cloneCrs = new ChildRewriter[count]; for (int i = 0; i < count; i++) { ElementInit init = inits[i]; // Initializers all run on non-empty stack (the list instance is on it). var 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[count]; for (int i = 0; i < 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: bool isRefNew = IsRefInstance(node.NewExpression); var comma = new ArrayBuilder <Expression>(count + 2 + (isRefNew ? 1 : 0)); ParameterExpression tempNew = MakeTemp(rewrittenNew.Type); comma.UncheckedAdd(new AssignBinaryExpression(tempNew, rewrittenNew)); ParameterExpression refTempNew = tempNew; if (isRefNew) { refTempNew = MakeTemp(tempNew.Type.MakeByRefType()); comma.UncheckedAdd(new ByRefAssignBinaryExpression(refTempNew, tempNew)); } for (int i = 0; i < count; i++) { ChildRewriter cr = cloneCrs[i]; Result add = cr.Finish(new InstanceMethodCallExpressionN(inits[i].AddMethod, refTempNew, cr[0, -1])); comma.UncheckedAdd(add.Node); } comma.UncheckedAdd(tempNew); expr = MakeBlock(comma); break; default: throw ContractUtils.Unreachable; } return(new Result(action, expr)); }
// RewriteListInitExpression private Result RewriteListInitExpression(Expression expr, Stack stack) { var node = (ListInitExpression)expr; //ctor runs on initial stack var newResult = RewriteExpression(node.NewExpression, stack); var rewrittenNew = newResult.Node; var action = newResult.Action; var inits = node.Initializers; var cloneCrs = new ChildRewriter[inits.Count]; for (var i = 0; i < inits.Count; i++) { var init = inits[i]; //initializers all run on nonempty stack var 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: var newInits = new ElementInit[inits.Count]; for (var i = 0; i < inits.Count; i++) { var cr = cloneCrs[i]; if (cr.Action == RewriteAction.None) { newInits[i] = inits[i]; } else { newInits[i] = Expression.ElementInit(inits[i].AddMethod, cr[0, -1]); } } expr = Expression.ListInit((NewExpression)rewrittenNew, new TrueReadOnlyCollection <ElementInit>(newInits)); break; case RewriteAction.SpillStack: RequireNotRefInstance(node.NewExpression); var tempNew = MakeTemp(rewrittenNew.Type); var comma = new Expression[inits.Count + 2]; comma[0] = Expression.Assign(tempNew, rewrittenNew); for (var i = 0; i < inits.Count; i++) { var cr = cloneCrs[i]; var add = cr.Finish(Expression.Call(tempNew, inits[i].AddMethod, 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)); }
// 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] = Expression.ElementInit(inits[i].AddMethod, cr[0, -1]); } } expr = Expression.ListInit((NewExpression)rewrittenNew, new ReadOnlyCollection <ElementInit>(newInits)); break; case RewriteAction.SpillStack: ParameterExpression tempNew = MakeTemp(rewrittenNew.Type); Expression[] comma = new Expression[inits.Count + 2]; comma[0] = Expression.Assign(tempNew, rewrittenNew); for (int i = 0; i < inits.Count; i++) { ChildRewriter cr = cloneCrs[i]; Result add = cr.Finish(Expression.Call(tempNew, inits[i].AddMethod, cr[0, -1])); comma[i + 1] = add.Node; } comma[inits.Count + 1] = tempNew; expr = Expression.Block(comma); break; default: throw Assert.Unreachable; } return(new Result(action, expr)); }