internal override Expression GetExpression() { if (_instance == null) { return(Expression.Equal ( Expression.Convert(_expression, typeof(object)), AstUtils.Null )); } var temp = Expression.Parameter(typeof(object), null); return(Expression.Block ( ReadOnlyCollectionEx.Create(temp), ReadOnlyCollectionEx.Create <Expression> ( #if ENABLEDYNAMICPROGRAMMING Expression.Assign( temp, Expression.Property( Expression.Constant(new WeakReference(_instance)), typeof(WeakReference).GetProperty("Target") ) ), #else Expression.Assign ( temp, Expression.Constant(_instance, typeof(object)) ), #endif Expression.AndAlso ( //check that WeakReference was not collected. Expression.NotEqual(temp, AstUtils.Null), Expression.Equal ( Expression.Convert(_expression, typeof(object)), temp ) ) ) )); }
public static ReadOnlyCollectionEx <T> ToReadOnlyCollection <T>(this IEnumerable <T> enumerable) { switch (enumerable) { case null: return(EmptyCollection <T> .Instance); case ReadOnlyCollectionEx <T> arrayReadOnlyCollection: return(arrayReadOnlyCollection); default: { var array = AsArrayInternal(enumerable); return(array.Length == 0 ? EmptyCollection <T> .Instance : ReadOnlyCollectionEx.Create(array)); } } }
protected internal override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) { var count = node.Variables.Count; var boxes = new List <IStrongBox>(); var vars = new List <ParameterExpression>(); var indexes = new int[count]; for (var i = 0; i < indexes.Length; i++) { var box = GetBox(node.Variables[i]); if (box == null) { indexes[i] = vars.Count; vars.Add(node.Variables[i]); } else { indexes[i] = -1 - boxes.Count; boxes.Add(box); } } // No variables were rewritten. Just return the original node. if (boxes.Count == 0) { return(node); } var boxesConst = Expression.Constant(new RuntimeOps.RuntimeVariables(boxes.ToArray()), typeof(IRuntimeVariables)); // All of them were rewritten. Just return the array as a constant if (vars.Count == 0) { return(boxesConst); } // Otherwise, we need to return an object that merges them. return(Expression.Invoke ( Expression.Constant(new Func <IRuntimeVariables, IRuntimeVariables, int[], IRuntimeVariables>(MergeRuntimeVariables)), Expression.RuntimeVariables(ReadOnlyCollectionEx.Create(vars.ToArray())), boxesConst, Expression.Constant(indexes) )); }
/// <summary> /// Creates a <see cref="ListInitExpression" /> that uses a specified method to add elements to a collection. /// </summary> /// <param name="newExpression"> /// A <see cref="NewExpression" /> to set the <see cref="ListInitExpression.NewExpression" /> /// property equal to. /// </param> /// <param name="addMethod"> /// A <see cref="MethodInfo" /> that represents an instance method named "Add" (case insensitive), /// that adds an element to a collection. /// </param> /// <param name="initializers"> /// An <see cref="IEnumerable{T}" /> that contains <see cref="Expression" /> objects to use to /// populate the Initializers collection. /// </param> /// <returns> /// A <see cref="ListInitExpression" /> that has the <see cref="NodeType" /> property equal to /// <see cref="ExpressionType.ListInit" /> and the <see cref="ListInitExpression.NewExpression" /> property set to the /// specified value. /// </returns> public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, IEnumerable <Expression> initializers) { if (addMethod == null) { return(ListInit(newExpression, initializers)); } ContractUtils.RequiresNotNull(newExpression, nameof(newExpression)); ContractUtils.RequiresNotNull(initializers, nameof(initializers)); var initializerList = initializers.ToReadOnlyCollection(); var initList = new ElementInit[initializerList.Count]; for (var i = 0; i < initializerList.Count; i++) { initList[i] = ElementInit(addMethod, initializerList[i]); } return(ListInit(newExpression, ReadOnlyCollectionEx.Create(initList))); }
public static ReadOnlyCollectionEx <T> ToReadOnlyCollection <T>(this IEnumerable <T> enumerable) { switch (enumerable) { case null: return(EmptyCollection <T> .Instance); case ReadOnlyCollectionEx <T> arrayReadOnlyCollection: return(arrayReadOnlyCollection); default: { var array = AsArrayInternal(enumerable); #pragma warning disable CA1062 // Validate arguments of public methods return(array.Length == 0 ? EmptyCollection <T> .Instance : ReadOnlyCollectionEx.Create(array)); #pragma warning restore CA1062 // Validate arguments of public methods } } }
private static NewArrayExpression NewArrayInitExtracted(Type type, IEnumerable <Expression> initializers, string initializersName) { var initializerList = initializers.ToReadOnlyCollection(); Expression[]? newList = null; for (int i = 0, n = initializerList.Count; i < n; i++) { var expr = initializerList[i]; ContractUtils.RequiresNotNull(expr, initializersName, i); ExpressionUtils.RequiresCanRead(expr, initializersName, i); if (!type.IsReferenceAssignableFromInternal(expr.Type)) { if (!TryQuote(type, ref expr)) { throw new InvalidOperationException($"An expression of type '{expr.Type}' cannot be used to initialize an array of type '{type}'"); } if (newList == null) { newList = new Expression[initializerList.Count]; for (var j = 0; j < i; j++) { newList[j] = initializerList[j]; } } } if (newList != null) { newList[i] = expr; } } if (newList != null) { initializerList = ReadOnlyCollectionEx.Create(newList); } return(NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList)); }
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) { expr = NewArrayExpression.Make(node.NodeType, node.Type, ReadOnlyCollectionEx.Create(cr[0, -1])); } return(cr.Finish(expr)); }
internal RuntimeVariablesExpression(ParameterExpression[] variables) { _variables = variables; _variablesAsReadOnlyCollection = ReadOnlyCollectionEx.Create(_variables); }
internal ElementInit(MethodInfo addMethod, Expression[] arguments) { AddMethod = addMethod; _argumentsAsReadOnlyCollection = ReadOnlyCollectionEx.Create(arguments); }
private DynamicMetaObject BuildCallMethodWithResult <TBinder>(MethodInfo method, TBinder binder, Expression[] args, DynamicMetaObject fallbackResult, Func <MetaDynamic, TBinder, DynamicMetaObject?, DynamicMetaObject>?fallbackInvoke) where TBinder : DynamicMetaObjectBinder { if (!IsOverridden(method)) { return(fallbackResult); } // Build a new expression like: #pragma warning disable S125 // Sections of code should not be commented out // { // object result; // TryGetMember(payload, out result) ? fallbackInvoke(result) : fallbackResult // } #pragma warning restore S125 // Sections of code should not be commented out var result = Expression.Parameter(typeof(object), null); var callArgs = method != CachedReflectionInfo.DynamicObjectTryBinaryOperation ? Expression.Parameter(typeof(object[]), null) : Expression.Parameter(typeof(object), null); var callArgsValue = GetConvertedArgs(args); var resultMetaObject = new DynamicMetaObject(result, BindingRestrictions.Empty); // Need to add a conversion if calling TryConvert if (binder.ReturnType != typeof(object)) { Debug.Assert(binder is ConvertBinder && fallbackInvoke == null); var convert = Expression.Convert(resultMetaObject.Expression, binder.ReturnType); // will always be a cast or unbox Debug.Assert(convert.Method == null); // Prepare a good exception message in case the convert will fail var convertFailed = $"The result type '{{0}}' of the dynamic binding produced by the object with type '{Value!.GetType()}' for the binder '{binder.GetType()}' is not compatible with the result type '{binder.ReturnType}' expected by the call site."; // If the return type can not be assigned null then just check for type assignability otherwise allow null. var condition = binder.ReturnType.IsValueType && Nullable.GetUnderlyingType(binder.ReturnType) == null ? (Expression)Expression.TypeIs(resultMetaObject.Expression, binder.ReturnType) : Expression.OrElse ( Expression.Equal(resultMetaObject.Expression, AstUtils.Null), Expression.TypeIs(resultMetaObject.Expression, binder.ReturnType) ); Expression checkedConvert = Expression.Condition ( condition, convert, Expression.Throw ( Expression.New ( CachedReflectionInfo.InvalidCastExceptionCtorString, ReadOnlyCollectionEx.Create <Expression> ( Expression.Call ( CachedReflectionInfo.StringFormatStringObjectArray, Expression.Constant(convertFailed), Expression.NewArrayInit ( typeof(object), ReadOnlyCollectionEx.Create <Expression> ( Expression.Condition ( Expression.Equal(resultMetaObject.Expression, AstUtils.Null), Expression.Constant("null"), Expression.Call ( resultMetaObject.Expression, CachedReflectionInfo.ObjectGetType ), typeof(object) ) ) ) ) ) ), binder.ReturnType ), binder.ReturnType ); resultMetaObject = new DynamicMetaObject(checkedConvert, resultMetaObject.Restrictions); } if (fallbackInvoke != null) { resultMetaObject = fallbackInvoke(this, binder, resultMetaObject); } return(new DynamicMetaObject ( Expression.Block ( ReadOnlyCollectionEx.Create(result, callArgs), ReadOnlyCollectionEx.Create <Expression> ( method != CachedReflectionInfo.DynamicObjectTryBinaryOperation ? Expression.Assign(callArgs, Expression.NewArrayInit(typeof(object), callArgsValue)) : Expression.Assign(callArgs, callArgsValue[0]), Expression.Condition ( Expression.Call ( GetLimitedSelf(), method, BuildCallArgs ( binder, args, callArgs, result ) ), Expression.Block ( method != CachedReflectionInfo.DynamicObjectTryBinaryOperation ? ReferenceArgAssign(callArgs, args) : AstUtils.Empty, resultMetaObject.Expression ), fallbackResult.Expression, binder.ReturnType ) ) ), GetRestrictions().Merge(resultMetaObject.Restrictions).Merge(fallbackResult.Restrictions) )); }
protected ProgressiveList(Progressor <T> progressor, IList <T> cache, IEqualityComparer <T> comparer) : base(progressor, cache, comparer) { _cache = cache; Cache = new ReadOnlyCollectionEx <T>(_cache); }
internal ScopeN(ParameterExpression[] variables, Expression[] body) : base(variables) { _body = body; _bodyAsReadOnlyCollection = ReadOnlyCollectionEx.Create(_body); }
internal SwitchCase(Expression body, Expression[] testValues) { Body = body; _testValues = testValues; _textValuesAsReadOnlyCollection = ReadOnlyCollectionEx.Create(_testValues); }
internal MemberInitExpression(NewExpression newExpression, MemberBinding[] bindings) { NewExpression = newExpression; _bindings = bindings; _bindingsAsReadOnlyCollection = ReadOnlyCollectionEx.Create(_bindings); }
private bool TryEmitHashtableSwitch(SwitchExpression node, CompilationFlags flags) { // If we have a comparison other than string equality, bail if (node.Comparison != CachedReflectionInfo.StringOpEqualityStringString && node.Comparison != CachedReflectionInfo.StringEqualsStringString) { return(false); } // All test values must be constant. var tests = 0; foreach (var c in node.Cases) { foreach (var 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); var nullCase = -1; var add = CachedReflectionInfo.DictionaryOfStringInt32AddStringInt32; for (int i = 0, n = node.Cases.Count; i < n; i++) { foreach (var expression in node.Cases[i].TestValues) { var t = (ConstantExpression)expression; if (t.Value != null) { initializers.Add(Expression.ElementInit(add, ReadOnlyCollectionEx.Create <Expression>(t, Utils.Constant(i)))); } else { nullCase = i; } } cases.UncheckedAdd(Expression.SwitchCase(node.Cases[i].Body, ReadOnlyCollectionEx.Create <Expression>(Utils.Constant(i)))); } // Create the field to hold the lazily initialized dictionary var 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 ( CachedReflectionInfo.DictionaryOfStringInt32CtorInt32, ReadOnlyCollectionEx.Create <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: // } // var switchValue = Expression.Variable(typeof(string), "switchValue"); var switchIndex = Expression.Variable(typeof(int), "switchIndex"); var reduced = Expression.Block ( ReadOnlyCollectionEx.Create(switchIndex, switchValue), ReadOnlyCollectionEx.Create <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.ToArray()) ) ); EmitExpression(reduced, flags); return(true); }
internal NewArrayExpression(Type type, Expression[] expressions) { _expressions = expressions; Type = type; _expressionsAsReadOnlyCollection = ReadOnlyCollectionEx.Create(_expressions); }
private Result RewriteListInitExpression(Expression expr, Stack stack) { var node = (ListInitExpression)expr; // Constructor runs on initial stack. var newResult = RewriteExpression(node.NewExpression, stack); var rewrittenNew = newResult.Node; var action = newResult.Action; var initializers = node.Initializers; var count = initializers.Count; var cloneCrs = new ChildRewriter[count]; for (var i = 0; i < count; i++) { var init = initializers[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: var newInitializer = new ElementInit[count]; for (var i = 0; i < count; i++) { var cr = cloneCrs[i]; if (cr.Action == RewriteAction.None) { newInitializer[i] = initializers[i]; } else { newInitializer[i] = new ElementInit(initializers[i].AddMethod, cr[0, -1]); } } expr = new ListInitExpression((NewExpression)rewrittenNew, ReadOnlyCollectionEx.Create(newInitializer)); break; case RewriteAction.SpillStack: var isRefNew = IsRefInstance(node.NewExpression); var comma = new ArrayBuilder <Expression>(count + 2 + (isRefNew ? 1 : 0)); var tempNew = MakeTemp(rewrittenNew.Type); comma.UncheckedAdd(new AssignBinaryExpression(tempNew, rewrittenNew)); var refTempNew = tempNew; if (isRefNew) { refTempNew = MakeTemp(tempNew.Type.MakeByRefType()); comma.UncheckedAdd(new ByRefAssignBinaryExpression(refTempNew, tempNew)); } for (var i = 0; i < count; i++) { var cr = cloneCrs[i]; var add = cr.Finish(new InstanceMethodCallExpressionN(initializers[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)); }
private DynamicMetaObject CallMethodReturnLast <TBinder>(MethodInfo method, TBinder binder, Expression[] args, Expression value, Func <MetaDynamic, TBinder, DynamicMetaObject?, DynamicMetaObject> fallback) where TBinder : DynamicMetaObjectBinder { // // First, call fallback to do default binding // This produces either an error or a call to a .NET member // var fallbackResult = fallback(this, binder, null); // Build a new expression like: #pragma warning disable S125 // Sections of code should not be commented out // { // object result; // TrySetMember(payload, result = value) ? result : fallbackResult // } #pragma warning restore S125 // Sections of code should not be commented out var result = Expression.Parameter(typeof(object), null); var callArgs = Expression.Parameter(typeof(object[]), null); var callArgsValue = GetConvertedArgs(args); var callDynamic = new DynamicMetaObject ( Expression.Block ( ReadOnlyCollectionEx.Create(result, callArgs), ReadOnlyCollectionEx.Create <Expression> ( Expression.Assign(callArgs, Expression.NewArrayInit(typeof(object), callArgsValue)), Expression.Condition ( Expression.Call ( GetLimitedSelf(), method, BuildCallArgs ( binder, args, callArgs, Expression.Assign(result, Expression.Convert(value, typeof(object))) ) ), Expression.Block ( ReferenceArgAssign(callArgs, args), result ), fallbackResult.Expression, typeof(object) ) ) ), GetRestrictions().Merge(fallbackResult.Restrictions) ); // // Now, call fallback again using our new MO as the error // When we do this, one of two things can happen: // 1. Binding will succeed, and it will ignore our call to // the dynamic method, OR // 2. Binding will fail, and it will use the MO we created // above. // return(fallback(this, binder, callDynamic)); }
public InvocationExpressionN(Expression lambda, Expression[] arguments, Type returnType) : base(lambda, returnType) { _arguments = arguments; _argumentsAsReadOnly = ReadOnlyCollectionEx.Create(_arguments); }
private static void ValidateNewArgs(ConstructorInfo constructor, ref Expression[] arguments, ref ReadOnlyCollectionEx <MemberInfo> members) { ParameterInfo[] pis = constructor.GetParameters(); if (pis.Length > 0) { if (arguments.Length != pis.Length) { throw new ArgumentException("Incorrect number of arguments for constructor"); } if (arguments.Length != members.Count) { throw new ArgumentException("Incorrect number of arguments for the given members "); } Expression[]? newArguments = null; MemberInfo[]? newMembers = null; for (int i = 0, n = arguments.Length; i < n; i++) { var arg = arguments[i]; ContractUtils.RequiresNotNull(arg, nameof(arguments), i); ExpressionUtils.RequiresCanRead(arg, nameof(arguments), i); var member = members[i]; ContractUtils.RequiresNotNull(member, nameof(members), i); if (!TypeUtils.AreEquivalent(member.DeclaringType, constructor.DeclaringType)) { throw new ArgumentException($" The member '{member.Name}' is not declared on type '{constructor.DeclaringType?.Name}' being created", i >= 0 ? $"{nameof(members)}[{i}]" : nameof(members)); } ValidateAnonymousTypeMember(ref member, out var memberType, nameof(members), i); if (!memberType.IsReferenceAssignableFromInternal(arg.Type) && !TryQuote(memberType, ref arg)) { throw new ArgumentException($" Argument type '{arg.Type}' does not match the corresponding member type '{memberType}'", i >= 0 ? $"{nameof(arguments)}[{i}]" : nameof(arguments)); } var pi = pis[i]; var pType = pi.ParameterType; if (pType.IsByRef) { pType = pType.GetElementType(); } if (!pType.IsReferenceAssignableFromInternal(arg.Type) && !TryQuote(pType, ref arg)) { throw new ArgumentException($"Expression of type '{arg.Type}' cannot be used for constructor parameter of type '{pType}'", i >= 0 ? $"{nameof(arguments)}[{i}]" : nameof(arguments)); } if (newArguments == null && arg != arguments[i]) { newArguments = new Expression[arguments.Length]; for (var j = 0; j < i; j++) { newArguments[j] = arguments[j]; } } if (newArguments != null) { newArguments[i] = arg; } if (newMembers == null && member != members[i]) { newMembers = new MemberInfo[members.Count]; for (var j = 0; j < i; j++) { newMembers[j] = members[j]; } } if (newMembers != null) { newMembers[i] = member; } } if (newArguments != null) { arguments = newArguments; } if (newMembers != null) { members = ReadOnlyCollectionEx.Create(newMembers); } } else if (arguments?.Length > 0) { throw new ArgumentException("Incorrect number of arguments for constructor"); } else if (members?.Count > 0) { throw new ArgumentException("Incorrect number of members for constructor"); } }