bool TransformArrayInitializers(List<ILNode> body, ILExpression expr, int pos) { ILVariable v, v3; ILExpression newarrExpr; TypeReference elementType; ILExpression lengthExpr; int arrayLength; if (expr.Match(ILCode.Stloc, out v, out newarrExpr) && newarrExpr.Match(ILCode.Newarr, out elementType, out lengthExpr) && lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) && arrayLength > 0) { ILExpression[] newArr; int initArrayPos; if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out newArr, out initArrayPos)) { var arrayType = new ArrayType( elementType, new[] { new ArrayDimension(0, arrayLength) }); body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr)); body.RemoveAt(initArrayPos); } // Put in a limit so that we don't consume too much memory if the code allocates a huge array // and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler! const int maxConsecutiveDefaultValueExpressions = 300; List<ILExpression> operands = new List<ILExpression>(); int numberOfInstructionsToRemove = 0; for (int j = pos + 1; j < body.Count; j++) { ILExpression nextExpr = body[j] as ILExpression; int arrayPos; if (nextExpr != null && nextExpr.Code.IsStoreToArray() && nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) && v == v3 && nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) && arrayPos >= operands.Count && arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions) { while (operands.Count < arrayPos) operands.Add(new ILExpression(ILCode.DefaultValue, elementType)); operands.Add(nextExpr.Arguments[2]); numberOfInstructionsToRemove++; } else { break; } } if (operands.Count == arrayLength) { var arrayType = new ArrayType( elementType, new[] { new ArrayDimension(0, arrayLength) }); expr.Arguments[0] = new ILExpression(ILCode.InitArray, arrayType, operands); body.RemoveRange(pos + 1, numberOfInstructionsToRemove); new ILInlining(method).InlineIfPossible(body, ref pos); return true; } } return false; }
public virtual bool Match(PatternMatcher pm, ILExpression e) { if (e.Arguments.Count != this.Arguments.Length || e.Prefixes != null) return false; for (int i = 0; i < this.Arguments.Length; i++) if (!this.Arguments[i].Match(pm, e.Arguments[i])) return false; return true; }
static ILExpression EliminateDups(ILExpression expr) { if (expr.Code == ILCode.Dup) return expr.Arguments.Single(); else return expr; }
static bool TransformDecimalCtorToConstant(ILExpression expr) { IMethod r; List<ILExpression> args; if (expr.Match(ILCode.Newobj, out r, out args) && r.DeclaringType.Namespace == "System" && r.DeclaringType.Name == "Decimal") { if (args.Count == 1) { int val; if (args[0].Match(ILCode.Ldc_I4, out val)) { expr.Code = ILCode.Ldc_Decimal; expr.Operand = new decimal(val); expr.InferredType = r.DeclaringType.ToTypeSig(); expr.Arguments.Clear(); return true; } } else if (args.Count == 5) { int lo, mid, hi, isNegative, scale; if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) && expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) && expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) && expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) && expr.Arguments[4].Match(ILCode.Ldc_I4, out scale)) { expr.Code = ILCode.Ldc_Decimal; expr.Operand = new decimal(lo, mid, hi, isNegative != 0, (byte)scale); expr.InferredType = r.DeclaringType.ToTypeSig(); expr.Arguments.Clear(); return true; } } } return false; }
protected override ILExpression VisitExpression(ILExpression expression) { if (expression.Code == ILCode.Stloc) { var variable = (ILVariable)expression.Operand; if (variable.Type.HasInterface("System.IDisposable")) { var key = Tuple.Create(variable, currentScope); if (starts.Keys.Any(k => k.Item1 == variable && k.Item2 != currentScope)) { LogTo.Warning("Method {0}: Using cannot be added because reassigning a variable in a condition is not supported.", method); } else { if (starts.ContainsKey(key)) { UsingRanges.Add(new ILRange { From = starts[key], To = expression.FirstILOffset() }); starts.Remove(key); } if (!currentTrys.Contains(expression.LastILOffset())) starts.Add(key, expression.LastILOffset()); } } } if (expression.Code == ILCode.Ret && currentScope > 1) { EarlyReturns.Add(expression.FirstILOffset()); } return base.VisitExpression(expression); }
static ILExpression HandleDecimalConstants(ILExpression expr) { if (expr.Code == ILCode.Newobj) { MethodReference r = (MethodReference)expr.Operand; if (r.DeclaringType.Name == "Decimal" && r.DeclaringType.Namespace == "System") { if (expr.Arguments.Count == 1) { int? val = GetI4Constant(expr.Arguments[0]); if (val != null) { expr.Arguments.Clear(); expr.Code = ILCode.Ldc_Decimal; expr.Operand = new decimal(val.Value); expr.InferredType = r.DeclaringType; } } else if (expr.Arguments.Count == 5) { int? lo = GetI4Constant(expr.Arguments[0]); int? mid = GetI4Constant(expr.Arguments[1]); int? hi = GetI4Constant(expr.Arguments[2]); int? isNegative = GetI4Constant(expr.Arguments[3]); int? scale = GetI4Constant(expr.Arguments[4]); if (lo != null && mid != null && hi != null && isNegative != null && scale != null) { expr.Arguments.Clear(); expr.Code = ILCode.Ldc_Decimal; expr.Operand = new decimal(lo.Value, mid.Value, hi.Value, isNegative.Value != 0, (byte)scale); expr.InferredType = r.DeclaringType; } } } } return expr; }
protected ILExpression CreateLabeledExpression(GMCode code) { int absolute = GMCodeUtil.getBranchOffset(CurrentRaw) + CurrentPC; ILExpression e = new ILExpression(code, GetLabel(absolute)); e.Extra = (int)(CurrentRaw & 0xFFFF); e.ILRanges.Add(new ILRange(CurrentPC, CurrentPC)); return e; }
public bool SimplifyLiftedOperators(ILExpression expr) { if (Simplify(expr)) return true; bool modified = false; foreach (var a in expr.Arguments) modified |= SimplifyLiftedOperators(a); return modified; }
/// <summary> /// Finds individual instructions within the block that represent higher level concepts related to dynamic call sites. /// This enables FindDynamicCallSites to locate and transform call sites in a single pass. /// </summary> public bool AnalyzeInstructions(List<ILNode> body, ILExpression expr, int pos) { bool result = false; var newInstruction = AnalyzeInstruction(expr, ref result); if (newInstruction != expr) body[pos] = newInstruction; return result; }
bool SimplifyLiftedOperators(List<ILNode> body, ILExpression expr, int pos) { if (!new PatternMatcher(typeSystem).SimplifyLiftedOperators(expr)) return false; var inlining = new ILInlining(method); while (--pos >= 0 && inlining.InlineIfPossible(body, ref pos)) ; return true; }
bool SimplifyLiftedOperators(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { if (!GetPatternMatcher(corLib).SimplifyLiftedOperators(expr)) return false; var inlining = GetILInlining(method); while (--pos >= 0 && inlining.InlineIfPossible(block, body, ref pos)) ; return true; }
public override bool Match(ILNode other) { ILExpression expr = other as ILExpression; if (expr != null && expr.Code == ILCode.Stloc && (!MustBeGenerated || ((ILVariable)expr.Operand).IsGenerated) && Match(this.Arguments, expr.Arguments)) { this.LastMatch = expr; return true; } else { return false; } }
static bool TypeConversionSimplifications(List<ILNode> body, ILExpression expr, int pos) { bool modified = false; modified |= TransformDecimalCtorToConstant(expr); modified |= SimplifyLdcI4ConvI8(expr); modified |= RemoveConvIFromArrayCreation(expr); foreach(ILExpression arg in expr.Arguments) { modified |= TypeConversionSimplifications(null, arg, -1); } return modified; }
static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos) { bool modified = false; expr = SimplifyLdObjAndStObj(expr, ref modified); if (modified && body != null) body[pos] = expr; for (int i = 0; i < expr.Arguments.Count; i++) { expr.Arguments[i] = SimplifyLdObjAndStObj(expr.Arguments[i], ref modified); modified |= SimplifyLdObjAndStObj(null, expr.Arguments[i], -1); } return modified; }
static bool SimplifyLdcI4ConvI8(ILExpression expr) { ILExpression ldc; int val; if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) { expr.Code = ILCode.Ldc_I8; expr.Operand = (long)val; expr.Arguments.Clear(); return true; } return false; }
public ParameterDeclarationAnnotation(ILExpression expr) { Debug.Assert(expr.Code == ILCode.ExpressionTreeParameterDeclarations); for (int i = 0; i < expr.Arguments.Count - 1; i++) { ILExpression p = expr.Arguments[i]; // p looks like this: // stloc(v, call(Expression::Parameter, call(Type::GetTypeFromHandle, ldtoken(...)), ldstr(...))) ILVariable v = (ILVariable)p.Operand; TypeReference typeRef = (TypeReference)p.Arguments[0].Arguments[0].Arguments[0].Operand; string name = (string)p.Arguments[0].Arguments[1].Operand; Parameters.Add(new ParameterDeclaration(AstBuilder.ConvertType(typeRef), name).WithAnnotation(v)); } }
static bool SimplifyLdcI4ConvI8(ILExpression expr) { ILExpression ldc; int val; if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) { expr.Code = ILCode.Ldc_I8; expr.Operand = (long)val; foreach (var arg in expr.Arguments) expr.ILRanges.AddRange(arg.GetSelfAndChildrenRecursiveILRanges()); expr.Arguments.Clear(); return true; } return false; }
/// <summary> /// Inlines 'expr' into 'next', if possible. /// </summary> public static bool InlineIfPossible(ILExpression expr, ILNode next, ILBlock method) { if (expr.Code != ILCode.Stloc) throw new ArgumentException("expr must be stloc"); // ensure the variable is accessed only a single time if (method.GetSelfAndChildrenRecursive<ILExpression>().Count(e => e != expr && e.Operand == expr.Operand) != 1) return false; ILExpression parent; int pos; if (FindLoadInNext(next as ILExpression, (ILVariable)expr.Operand, out parent, out pos) == true) { parent.Arguments[pos] = expr.Arguments[0]; return true; } return false; }
bool SimplifyLdcI4ConvI8(ILExpression expr) { ILExpression ldc; int val; if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) { expr.Code = ILCode.Ldc_I8; expr.Operand = (long)val; if (context.CalculateILRanges) { foreach (var arg in expr.Arguments) arg.AddSelfAndChildrenRecursiveILRanges(expr.ILRanges); } expr.Arguments.Clear(); return true; } return false; }
static bool CanBeRepresentedAsCompoundAssignment(ILExpression expr) { switch (expr.Code) { case ILCode.Add: case ILCode.Add_Ovf: case ILCode.Add_Ovf_Un: case ILCode.Sub: case ILCode.Sub_Ovf: case ILCode.Sub_Ovf_Un: case ILCode.Mul: case ILCode.Mul_Ovf: case ILCode.Mul_Ovf_Un: case ILCode.Div: case ILCode.Div_Un: case ILCode.Rem: case ILCode.Rem_Un: case ILCode.And: case ILCode.Or: case ILCode.Xor: case ILCode.Shl: case ILCode.Shr: case ILCode.Shr_Un: return true; case ILCode.Call: var m = expr.Operand as IMethod; if (m == null || m.MethodSig == null || m.MethodSig.HasThis || expr.Arguments.Count != 2) return false; switch (m.Name) { case "op_Addition": case "op_Subtraction": case "op_Multiply": case "op_Division": case "op_Modulus": case "op_BitwiseAnd": case "op_BitwiseOr": case "op_ExclusiveOr": case "op_LeftShift": case "op_RightShift": return true; default: return false; } default: return false; } }
/// <summary> /// Finds the position to inline to. /// </summary> /// <returns>true = found; false = cannot continue search; null = not found</returns> static bool? FindLoadInNext(ILExpression expr, ILVariable v, out ILExpression parent, out int pos) { parent = null; pos = 0; if (expr == null) return false; for (int i = 0; i < expr.Arguments.Count; i++) { ILExpression arg = expr.Arguments[i]; if (arg.Code == ILCode.Ldloc && arg.Operand == v) { parent = expr; pos = i; return true; } bool? r = FindLoadInNext(arg, v, out parent, out pos); if (r != null) return r; } return IsWithoutSideEffects(expr.Code) ? (bool?)null : false; }
bool TransformDecimalCtorToConstant(ILExpression expr) { IMethod r; List<ILExpression> args; if (expr.Match(ILCode.Newobj, out r, out args) && r.DeclaringType.Compare(systemString, decimalString)) { if (args.Count == 1) { int val; if (args[0].Match(ILCode.Ldc_I4, out val)) { expr.Code = ILCode.Ldc_Decimal; expr.Operand = new decimal(val); expr.InferredType = r.DeclaringType.ToTypeSig(); if (context.CalculateILRanges) { foreach (var arg in expr.Arguments) arg.AddSelfAndChildrenRecursiveILRanges(expr.ILRanges); } expr.Arguments.Clear(); return true; } } else if (args.Count == 5) { int lo, mid, hi, isNegative, scale; if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) && expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) && expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) && expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) && expr.Arguments[4].Match(ILCode.Ldc_I4, out scale)) { expr.Code = ILCode.Ldc_Decimal; expr.Operand = new decimal(lo, mid, hi, isNegative != 0, (byte)scale); expr.InferredType = r.DeclaringType.ToTypeSig(); if (context.CalculateILRanges) { foreach (var arg in expr.Arguments) arg.AddSelfAndChildrenRecursiveILRanges(expr.ILRanges); } expr.Arguments.Clear(); return true; } } } return false; }
static bool TransformDecimalCtorToConstant(List<ILNode> body, ILExpression expr, int pos) { MethodReference r; List<ILExpression> args; if (expr.Match(ILCode.Newobj, out r, out args) && r.DeclaringType.Namespace == "System" && r.DeclaringType.Name == "Decimal") { if (args.Count == 1) { int val; if (args[0].Match(ILCode.Ldc_I4, out val)) { expr.Code = ILCode.Ldc_Decimal; expr.Operand = new decimal(val); expr.InferredType = r.DeclaringType; expr.Arguments.Clear(); return true; } } else if (args.Count == 5) { int lo, mid, hi, isNegative, scale; if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) && expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) && expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) && expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) && expr.Arguments[4].Match(ILCode.Ldc_I4, out scale)) { expr.Code = ILCode.Ldc_Decimal; expr.Operand = new decimal(lo, mid, hi, isNegative != 0, (byte)scale); expr.InferredType = r.DeclaringType; expr.Arguments.Clear(); return true; } } } bool modified = false; foreach(ILExpression arg in expr.Arguments) { modified |= TransformDecimalCtorToConstant(null, arg, -1); } return modified; }
static ILExpression SimplifyLdObjAndStObj(ILExpression expr, ref bool modified) { if (expr.Code == ILCode.Initobj) { expr.Code = ILCode.Stobj; expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand)); modified = true; } ILExpression arg, arg2; TypeReference type; ILCode? newCode = null; if (expr.Match(ILCode.Stobj, out type, out arg, out arg2)) { switch (arg.Code) { case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break; case ILCode.Ldloca: newCode = ILCode.Stloc; break; case ILCode.Ldflda: newCode = ILCode.Stfld; break; case ILCode.Ldsflda: newCode = ILCode.Stsfld; break; } } else if (expr.Match(ILCode.Ldobj, out type, out arg)) { switch (arg.Code) { case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break; case ILCode.Ldloca: newCode = ILCode.Ldloc; break; case ILCode.Ldflda: newCode = ILCode.Ldfld; break; case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break; } } if (newCode != null) { arg.Code = newCode.Value; if (expr.Code == ILCode.Stobj) { arg.InferredType = expr.InferredType; arg.ExpectedType = expr.ExpectedType; arg.Arguments.Add(arg2); } arg.ILRanges.AddRange(expr.ILRanges); modified = true; return arg; } else { return expr; } }
static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos) { bool modified = false; if (expr.Code == ILCode.Initobj) { expr.Code = ILCode.Stobj; expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand)); modified = true; } ILExpression arg, arg2; TypeReference type; ILCode? newCode = null; if (expr.Match(ILCode.Stobj, out type, out arg, out arg2)) { switch (arg.Code) { case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break; case ILCode.Ldloca: newCode = ILCode.Stloc; break; case ILCode.Ldflda: newCode = ILCode.Stfld; break; case ILCode.Ldsflda: newCode = ILCode.Stsfld; break; } } else if (expr.Match(ILCode.Ldobj, out type, out arg)) { switch (arg.Code) { case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break; case ILCode.Ldloca: newCode = ILCode.Ldloc; break; case ILCode.Ldflda: newCode = ILCode.Ldfld; break; case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break; } } if (newCode != null) { arg.Code = newCode.Value; if (expr.Code == ILCode.Stobj) arg.Arguments.Add(arg2); arg.ILRanges.AddRange(expr.ILRanges); body[pos] = arg; modified = true; } return modified; }
bool MakeCompoundAssignment(ILExpression expr) { // stelem.any(T, ldloc(array), ldloc(pos), <OP>(ldelem.any(T, ldloc(array), ldloc(pos)), <RIGHT>)) // or // stobj(T, ldloc(ptr), <OP>(ldobj(T, ldloc(ptr)), <RIGHT>)) ILCode expectedLdelemCode; switch (expr.Code) { case ILCode.Stelem_Any: expectedLdelemCode = ILCode.Ldelem_Any; break; case ILCode.Stfld: expectedLdelemCode = ILCode.Ldfld; break; case ILCode.Stobj: expectedLdelemCode = ILCode.Ldobj; break; case ILCode.CallSetter: expectedLdelemCode = ILCode.CallGetter; break; case ILCode.CallvirtSetter: expectedLdelemCode = ILCode.CallvirtGetter; break; default: return(false); } // all arguments except the last (so either array+pos, or ptr): bool hasGeneratedVar = false; for (int i = 0; i < expr.Arguments.Count - 1; i++) { ILVariable inputVar; if (!expr.Arguments[i].Match(ILCode.Ldloc, out inputVar)) { return(false); } hasGeneratedVar |= inputVar.IsGenerated; } // At least one of the variables must be generated; otherwise we just keep the expanded form. // We do this because we want compound assignments to be represented in ILAst only when strictly necessary; // other compound assignments will be introduced by ReplaceMethodCallsWithOperator // (which uses a reversible transformation, see ReplaceMethodCallsWithOperator.RestoreOriginalAssignOperatorAnnotation) if (!hasGeneratedVar) { return(false); } ILExpression op = expr.Arguments.Last(); if (!CanBeRepresentedAsCompoundAssignment(op.Code)) { return(false); } ILExpression ldelem = op.Arguments[0]; if (ldelem.Code != expectedLdelemCode) { return(false); } Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1); for (int i = 0; i < ldelem.Arguments.Count; i++) { if (!ldelem.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand)) { return(false); } } expr.Code = ILCode.CompoundAssignment; expr.Operand = null; expr.Arguments.RemoveRange(0, ldelem.Arguments.Count); // result is "CompoundAssignment(<OP>(ldelem.any(...), <RIGHT>))" return(true); }
bool IntroducePostIncrementForVariables(List <ILNode> body, ILExpression expr, int pos) { // Works for variables and static fields/properties // expr = ldloc(i) // stloc(i, add(expr, ldc.i4(1))) // -> // expr = postincrement(1, ldloca(i)) ILVariable exprVar; ILExpression exprInit; if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated)) { return(false); } //The next expression ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression; if (nextExpr == null) { return(false); } ILCode loadInstruction = exprInit.Code; ILCode storeInstruction = nextExpr.Code; bool recombineVariable = false; // We only recognise local variables, static fields, and static getters with no arguments switch (loadInstruction) { case ILCode.Ldloc: //Must be a matching store type if (storeInstruction != ILCode.Stloc) { return(false); } ILVariable loadVar = (ILVariable)exprInit.Operand; ILVariable storeVar = (ILVariable)nextExpr.Operand; if (loadVar != storeVar) { if (loadVar.OriginalVariable != null && loadVar.OriginalVariable == storeVar.OriginalVariable) { recombineVariable = true; } else { return(false); } } break; case ILCode.Ldsfld: if (storeInstruction != ILCode.Stsfld) { return(false); } if (exprInit.Operand != nextExpr.Operand) { return(false); } break; case ILCode.CallGetter: // non-static getters would have the 'this' argument if (exprInit.Arguments.Count != 0) { return(false); } if (storeInstruction != ILCode.CallSetter) { return(false); } if (!IsGetterSetterPair(exprInit.Operand, nextExpr.Operand)) { return(false); } break; default: return(false); } ILExpression addExpr = nextExpr.Arguments[0]; int incrementAmount; ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount); if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar))) { return(false); } if (recombineVariable) { // Split local variable, unsplit these two instances // replace nextExpr.Operand with exprInit.Operand ReplaceVariables(method, oldVar => oldVar == nextExpr.Operand ? (ILVariable)exprInit.Operand : oldVar); } switch (loadInstruction) { case ILCode.Ldloc: exprInit.Code = ILCode.Ldloca; break; case ILCode.Ldsfld: exprInit.Code = ILCode.Ldsflda; break; case ILCode.CallGetter: exprInit = new ILExpression(ILCode.AddressOf, null, exprInit); break; } expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit); body.RemoveAt(pos + 1); // TODO ILRanges return(true); }
ILExpression IntroducePostIncrementForInstanceFields(ILExpression expr) { // stfld(field, ldloc(instance), add(stloc(helperVar, ldfld(field, ldloc(instance))), ldc.i4(1))) // -> stloc(helperVar, postincrement(1, ldflda(field, ldloc(instance)))) // Also works for array elements and pointers: // stelem.any(T, ldloc(instance), ldloc(pos), add(stloc(helperVar, ldelem.any(T, ldloc(instance), ldloc(pos))), ldc.i4(1))) // -> stloc(helperVar, postincrement(1, ldelema(ldloc(instance), ldloc(pos)))) // stobj(T, ldloc(ptr), add(stloc(helperVar, ldobj(T, ldloc(ptr)), ldc.i4(1)))) // -> stloc(helperVar, postIncrement(1, ldloc(ptr))) // callsetter(set_P, ldloc(instance), add(stloc(helperVar, callgetter(get_P, ldloc(instance))), ldc.i4(1))) // -> stloc(helperVar, postIncrement(1, propertyaddress. callgetter(get_P, ldloc(instance)))) if (!(expr.Code == ILCode.Stfld || expr.Code.IsStoreToArray() || expr.Code == ILCode.Stobj || expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter)) { return(null); } // Test that all arguments except the last are ldloc (1 arg for fields and pointers, 2 args for arrays) for (int i = 0; i < expr.Arguments.Count - 1; i++) { if (expr.Arguments[i].Code != ILCode.Ldloc) { return(null); } } ILExpression addExpr = expr.Arguments[expr.Arguments.Count - 1]; int incrementAmount; ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount); ILVariable helperVar; ILExpression initialValue; if (!(incrementAmount != 0 && addExpr.Arguments[0].Match(ILCode.Stloc, out helperVar, out initialValue))) { return(null); } if (expr.Code == ILCode.Stfld) { if (initialValue.Code != ILCode.Ldfld) { return(null); } // There might be two different FieldReference instances, so we compare the field's signatures: FieldReference getField = (FieldReference)initialValue.Operand; FieldReference setField = (FieldReference)expr.Operand; if (!(TypeAnalysis.IsSameType(getField.DeclaringType, setField.DeclaringType) && getField.Name == setField.Name && TypeAnalysis.IsSameType(getField.FieldType, setField.FieldType))) { return(null); } } else if (expr.Code == ILCode.Stobj) { if (!(initialValue.Code == ILCode.Ldobj && initialValue.Operand == expr.Operand)) { return(null); } } else if (expr.Code == ILCode.CallSetter) { if (!(initialValue.Code == ILCode.CallGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand))) { return(null); } } else if (expr.Code == ILCode.CallvirtSetter) { if (!(initialValue.Code == ILCode.CallvirtGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand))) { return(null); } } else { if (!initialValue.Code.IsLoadFromArray()) { return(null); } } Debug.Assert(expr.Arguments.Count - 1 == initialValue.Arguments.Count); for (int i = 0; i < initialValue.Arguments.Count; i++) { if (!initialValue.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand)) { return(null); } } ILExpression stloc = addExpr.Arguments[0]; if (expr.Code == ILCode.Stobj) { stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue.Arguments[0]); } else if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) { initialValue = new ILExpression(ILCode.AddressOf, null, initialValue); stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue); } else { stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue); initialValue.Code = (expr.Code == ILCode.Stfld ? ILCode.Ldflda : ILCode.Ldelema); } // TODO: ILRanges? return(stloc); }
static ILExpression SimplifyLdObjAndStObj(ILExpression expr, ref bool modified) { if (expr.Code == ILCode.Initobj) { expr.Code = ILCode.Stobj; expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand)); modified = true; } else if (expr.Code == ILCode.Cpobj) { expr.Code = ILCode.Stobj; expr.Arguments[1] = new ILExpression(ILCode.Ldobj, expr.Operand, expr.Arguments[1]); modified = true; } ILExpression arg, arg2; TypeReference type; ILCode? newCode = null; if (expr.Match(ILCode.Stobj, out type, out arg, out arg2)) { switch (arg.Code) { case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break; case ILCode.Ldloca: newCode = ILCode.Stloc; break; case ILCode.Ldflda: newCode = ILCode.Stfld; break; case ILCode.Ldsflda: newCode = ILCode.Stsfld; break; } } else if (expr.Match(ILCode.Ldobj, out type, out arg)) { switch (arg.Code) { case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break; case ILCode.Ldloca: newCode = ILCode.Ldloc; break; case ILCode.Ldflda: newCode = ILCode.Ldfld; break; case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break; } } if (newCode != null) { arg.Code = newCode.Value; if (expr.Code == ILCode.Stobj) { arg.InferredType = expr.InferredType; arg.ExpectedType = expr.ExpectedType; arg.Arguments.Add(arg2); } arg.ILRanges.AddRange(expr.ILRanges); modified = true; return(arg); } else { return(expr); } }
public static bool Match <T>(this ILNode node, ILCode code, out T operand, out ILExpression arg1, out ILExpression arg2) { List <ILExpression> args; if (node.Match(code, out operand, out args) && args.Count == 2) { arg1 = args[0]; arg2 = args[1]; return(true); } arg1 = null; arg2 = null; return(false); }
bool HandleStringFixing(ILVariable pinnedVar, List <ILNode> body, ref int pos, ref ILExpression fixedStmtInitializer) { // fixed (stloc(pinnedVar, ldloc(text))) { // var1 = var2 = conv.i(ldloc(pinnedVar)) // if (logicnot(logicnot(var1))) { // var2 = add(var1, call(RuntimeHelpers::get_OffsetToStringData)) // } // stloc(ptrVar, var2) // ... if (pos >= body.Count) { return(false); } ILVariable var1, var2; ILExpression varAssignment, ptrInitialization; if (!(body[pos].Match(ILCode.Stloc, out var1, out varAssignment) && varAssignment.Match(ILCode.Stloc, out var2, out ptrInitialization))) { return(false); } if (!(var1.IsGenerated && var2.IsGenerated)) { return(false); } if (ptrInitialization.Code == ILCode.Conv_I || ptrInitialization.Code == ILCode.Conv_U) { ptrInitialization = ptrInitialization.Arguments[0]; } if (!ptrInitialization.MatchLdloc(pinnedVar)) { return(false); } ILCondition ifStmt = body[pos + 1] as ILCondition; if (!(ifStmt != null && ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && (ifStmt.FalseBlock == null || ifStmt.FalseBlock.Body.Count == 0))) { return(false); } if (!UnpackDoubleNegation(ifStmt.Condition).MatchLdloc(var1)) { return(false); } ILVariable assignedVar; ILExpression assignedExpr; if (!(ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out assignedVar, out assignedExpr) && assignedVar == var2 && assignedExpr.Code == ILCode.Add)) { return(false); } MethodReference calledMethod; if (!(assignedExpr.Arguments[0].MatchLdloc(var1))) { return(false); } if (!(assignedExpr.Arguments[1].Match(ILCode.Call, out calledMethod) || assignedExpr.Arguments[1].Match(ILCode.CallGetter, out calledMethod))) { return(false); } if (!(calledMethod.Name == "get_OffsetToStringData" && calledMethod.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers")) { return(false); } ILVariable pointerVar; if (body[pos + 2].Match(ILCode.Stloc, out pointerVar, out assignedExpr) && assignedExpr.MatchLdloc(var2)) { pos += 3; fixedStmtInitializer.Operand = pointerVar; return(true); } return(false); }
void CachedDelegateInitializationWithLocal(ILBlock block, ref int i) { // if (logicnot(ldloc(v))) { // stloc(v, newobj(Action::.ctor, ldloc(displayClass), ldftn(method))) // } else { // } // ...(..., ldloc(v), ...) ILCondition c = block.Body[i] as ILCondition; if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null) { return; } if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) { return; } if (!c.Condition.Match(ILCode.LogicNot)) { return; } ILExpression condition = c.Condition.Arguments.Single() as ILExpression; if (condition == null || condition.Code != ILCode.Ldloc) { return; } ILVariable v = (ILVariable)condition.Operand; ILExpression stloc = c.TrueBlock.Body[0] as ILExpression; if (!(stloc != null && stloc.Code == ILCode.Stloc && (ILVariable)stloc.Operand == v)) { return; } ILExpression newObj = stloc.Arguments[0]; if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2)) { return; } if (newObj.Arguments[0].Code != ILCode.Ldloc) { return; } if (newObj.Arguments[1].Code != ILCode.Ldftn) { return; } MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod)) { return; } ILNode followingNode = block.Body.ElementAtOrDefault(i + 1); int ldlocOperandCount = followingNode .EnumerateSelfAndChildrenRecursive() .OfType <ILExpression>() .Count( e => e.Code == ILCode.Ldloc && (ILVariable)e.Operand == v); if (followingNode != null && ldlocOperandCount == 1) { ILInlining inlining = new ILInlining(method); if (!(inlining.numLdloc.GetOrDefault(v) == 2 && inlining.numStloc.GetOrDefault(v) == 2 && inlining.numLdloca.GetOrDefault(v) == 0)) { return; } // Find the store instruction that initializes the local to null: foreach (ILBlock storeBlock in method.EnumerateSelfAndChildrenRecursive().OfType <ILBlock>()) { for (int j = 0; j < storeBlock.Body.Count; j++) { ILVariable storedVar; ILExpression storedExpr; if (storeBlock.Body[j].Match(ILCode.Stloc, out storedVar, out storedExpr) && storedVar == v && storedExpr.Match(ILCode.Ldnull)) { // Remove the instruction storeBlock.Body.RemoveAt(j); if (storeBlock == block && j < i) { i--; } break; } } } block.Body[i] = stloc; // remove the 'if (v==null)' inlining = new ILInlining(method); inlining.InlineIfPossible(block.Body, ref i); } }
void CachedDelegateInitializationWithField(ILBlock block, ref int i) { // if (logicnot(ldsfld(field))) { // stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method))) // } else { // } // ...(..., ldsfld(field), ...) ILCondition c = block.Body[i] as ILCondition; if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null) { return; } if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) { return; } if (!c.Condition.Match(ILCode.LogicNot)) { return; } ILExpression condition = c.Condition.Arguments.Single() as ILExpression; if (condition == null || condition.Code != ILCode.Ldsfld) { return; } FieldDefinition field = ((FieldReference)condition.Operand).ResolveWithinSameModule(); // field is defined in current assembly if (field == null || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) { return; } ILExpression stsfld = c.TrueBlock.Body[0] as ILExpression; if (!(stsfld != null && stsfld.Code == ILCode.Stsfld && ((FieldReference)stsfld.Operand).ResolveWithinSameModule() == field)) { return; } ILExpression newObj = stsfld.Arguments[0]; if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2)) { return; } if (newObj.Arguments[0].Code != ILCode.Ldnull) { return; } if (newObj.Arguments[1].Code != ILCode.Ldftn) { return; } MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod)) { return; } ILNode followingNode = block.Body.ElementAtOrDefault(i + 1); int ldfldResolvingWithinSameMethodCount = followingNode .EnumerateSelfAndChildrenRecursive() .OfType <ILExpression>() .Count( e => e.Code == ILCode.Ldsfld && ((FieldReference)e.Operand).ResolveWithinSameModule() == field); if (followingNode != null && ldfldResolvingWithinSameMethodCount == 1) { foreach (ILExpression parent in followingNode.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>()) { for (int j = 0; j < parent.Arguments.Count; j++) { if (parent.Arguments[j].Code == ILCode.Ldsfld && ((FieldReference)parent.Arguments[j].Operand).ResolveWithinSameModule() == field) { parent.Arguments[j] = newObj; block.Body.RemoveAt(i); i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: false); return; } } } } }
public static bool MatchStloc(this ILNode node, ILVariable expectedVar, out ILExpression expr) { ILVariable v; return(node.Match(ILCode.Stloc, out v, out expr) && v == expectedVar); }
public static bool Match(this ILNode node, ILCode code) { ILExpression expr = node as ILExpression; return(expr != null && expr.Prefixes == null && expr.Code == code); }
List <ILNode> ConvertToAst(List <ByteCode> body, HashSet <ExceptionHandler> ehs) { List <ILNode> ast = new List <ILNode>(); while (ehs.Any()) { ILTryCatchBlock tryCatchBlock = new ILTryCatchBlock(); // Find the first and widest scope int tryStart = ehs.Min(eh => eh.TryStart.Offset); int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset); var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).OrderBy(eh => eh.TryStart.Offset).ToList(); // Remember that any part of the body migt have been removed due to unreachability // Cut all instructions up to the try block { int tryStartIdx = 0; while (tryStartIdx < body.Count && body[tryStartIdx].Offset < tryStart) { tryStartIdx++; } ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx))); } // Cut the try block { HashSet <ExceptionHandler> nestedEHs = new HashSet <ExceptionHandler>(ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd))); ehs.ExceptWith(nestedEHs); int tryEndIdx = 0; while (tryEndIdx < body.Count && body[tryEndIdx].Offset < tryEnd) { tryEndIdx++; } tryCatchBlock.TryBlock = new ILBlock(ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs)); } // Cut all handlers tryCatchBlock.CatchBlocks = new List <ILTryCatchBlock.CatchBlock>(); foreach (ExceptionHandler eh in handlers) { int handlerEndOffset = eh.HandlerEnd == null ? methodDef.Body.CodeSize : eh.HandlerEnd.Offset; int startIdx = 0; while (startIdx < body.Count && body[startIdx].Offset < eh.HandlerStart.Offset) { startIdx++; } int endIdx = 0; while (endIdx < body.Count && body[endIdx].Offset < handlerEndOffset) { endIdx++; } HashSet <ExceptionHandler> nestedEHs = new HashSet <ExceptionHandler>(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < handlerEndOffset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= handlerEndOffset))); ehs.ExceptWith(nestedEHs); List <ILNode> handlerAst = ConvertToAst(body.CutRange(startIdx, endIdx - startIdx), nestedEHs); if (eh.HandlerType == ExceptionHandlerType.Catch) { ILTryCatchBlock.CatchBlock catchBlock = new ILTryCatchBlock.CatchBlock() { ExceptionType = eh.CatchType, Body = handlerAst }; // Handle the automatically pushed exception on the stack ByteCode ldexception = ldexceptions[eh]; if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0) { // Exception is not used catchBlock.ExceptionVariable = null; } else if (ldexception.StoreTo.Count == 1) { ILExpression first = catchBlock.Body[0] as ILExpression; if (first != null && first.Code == ILCode.Pop && first.Arguments[0].Code == ILCode.Ldloc && first.Arguments[0].Operand == ldexception.StoreTo[0]) { // The exception is just poped - optimize it all away; if (context.Settings.AlwaysGenerateExceptionVariableForCatchBlocks) { catchBlock.ExceptionVariable = new ILVariable() { Name = "ex_" + eh.HandlerStart.Offset.ToString("X2"), IsGenerated = true } } ; else { catchBlock.ExceptionVariable = null; } catchBlock.Body.RemoveAt(0); } else { catchBlock.ExceptionVariable = ldexception.StoreTo[0]; } } else { ILVariable exTemp = new ILVariable() { Name = "ex_" + eh.HandlerStart.Offset.ToString("X2"), IsGenerated = true }; catchBlock.ExceptionVariable = exTemp; foreach (ILVariable storeTo in ldexception.StoreTo) { catchBlock.Body.Insert(0, new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, exTemp))); } } tryCatchBlock.CatchBlocks.Add(catchBlock); } else if (eh.HandlerType == ExceptionHandlerType.Finally) { tryCatchBlock.FinallyBlock = new ILBlock(handlerAst); } else if (eh.HandlerType == ExceptionHandlerType.Fault) { tryCatchBlock.FaultBlock = new ILBlock(handlerAst); } else { // TODO: ExceptionHandlerType.Filter } } ehs.ExceptWith(handlers); ast.Add(tryCatchBlock); } // Add whatever is left ast.AddRange(ConvertToAst(body)); return(ast); }
List <ILNode> ConvertToAst(List <ByteCode> body) { List <ILNode> ast = new List <ILNode>(); // Convert stack-based IL code to ILAst tree foreach (ByteCode byteCode in body) { ILRange ilRange = new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset }; if (byteCode.StackBefore == null) { // Unreachable code continue; } ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand); expr.ILRanges.Add(ilRange); if (byteCode.Prefixes != null && byteCode.Prefixes.Length > 0) { ILExpressionPrefix[] prefixes = new ILExpressionPrefix[byteCode.Prefixes.Length]; for (int i = 0; i < prefixes.Length; i++) { prefixes[i] = new ILExpressionPrefix((ILCode)byteCode.Prefixes[i].OpCode.Code, byteCode.Prefixes[i].Operand); } expr.Prefixes = prefixes; } // Label for this instruction if (byteCode.Label != null) { ast.Add(byteCode.Label); } // Reference arguments using temporary variables int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length; for (int i = byteCode.StackBefore.Length - popCount; i < byteCode.StackBefore.Length; i++) { StackSlot slot = byteCode.StackBefore[i]; expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom)); } // Store the result to temporary variable(s) if needed if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) { ast.Add(expr); } else if (byteCode.StoreTo.Count == 1) { ast.Add(new ILExpression(ILCode.Stloc, byteCode.StoreTo[0], expr)); } else { ILVariable tmpVar = new ILVariable() { Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true }; ast.Add(new ILExpression(ILCode.Stloc, tmpVar, expr)); foreach (ILVariable storeTo in byteCode.StoreTo.AsEnumerable().Reverse()) { ast.Add(new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, tmpVar))); } } } return(ast); }
public List <ILNode> Build(File.Code code, ErrorContext error = null) { if (code == null) { throw new ArgumentNullException("code"); } Stream stream = code.Data; if (stream == null) { throw new ArgumentNullException("code.Data"); } if (!stream.CanRead) { throw new ArgumentException("Must be readable", "code_stream"); } if (!stream.CanSeek) { throw new ArgumentException("Must be seekable", "code_stream"); } if (stream.Length == 0) { return(new List <ILNode>()); // empty stream } StartingOffset = code.CodePosition; Error = error ?? new ErrorContext(code.Name); labels = new Dictionary <int, ILLabel>(); // cause they are all the same stream.Position = 0; r = new BinaryReader(stream); CurrentPC = 0; List <ILNode> list = new List <ILNode>(); Dictionary <int, int> pcToExpressoin = new Dictionary <int, int>(); Start(list); while (stream.Position < stream.Length) { CurrentPC = (int)stream.Position / 4; CurrentRaw = r.ReadUInt32(); ILExpression e = CreateExpression(list); if (e != null) { /* * // hack here cause of issues * if (e.Code == GMCode.Conv) * { * var prev = list.Last.Value as ILExpression; * Debug.Assert(prev.Code != GMCode.Pop); * prev.ILRanges.Add(new ILRange(CurrentPC, CurrentPC)); * prev.Types = e.Types; // don't add it * } * else */ pcToExpressoin.Add(CurrentPC, list.Count); list.Add(e); } } CurrentPC = (int)stream.Position / 4; CurrentRaw = 0; if (labelExists(CurrentPC)) // this is in case we do have a jump but we need to exit clean { pcToExpressoin.Add(CurrentPC, list.Count); list.Add(CreateExpression(GMCode.Exit, null)); // make sure we got an exit as the last code // we HAVE to have an exit } else { ILExpression last = list.Last() as ILExpression; if (last.Code != GMCode.Ret && last.Code != GMCode.Exit) { pcToExpressoin.Add(CurrentPC, list.Count); list.Add(CreateExpression(GMCode.Exit, null)); // make sure we got an exit as the last code } } foreach (var l in labels) { int n; if (pcToExpressoin.TryGetValue(l.Key, out n)) { list[n].UserData = l.Value; } } var rlist = new List <ILNode>(); for (int i = 0; i < list.Count; i++) { ILExpression e = list[i] as ILExpression; if (e != null) { if (e.UserData != null) { rlist.Add(e.UserData as ILLabel); e.UserData = null; } if (e.Code == GMCode.Conv) { ILExpression ne = list[i + 1] as ILExpression; ne.ILRanges.AddRange(e.ILRanges); ne.Types = e.Types; continue; // skip } } rlist.Add(list[i]); } Finish(rlist); return(rlist); }
void RunInference(ILExpression expr) { bool anyArgumentIsMissingExpectedType = expr.Arguments.Any(a => a.ExpectedType == null); if (expr.InferredType == null || anyArgumentIsMissingExpectedType) InferTypeForExpression(expr, expr.ExpectedType, forceInferChildren: anyArgumentIsMissingExpectedType); foreach (var arg in expr.Arguments) { if (arg.Code != ILCode.Stloc) { RunInference(arg); } } }
bool MakeAssignmentExpression(List <ILNode> body, ILExpression expr, int pos) { // exprVar = ... // stloc(v, exprVar) // -> // exprVar = stloc(v, ...)) ILVariable exprVar; ILExpression initializer; if (!(expr.Match(ILCode.Stloc, out exprVar, out initializer) && exprVar.IsGenerated)) { return(false); } ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression; ILVariable v; ILExpression stLocArg; if (nextExpr.Match(ILCode.Stloc, out v, out stLocArg) && stLocArg.MatchLdloc(exprVar)) { ILExpression store2 = body.ElementAtOrDefault(pos + 2) as ILExpression; if (StoreCanBeConvertedToAssignment(store2, exprVar)) { // expr_44 = ... // stloc(v1, expr_44) // anystore(v2, expr_44) // -> // stloc(v1, anystore(v2, ...)) ILInlining inlining = new ILInlining(method); if (inlining.numLdloc.GetOrDefault(exprVar) == 2 && inlining.numStloc.GetOrDefault(exprVar) == 1) { body.RemoveAt(pos + 2); // remove store2 body.RemoveAt(pos); // remove expr = ... nextExpr.Arguments[0] = store2; store2.Arguments[store2.Arguments.Count - 1] = initializer; inlining.InlineIfPossible(body, ref pos); return(true); } } body.RemoveAt(pos + 1); // remove stloc nextExpr.Arguments[0] = initializer; ((ILExpression)body[pos]).Arguments[0] = nextExpr; return(true); } else if ((nextExpr.Code == ILCode.Stsfld || nextExpr.Code == ILCode.CallSetter || nextExpr.Code == ILCode.CallvirtSetter) && nextExpr.Arguments.Count == 1) { // exprVar = ... // stsfld(fld, exprVar) // -> // exprVar = stsfld(fld, ...)) if (nextExpr.Arguments[0].MatchLdloc(exprVar)) { body.RemoveAt(pos + 1); // remove stsfld nextExpr.Arguments[0] = initializer; ((ILExpression)body[pos]).Arguments[0] = nextExpr; return(true); } } return(false); }
string GenerateNameForVariable(ILVariable variable, ILBlock methodBody) { string proposedName = null; if (variable.Type == context.CurrentType.Module.TypeSystem.Int32) { // test whether the variable might be a loop counter bool isLoopCounter = false; foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive <ILWhileLoop>()) { ILExpression expr = loop.Condition; while (expr != null && expr.Code == ILCode.LogicNot) { expr = expr.Arguments[0]; } if (expr != null) { switch (expr.Code) { case ILCode.Clt: case ILCode.Clt_Un: case ILCode.Cgt: case ILCode.Cgt_Un: ILVariable loadVar; if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) { isLoopCounter = true; } break; } } } if (isLoopCounter) { // For loop variables, use i,j,k,l,m,n for (char c = 'i'; c <= maxLoopVariableName; c++) { if (!typeNames.ContainsKey(c.ToString())) { proposedName = c.ToString(); break; } } } } if (string.IsNullOrEmpty(proposedName)) { var proposedNameForStores = (from expr in methodBody.GetSelfAndChildrenRecursive <ILExpression>() where expr.Code == ILCode.Stloc && expr.Operand == variable select GetNameFromExpression(expr.Arguments.Single()) ).Except(fieldNamesInCurrentType).ToList(); if (proposedNameForStores.Count == 1) { proposedName = proposedNameForStores[0]; } } if (string.IsNullOrEmpty(proposedName)) { var proposedNameForLoads = (from expr in methodBody.GetSelfAndChildrenRecursive <ILExpression>() from i in Enumerable.Range(0, expr.Arguments.Count) let arg = expr.Arguments[i] where arg.Code == ILCode.Ldloc && arg.Operand == variable select GetNameForArgument(expr, i) ).Except(fieldNamesInCurrentType).ToList(); if (proposedNameForLoads.Count == 1) { proposedName = proposedNameForLoads[0]; } } if (string.IsNullOrEmpty(proposedName)) { proposedName = GetNameByType(variable.Type); } // remove any numbers from the proposed name int number; proposedName = SplitName(proposedName, out number); if (!typeNames.ContainsKey(proposedName)) { typeNames.Add(proposedName, 0); } int count = ++typeNames[proposedName]; if (count > 1) { return(proposedName + count.ToString()); } else { return(proposedName); } }
public static bool MatchLastAndBr <T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel) { if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out operand, out arg) && bb.Body.LastOrDefault().Match(ILCode.Br, out brLabel)) { return(true); } operand = default(T); arg = null; brLabel = null; return(false); }
TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false) { switch (expr.Code) { #region Logical operators case ILCode.LogicNot: if (forceInferChildren) { InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); } return typeSystem.Boolean; case ILCode.LogicAnd: case ILCode.LogicOr: // if Operand is set the logic and/or expression is a custom operator // we can deal with it the same as a normal invocation. if (expr.Operand != null) goto case ILCode.Call; if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean); } return typeSystem.Boolean; case ILCode.TernaryOp: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); } return InferBinaryArguments(expr.Arguments[1], expr.Arguments[2], expectedType, forceInferChildren); case ILCode.NullCoalescing: return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType, forceInferChildren); #endregion #region Variable load/store case ILCode.Stloc: { ILVariable v = (ILVariable)expr.Operand; if (forceInferChildren) { // do not use 'expectedType' in here! InferTypeForExpression(expr.Arguments.Single(), v.Type); } return v.Type; } case ILCode.Ldloc: { ILVariable v = (ILVariable)expr.Operand; if (v.Type == null && singleLoadVariables.Contains(v)) { v.Type = expectedType; } return v.Type; } case ILCode.Ldloca: { ILVariable v = (ILVariable)expr.Operand; if (v.Type != null) return new ByReferenceType(v.Type); else return null; } #endregion #region Call / NewObj case ILCode.Call: case ILCode.Callvirt: case ILCode.CallGetter: case ILCode.CallvirtGetter: case ILCode.CallSetter: case ILCode.CallvirtSetter: { MethodReference method = (MethodReference)expr.Operand; if (forceInferChildren) { for (int i = 0; i < expr.Arguments.Count; i++) { if (i == 0 && method.HasThis) { InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(method.DeclaringType, expr.GetPrefix(ILCode.Constrained))); } else { InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1 : i].ParameterType, method)); } } } if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) { return SubstituteTypeArgs(method.Parameters.Last().ParameterType, method); } else { return SubstituteTypeArgs(method.ReturnType, method); } } case ILCode.Newobj: { MethodReference ctor = (MethodReference)expr.Operand; if (forceInferChildren) { for (int i = 0; i < ctor.Parameters.Count; i++) { InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(ctor.Parameters[i].ParameterType, ctor)); } } return ctor.DeclaringType; } case ILCode.InitObject: case ILCode.InitCollection: return InferTypeForExpression(expr.Arguments[0], expectedType); case ILCode.InitializedObject: // expectedType should always be known due to the parent method call / property setter Debug.Assert(expectedType != null); return expectedType; #endregion #region Load/Store Fields case ILCode.Ldfld: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained))); } return GetFieldType((FieldReference)expr.Operand); case ILCode.Ldsfld: return GetFieldType((FieldReference)expr.Operand); case ILCode.Ldflda: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained))); } return new ByReferenceType(GetFieldType((FieldReference)expr.Operand)); case ILCode.Ldsflda: return new ByReferenceType(GetFieldType((FieldReference)expr.Operand)); case ILCode.Stfld: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained))); InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand)); } return GetFieldType((FieldReference)expr.Operand); case ILCode.Stsfld: if (forceInferChildren) InferTypeForExpression(expr.Arguments[0], GetFieldType((FieldReference)expr.Operand)); return GetFieldType((FieldReference)expr.Operand); #endregion #region Reference/Pointer instructions case ILCode.Ldind_Ref: return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); case ILCode.Stind_Ref: if (forceInferChildren) { TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); InferTypeForExpression(expr.Arguments[1], elementType); } return null; case ILCode.Ldobj: { TypeReference type = (TypeReference)expr.Operand; var argType = InferTypeForExpression(expr.Arguments[0], null); if (argType is PointerType || argType is ByReferenceType) { var elementType = ((TypeSpecification)argType).ElementType; int infoAmount = GetInformationAmount(elementType); if (infoAmount == 1 && GetInformationAmount(type) == 8) { // A bool can be loaded from both bytes and sbytes. type = elementType; } if (infoAmount >= 8 && infoAmount <= 64 && infoAmount == GetInformationAmount(type)) { // An integer can be loaded as another integer of the same size. // For integers smaller than 32 bit, the signs must match (as loading performs sign extension) bool? elementTypeIsSigned = IsSigned(elementType); bool? typeIsSigned = IsSigned(type); if (elementTypeIsSigned != null && typeIsSigned != null) { if (infoAmount >= 32 || elementTypeIsSigned == typeIsSigned) type = elementType; } } } if (argType is PointerType) InferTypeForExpression(expr.Arguments[0], new PointerType(type)); else InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type)); return type; } case ILCode.Stobj: { TypeReference operandType = (TypeReference)expr.Operand; TypeReference pointerType = InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType)); TypeReference elementType; if (pointerType is PointerType) elementType = ((PointerType)pointerType).ElementType; else if (pointerType is ByReferenceType) elementType = ((ByReferenceType)pointerType).ElementType; else elementType = null; if (elementType != null) { // An integer can be stored in any other integer of the same size. int infoAmount = GetInformationAmount(elementType); if (infoAmount == 1 && GetInformationAmount(operandType) == 8) operandType = elementType; else if (infoAmount == GetInformationAmount(operandType) && IsSigned(elementType) != null && IsSigned(operandType) != null) operandType = elementType; } if (forceInferChildren) { if (pointerType is PointerType) InferTypeForExpression(expr.Arguments[0], new PointerType(operandType)); else if (!IsSameType(operandType, expr.Operand as TypeReference)) InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType)); InferTypeForExpression(expr.Arguments[1], operandType); } return operandType; } case ILCode.Initobj: return null; case ILCode.DefaultValue: return (TypeReference)expr.Operand; case ILCode.Localloc: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Int32); } if (expectedType is PointerType) return expectedType; else return typeSystem.IntPtr; case ILCode.Sizeof: return typeSystem.Int32; case ILCode.PostIncrement: case ILCode.PostIncrement_Ovf: case ILCode.PostIncrement_Ovf_Un: { TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); if (forceInferChildren && elementType != null) { // Assign expected type to the child expression InferTypeForExpression(expr.Arguments[0], new ByReferenceType(elementType)); } return elementType; } case ILCode.Mkrefany: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], (TypeReference)expr.Operand); } return typeSystem.TypedReference; case ILCode.Refanytype: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference); } return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true); case ILCode.Refanyval: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference); } return new ByReferenceType((TypeReference)expr.Operand); case ILCode.AddressOf: { TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType)); return t != null ? new ByReferenceType(t) : null; } case ILCode.ValueOf: return GetNullableTypeArgument(InferTypeForExpression(expr.Arguments[0], CreateNullableType(expectedType))); case ILCode.NullableOf: return CreateNullableType(InferTypeForExpression(expr.Arguments[0], GetNullableTypeArgument(expectedType))); #endregion #region Arithmetic instructions case ILCode.Not: // bitwise complement case ILCode.Neg: return InferTypeForExpression(expr.Arguments.Single(), expectedType); case ILCode.Add: return InferArgumentsInAddition(expr, null, expectedType); case ILCode.Sub: return InferArgumentsInSubtraction(expr, null, expectedType); case ILCode.Mul: case ILCode.Or: case ILCode.And: case ILCode.Xor: return InferArgumentsInBinaryOperator(expr, null, expectedType); case ILCode.Add_Ovf: return InferArgumentsInAddition(expr, true, expectedType); case ILCode.Sub_Ovf: return InferArgumentsInSubtraction(expr, true, expectedType); case ILCode.Mul_Ovf: case ILCode.Div: case ILCode.Rem: return InferArgumentsInBinaryOperator(expr, true, expectedType); case ILCode.Add_Ovf_Un: return InferArgumentsInAddition(expr, false, expectedType); case ILCode.Sub_Ovf_Un: return InferArgumentsInSubtraction(expr, false, expectedType); case ILCode.Mul_Ovf_Un: case ILCode.Div_Un: case ILCode.Rem_Un: return InferArgumentsInBinaryOperator(expr, false, expectedType); case ILCode.Shl: if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); if (expectedType != null && ( expectedType.MetadataType == MetadataType.Int32 || expectedType.MetadataType == MetadataType.UInt32 || expectedType.MetadataType == MetadataType.Int64 || expectedType.MetadataType == MetadataType.UInt64) ) return NumericPromotion(InferTypeForExpression(expr.Arguments[0], expectedType)); else return NumericPromotion(InferTypeForExpression(expr.Arguments[0], null)); case ILCode.Shr: case ILCode.Shr_Un: { if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); TypeReference type = NumericPromotion(InferTypeForExpression(expr.Arguments[0], null)); TypeReference expectedInputType = null; switch (type.MetadataType) { case MetadataType.Int32: if (expr.Code == ILCode.Shr_Un) expectedInputType = typeSystem.UInt32; break; case MetadataType.UInt32: if (expr.Code == ILCode.Shr) expectedInputType = typeSystem.Int32; break; case MetadataType.Int64: if (expr.Code == ILCode.Shr_Un) expectedInputType = typeSystem.UInt64; break; case MetadataType.UInt64: if (expr.Code == ILCode.Shr) expectedInputType = typeSystem.UInt64; break; } if (expectedInputType != null) { InferTypeForExpression(expr.Arguments[0], expectedInputType); return expectedInputType; } else { return type; } } case ILCode.CompoundAssignment: { var op = expr.Arguments[0]; if (op.Code == ILCode.NullableOf) op = op.Arguments[0].Arguments[0]; var varType = InferTypeForExpression(op.Arguments[0], null); if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], varType); } return varType; } #endregion #region Constant loading instructions case ILCode.Ldnull: return typeSystem.Object; case ILCode.Ldstr: return typeSystem.String; case ILCode.Ldftn: case ILCode.Ldvirtftn: return typeSystem.IntPtr; case ILCode.Ldc_I4: if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1)) return typeSystem.Boolean; if (expectedType is PointerType && (int)expr.Operand == 0) return expectedType; if (IsIntegerOrEnum(expectedType) && OperandFitsInType(expectedType, (int)expr.Operand)) return expectedType; else return typeSystem.Int32; case ILCode.Ldc_I8: if (expectedType is PointerType && (long)expr.Operand == 0) return expectedType; if (IsIntegerOrEnum(expectedType) && GetInformationAmount(expectedType) >= NativeInt) return expectedType; else return typeSystem.Int64; case ILCode.Ldc_R4: return typeSystem.Single; case ILCode.Ldc_R8: return typeSystem.Double; case ILCode.Ldc_Decimal: return new TypeReference("System", "Decimal", module, module.TypeSystem.Corlib, true); case ILCode.Ldtoken: if (expr.Operand is TypeReference) return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true); else if (expr.Operand is FieldReference) return new TypeReference("System", "RuntimeFieldHandle", module, module.TypeSystem.Corlib, true); else return new TypeReference("System", "RuntimeMethodHandle", module, module.TypeSystem.Corlib, true); case ILCode.Arglist: return new TypeReference("System", "RuntimeArgumentHandle", module, module.TypeSystem.Corlib, true); #endregion #region Array instructions case ILCode.Newarr: if (forceInferChildren) { var lengthType = InferTypeForExpression(expr.Arguments.Single(), null); if (lengthType == typeSystem.IntPtr) { lengthType = typeSystem.Int64; } else if (lengthType == typeSystem.UIntPtr) { lengthType = typeSystem.UInt64; } else if (lengthType != typeSystem.UInt32 && lengthType != typeSystem.Int64 && lengthType != typeSystem.UInt64) { lengthType = typeSystem.Int32; } if (forceInferChildren) { InferTypeForExpression(expr.Arguments.Single(), lengthType); } } return new ArrayType((TypeReference)expr.Operand); case ILCode.InitArray: var operandAsArrayType = (ArrayType)expr.Operand; if (forceInferChildren) { foreach (ILExpression arg in expr.Arguments) InferTypeForExpression(arg, operandAsArrayType.ElementType); } return operandAsArrayType; case ILCode.Ldlen: return typeSystem.Int32; case ILCode.Ldelem_U1: case ILCode.Ldelem_U2: case ILCode.Ldelem_U4: case ILCode.Ldelem_I1: case ILCode.Ldelem_I2: case ILCode.Ldelem_I4: case ILCode.Ldelem_I8: case ILCode.Ldelem_R4: case ILCode.Ldelem_R8: case ILCode.Ldelem_I: case ILCode.Ldelem_Ref: { ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; if (forceInferChildren) { InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); } return arrayType != null ? arrayType.ElementType : null; } case ILCode.Ldelem_Any: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); } return (TypeReference)expr.Operand; case ILCode.Ldelema: { ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); return arrayType != null ? new ByReferenceType(arrayType.ElementType) : null; } case ILCode.Stelem_I: case ILCode.Stelem_I1: case ILCode.Stelem_I2: case ILCode.Stelem_I4: case ILCode.Stelem_I8: case ILCode.Stelem_R4: case ILCode.Stelem_R8: case ILCode.Stelem_Ref: case ILCode.Stelem_Any: { ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; if (forceInferChildren) { InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); if (arrayType != null) { InferTypeForExpression(expr.Arguments[2], arrayType.ElementType); } } return arrayType != null ? arrayType.ElementType : null; } #endregion #region Conversion instructions case ILCode.Conv_I1: case ILCode.Conv_Ovf_I1: case ILCode.Conv_Ovf_I1_Un: return HandleConversion(8, true, expr.Arguments[0], expectedType, typeSystem.SByte); case ILCode.Conv_I2: case ILCode.Conv_Ovf_I2: case ILCode.Conv_Ovf_I2_Un: return HandleConversion(16, true, expr.Arguments[0], expectedType, typeSystem.Int16); case ILCode.Conv_I4: case ILCode.Conv_Ovf_I4: case ILCode.Conv_Ovf_I4_Un: return HandleConversion(32, true, expr.Arguments[0], expectedType, typeSystem.Int32); case ILCode.Conv_I8: case ILCode.Conv_Ovf_I8: case ILCode.Conv_Ovf_I8_Un: return HandleConversion(64, true, expr.Arguments[0], expectedType, typeSystem.Int64); case ILCode.Conv_U1: case ILCode.Conv_Ovf_U1: case ILCode.Conv_Ovf_U1_Un: return HandleConversion(8, false, expr.Arguments[0], expectedType, typeSystem.Byte); case ILCode.Conv_U2: case ILCode.Conv_Ovf_U2: case ILCode.Conv_Ovf_U2_Un: return HandleConversion(16, false, expr.Arguments[0], expectedType, typeSystem.UInt16); case ILCode.Conv_U4: case ILCode.Conv_Ovf_U4: case ILCode.Conv_Ovf_U4_Un: return HandleConversion(32, false, expr.Arguments[0], expectedType, typeSystem.UInt32); case ILCode.Conv_U8: case ILCode.Conv_Ovf_U8: case ILCode.Conv_Ovf_U8_Un: return HandleConversion(64, false, expr.Arguments[0], expectedType, typeSystem.UInt64); case ILCode.Conv_I: case ILCode.Conv_Ovf_I: case ILCode.Conv_Ovf_I_Un: return HandleConversion(NativeInt, true, expr.Arguments[0], expectedType, typeSystem.IntPtr); case ILCode.Conv_U: case ILCode.Conv_Ovf_U: case ILCode.Conv_Ovf_U_Un: return HandleConversion(NativeInt, false, expr.Arguments[0], expectedType, typeSystem.UIntPtr); case ILCode.Conv_R4: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Single); } return typeSystem.Single; case ILCode.Conv_R8: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Double); } return typeSystem.Double; case ILCode.Conv_R_Un: return (expectedType != null && expectedType.MetadataType == MetadataType.Single) ? typeSystem.Single : typeSystem.Double; case ILCode.Castclass: case ILCode.Unbox_Any: return (TypeReference)expr.Operand; case ILCode.Unbox: return new ByReferenceType((TypeReference)expr.Operand); case ILCode.Isinst: { // isinst performs the equivalent of a cast only for reference types; // value types still need to be unboxed after an isinst instruction TypeReference tr = (TypeReference)expr.Operand; return tr.IsValueType ? typeSystem.Object : tr; } case ILCode.Box: { var tr = (TypeReference)expr.Operand; if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), tr); return tr.IsValueType ? typeSystem.Object : tr; } #endregion #region Comparison instructions case ILCode.Ceq: case ILCode.Cne: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, null, null); return typeSystem.Boolean; case ILCode.Clt: case ILCode.Cgt: case ILCode.Cle: case ILCode.Cge: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, true, null); return typeSystem.Boolean; case ILCode.Clt_Un: case ILCode.Cgt_Un: case ILCode.Cle_Un: case ILCode.Cge_Un: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, false, null); return typeSystem.Boolean; #endregion #region Branch instructions case ILCode.Brtrue: if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); return null; case ILCode.Br: case ILCode.Leave: case ILCode.Endfinally: case ILCode.Switch: case ILCode.Throw: case ILCode.Rethrow: case ILCode.LoopOrSwitchBreak: case ILCode.LoopContinue: case ILCode.YieldBreak: return null; case ILCode.Ret: if (forceInferChildren && expr.Arguments.Count == 1) { TypeReference returnType = context.CurrentMethod.ReturnType; if (context.CurrentMethodIsAsync && returnType != null && returnType.Namespace == "System.Threading.Tasks") { if (returnType.Name == "Task") { returnType = typeSystem.Void; } else if (returnType.Name == "Task`1" && returnType.IsGenericInstance) { returnType = ((GenericInstanceType)returnType).GenericArguments[0]; } } InferTypeForExpression(expr.Arguments[0], returnType); } return null; case ILCode.YieldReturn: if (forceInferChildren) { GenericInstanceType genericType = context.CurrentMethod.ReturnType as GenericInstanceType; if (genericType != null) { // IEnumerable<T> or IEnumerator<T> InferTypeForExpression(expr.Arguments[0], genericType.GenericArguments[0]); } else { // non-generic IEnumerable or IEnumerator InferTypeForExpression(expr.Arguments[0], typeSystem.Object); } } return null; case ILCode.Await: { TypeReference taskType = InferTypeForExpression(expr.Arguments[0], null); if (taskType.Name == "Task`1" && taskType.IsGenericInstance && taskType.Namespace == "System.Threading.Tasks") { return ((GenericInstanceType)taskType).GenericArguments[0]; } return null; } #endregion case ILCode.Pop: return null; case ILCode.Wrap: case ILCode.Dup: { var arg = expr.Arguments.Single(); return arg.ExpectedType = InferTypeForExpression(arg, expectedType); } default: Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName()); return null; } }
void FindNestedAssignments(ILExpression expr, ExpressionToInfer parent) { foreach (ILExpression arg in expr.Arguments) { if (arg.Code == ILCode.Stloc) { ExpressionToInfer expressionToInfer = new ExpressionToInfer(); expressionToInfer.Expression = arg; allExpressions.Add(expressionToInfer); FindNestedAssignments(arg, expressionToInfer); ILVariable v = (ILVariable)arg.Operand; if (v.Type == null) { assignmentExpressions[v].Add(expressionToInfer); // the instruction that consumes the stloc result is handled as if it was reading the variable parent.Dependencies.Add(v); } } else { ILVariable v; if (arg.Match(ILCode.Ldloc, out v) && v.Type == null) { parent.Dependencies.Add(v); } FindNestedAssignments(arg, parent); } } }
public static bool MatchSingleAndBr <T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel) { if (bb.Body.Count == 3 && bb.Body[0] is ILLabel && bb.Body[1].Match(code, out operand, out arg) && bb.Body[2].Match(ILCode.Br, out brLabel)) { return(true); } operand = default(T); arg = null; brLabel = null; return(false); }
/// <summary> /// Infers the C# type of <paramref name="expr"/>. /// </summary> /// <param name="expr">The expression</param> /// <param name="expectedType">The expected type of the expression</param> /// <param name="forceInferChildren">Whether direct children should be inferred even if its not necessary. (does not apply to nested children!)</param> /// <returns>The inferred type</returns> TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false) { if (expectedType != null && !IsSameType(expr.ExpectedType, expectedType)) { expr.ExpectedType = expectedType; if (expr.Code != ILCode.Stloc) // stloc is special case and never gets re-evaluated forceInferChildren = true; } if (forceInferChildren || expr.InferredType == null) expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren); return expr.InferredType; }
public static bool MatchSingle <T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg) { if (bb.Body.Count == 2 && bb.Body[0] is ILLabel && bb.Body[1].Match(code, out operand, out arg)) { return(true); } operand = default(T); arg = null; return(false); }
TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType) { if (targetBitSize >= NativeInt && expectedType is PointerType) { InferTypeForExpression(arg, expectedType); return expectedType; } TypeReference argType = InferTypeForExpression(arg, null); if (targetBitSize >= NativeInt && argType is ByReferenceType) { // conv instructions on managed references mean that the GC should stop tracking them, so they become pointers: PointerType ptrType = new PointerType(((ByReferenceType)argType).ElementType); InferTypeForExpression(arg, ptrType); return ptrType; } else if (targetBitSize >= NativeInt && argType is PointerType) { return argType; } TypeReference resultType = (GetInformationAmount(expectedType) == targetBitSize && IsSigned(expectedType) == targetSigned) ? expectedType : targetType; arg.ExpectedType = resultType; // store the expected type in the argument so that AstMethodBodyBuilder will insert a cast return resultType; }
bool MatchFixedInitializer(List <ILNode> body, int i, out ILVariable pinnedVar, out ILExpression initValue, out int nextPos) { if (body[i].Match(ILCode.Stloc, out pinnedVar, out initValue) && pinnedVar.IsPinned && !IsNullOrZero(initValue)) { initValue = (ILExpression)body[i]; nextPos = i + 1; HandleStringFixing(pinnedVar, body, ref nextPos, ref initValue); return(true); } ILCondition ifStmt = body[i] as ILCondition; ILExpression arrayLoadingExpr; if (ifStmt != null && MatchFixedArrayInitializerCondition(ifStmt.Condition, out arrayLoadingExpr)) { ILVariable arrayVariable = (ILVariable)arrayLoadingExpr.Operand; ILExpression trueValue; if (ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out pinnedVar, out trueValue) && pinnedVar.IsPinned && IsNullOrZero(trueValue)) { if (ifStmt.FalseBlock != null && ifStmt.FalseBlock.Body.Count == 1 && ifStmt.FalseBlock.Body[0] is ILFixedStatement) { ILFixedStatement fixedStmt = (ILFixedStatement)ifStmt.FalseBlock.Body[0]; ILVariable stlocVar; ILExpression falseValue; if (fixedStmt.Initializers.Count == 1 && fixedStmt.BodyBlock.Body.Count == 0 && fixedStmt.Initializers[0].Match(ILCode.Stloc, out stlocVar, out falseValue) && stlocVar == pinnedVar) { ILVariable loadedVariable; if (falseValue.Code == ILCode.Ldelema && falseValue.Arguments[0].Match(ILCode.Ldloc, out loadedVariable) && loadedVariable == arrayVariable && IsNullOrZero(falseValue.Arguments[1])) { // OK, we detected the pattern for fixing an array. // Now check whether the loading expression was a store ot a temp. var // that can be eliminated. if (arrayLoadingExpr.Code == ILCode.Stloc) { ILInlining inlining = new ILInlining(method); if (inlining.numLdloc.GetOrDefault(arrayVariable) == 2 && inlining.numStloc.GetOrDefault(arrayVariable) == 1 && inlining.numLdloca.GetOrDefault(arrayVariable) == 0) { arrayLoadingExpr = arrayLoadingExpr.Arguments[0]; } } initValue = new ILExpression(ILCode.Stloc, pinnedVar, arrayLoadingExpr); nextPos = i + 1; return(true); } } } } } initValue = null; nextPos = -1; return(false); }