/// <summary> /// Return to the caller the set of pending return statements. /// </summary> /// <returns></returns> private ReadOnlyArray <PendingBranch> RemoveReturns() { var result = pendingBranches.ToReadOnly(); // Debug.Assert(AllReturns(result)); // if anything other than return were pending, we would have produced diagnostics earlier. this.pendingBranches.Clear(); return(result); }
internal BoundExpression BuildSequenceAndFree(SyntheticBoundNodeFactory F, BoundExpression expression) { var result = (locals.Count > 0 || statements.Count > 0 || temps.Count > 0) ? F.SpillSequence(locals.ToReadOnly(), temps.ToReadOnly(), fields.ToReadOnly(), statements.ToReadOnly(), expression) : expression; Free(); return(result); }
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 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.Add(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 AssemblyMetadata CreateAssemblyMetadata(ShadowCopy manifestModuleCopy) { // We don't need to use the global metadata cache here since the shadow copy // won't change and is private to us - only users of the same shadow copy provider see it. ArrayBuilder <ModuleMetadata> moduleBuilder = null; bool fault = true; ModuleMetadata manifestModule = null; try { manifestModule = CreateModuleMetadata(manifestModuleCopy); string originalDirectory = null, shadowCopyDirectory = null; foreach (string moduleName in manifestModule.GetModuleNames()) { if (moduleBuilder == null) { moduleBuilder = ArrayBuilder <ModuleMetadata> .GetInstance(); moduleBuilder.Add(manifestModule); originalDirectory = Path.GetDirectoryName(manifestModuleCopy.OriginalPath); shadowCopyDirectory = Path.GetDirectoryName(manifestModuleCopy.FullPath); } string originalPath = Path.Combine(originalDirectory, moduleName); string shadowCopyPath = Path.Combine(shadowCopyDirectory, moduleName); var moduleCopy = CopyFile(originalPath, shadowCopyPath); moduleBuilder.Add(CreateModuleMetadata(moduleCopy)); } var modules = (moduleBuilder != null) ? moduleBuilder.ToReadOnly() : ReadOnlyArray.Singleton(manifestModule); fault = false; return(new AssemblyMetadata(modules)); } finally { if (fault) { if (manifestModule != null) { manifestModule.Dispose(); } if (moduleBuilder != null) { for (int i = 1; i < moduleBuilder.Count; i++) { moduleBuilder[i].Dispose(); } } } if (moduleBuilder != null) { moduleBuilder.Free(); } } }