public void UncheckedAdd(int capacity) { Debug.Assert(capacity >= 0); var builder = new ArrayBuilder <T>(capacity); for (int i = 0; i < capacity; i++) { builder.UncheckedAdd(default(T)); } VerifyBuilderContents(Enumerable.Repeat(default(T), capacity), builder); }
internal void EmitVariableAccess(LambdaCompiler lc, ReadOnlyCollection <ParameterExpression> vars) { if (NearestHoistedLocals != null && vars.Count > 0) { // Find what array each variable is on & its index var indexes = new ArrayBuilder <long>(vars.Count); foreach (var variable in vars) { // For each variable, find what array it's defined on ulong parents = 0; var locals = NearestHoistedLocals; while (!locals.Indexes.ContainsKey(variable)) { parents++; if (locals.Parent == null) { Debug.Fail(string.Empty); } else { locals = locals.Parent; } } // combine the number of parents we walked, with the // real index of variable to get the index to emit. var index = (parents << 32) | (uint)locals.Indexes[variable]; indexes.UncheckedAdd((long)index); } EmitGet(NearestHoistedLocals.SelfVariable); lc.EmitConstantArray(indexes.ToArray()); lc.IL.Emit(OpCodes.Call, CachedReflectionInfo.RuntimeOpsCreateRuntimeVariablesObjectArrayInt64Array); } else { // No visible variables lc.IL.Emit(OpCodes.Call, CachedReflectionInfo.RuntimeOpsCreateRuntimeVariables); } }
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, t, Expression.Constant(i))); } else { nullCase = i; } } cases.UncheckedAdd(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( DictionaryOfStringInt32_Ctor_Int32, 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), Utils.Empty(), Expression.Assign(switchIndex, Expression.Constant(-1)) ) ), Expression.Switch(node.Type, switchIndex, node.DefaultBody, null, cases.ToReadOnly()) ); EmitExpression(reduced, flags); return(true); }
private Expression ReduceIndex() { // left[a0, a1, ... aN] (op)= r // // ... is reduced into ... // // tempObj = left // tempArg0 = a0 // ... // tempArgN = aN // tempValue = tempObj[tempArg0, ... tempArgN] (op) r // tempObj[tempArg0, ... tempArgN] = tempValue var index = (IndexExpression)Left; var vars = new ArrayBuilder<ParameterExpression>(index.ArgumentCount + 2); var exprs = new ArrayBuilder<Expression>(index.ArgumentCount + 3); ParameterExpression tempObj = Expression.Variable(index.Object.Type, "tempObj"); vars.UncheckedAdd(tempObj); exprs.UncheckedAdd(Expression.Assign(tempObj, index.Object)); int n = index.ArgumentCount; var tempArgs = new ArrayBuilder<Expression>(n); for (var i = 0; i < n; i++) { Expression arg = index.GetArgument(i); ParameterExpression tempArg = Expression.Variable(arg.Type, "tempArg" + i); vars.UncheckedAdd(tempArg); tempArgs.UncheckedAdd(tempArg); exprs.UncheckedAdd(Expression.Assign(tempArg, arg)); } IndexExpression tempIndex = Expression.MakeIndex(tempObj, index.Indexer, tempArgs.ToReadOnly()); // tempValue = tempObj[tempArg0, ... tempArgN] (op) r ExpressionType binaryOp = GetBinaryOpFromAssignmentOp(NodeType); Expression op = Expression.MakeBinary(binaryOp, tempIndex, Right, false, Method); LambdaExpression conversion = GetConversion(); if (conversion != null) { op = Expression.Invoke(conversion, op); } ParameterExpression tempValue = Expression.Variable(op.Type, "tempValue"); vars.UncheckedAdd(tempValue); exprs.UncheckedAdd(Expression.Assign(tempValue, op)); // tempObj[tempArg0, ... tempArgN] = tempValue exprs.UncheckedAdd(Expression.Assign(tempIndex, tempValue)); return Expression.Block(vars.ToReadOnly(), exprs.ToReadOnly()); }
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; int count = bindings.Count; BindingRewriter[] bindingRewriters = new BindingRewriter[count]; for (int i = 0; i < 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[count]; for (int i = 0; i < count; i++) { newBindings[i] = bindingRewriters[i].AsBinding(); } expr = new MemberInitExpression((NewExpression)rewrittenNew, new TrueReadOnlyCollection <MemberBinding>(newBindings)); 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++) { BindingRewriter cr = bindingRewriters[i]; Expression initExpr = cr.AsExpression(refTempNew); comma.UncheckedAdd(initExpr); } comma.UncheckedAdd(tempNew); expr = MakeBlock(comma); break; default: throw ContractUtils.Unreachable; } return(new Result(action, 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)); }
internal void EmitVariableAccess(LambdaCompiler lc, ReadOnlyCollection<ParameterExpression> vars) { if (NearestHoistedLocals != null && vars.Count > 0) { // Find what array each variable is on & its index var indexes = new ArrayBuilder<long>(vars.Count); foreach (ParameterExpression variable in vars) { // For each variable, find what array it's defined on ulong parents = 0; HoistedLocals locals = NearestHoistedLocals; while (!locals.Indexes.ContainsKey(variable)) { parents++; locals = locals.Parent; Debug.Assert(locals != null); } // combine the number of parents we walked, with the // real index of variable to get the index to emit. ulong index = (parents << 32) | (uint)locals.Indexes[variable]; indexes.UncheckedAdd((long)index); } EmitGet(NearestHoistedLocals.SelfVariable); lc.EmitConstantArray(indexes.ToArray()); lc.IL.Emit(OpCodes.Call, RuntimeOps_CreateRuntimeVariables_ObjectArray_Int64Array); } else { // No visible variables lc.IL.Emit(OpCodes.Call, RuntimeOps_CreateRuntimeVariables); } }
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; }