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)); }
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)); }
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 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)); }
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)); }
/// <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); }
// 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)); }
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); }
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); }
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); } }
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); } }
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; } }
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); } }
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 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 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); } }
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); } }
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); } }
// 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)); }
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); }