public static Dictionary <ILInstruction, string> DebugLocalLiveness(ILFunction method, IEnumerable <ILVariable> variables) //DecompilerContext context, { var insts = LivenessHelper.GetInstructions(method); var live_in = insts.Select(x => "").ToList(); var live_out = insts.Select(x => "").ToList(); Liveness.ControlFlow(insts, out int[][] succ, out int[][] pres); foreach (var v in variables) { var live = Liveness.CalcLiveness(insts, v, succ, pres); for (int idx = 0; idx < live.Length; idx++) { if (live[idx].LiveIn) { live_in[idx] += v.Name + ","; } if (live[idx].LiveOut) { live_out[idx] += v.Name + ","; } } } var zipped = live_in.Zip(live_out, (x, y) => "[" + x + "|" + y + "]").ToArray(); var d = new Dictionary <ILInstruction, string>(); for (int i = 0; i < insts.Count; i++) { d.Add(insts[i], zipped[i]); } return(d); }
public void Run(ILFunction function, ILTransformContext context) { var insts = LivenessHelper.GetInstructions(function); if (insts.Count == 1) { // empty body, skip method return; } // skip marked methods //if (function.CecilMethod.CustomAttributes.Any(x => x.AttributeType.Name == "ManualRefCounting")) if (function.Method.GetAttributes().Any(x => x.AttributeType.Name == "ManualRefCounting")) { return; } IEnumerable <ILVariable> vars = function.Variables; var usedVars = new List <ILVariable>(); foreach (var v in vars) { //var aliasSource = TypeInference.GetAliasSource(v); //// don't ref count parameters like this. Todo check for out and ref parameters (does O work already?) //if (aliasSource?.Kind == VariableKind.Parameter && aliasSource.StackType == StackType.O) // continue; // no typeof intermediate variables if (v.StoreInstructions.Count == 1 && (v.StoreInstructions.First() as StLoc)?.Value is LdTypeToken) { continue; } // skip variables that only contain NULL, etc if (TypeInference.GetVariableType(v) == null) { continue; } // only reference types or valuetypes that require ref counting if (TypeInference.GetVariableType(v).Kind == TypeKind.Pointer) { continue; var pType = TypeInference.GetVariableType(v) as ICSharpCode.Decompiler.TypeSystem.PointerType; var elemType = pType.ElementType; //if (!elemType.IsReferenceType.Value) // continue; if (!elemType.IsReferenceType.Value && !elemType.GetMethods().Any(x => x.Name.EndsWith("_AddRef"))) { continue; } } else { if (!TypeInference.GetVariableType(v).IsReferenceType.Value&& !TypeInference.GetVariableType(v).GetMethods().Any(x => x.Name.EndsWith("_AddRef"))) { continue; } } // references are not supported in C Debug.Assert(TypeInference.GetVariableType(v).Kind != TypeKind.ByReference); //todo: are the following two needed? //if (TypeInference.GetVariableType(v).Kind == TypeKind.Pointer) // continue; //if (TypeInference.GetVariableType(v).Kind == TypeKind.ByReference) // continue; usedVars.Add(v); } vars = usedVars.ToArray(); var liveDebug = DebugLiveness.DebugLocalLiveness(function, vars); AddRefCountingLocalLiveness(insts, vars); ILAstDebugPrinter.DebugIlAst(function, "after_ref", liveDebug); // Add casts to make compiler happy // Todo: I would prefer to access base field insead. No easy representation at this stage though. // Todo: move to own optimization foreach (var c in function.Body.Descendants.OfType <CallInstruction>()) { for (int idx = 0; idx < c.Method.Parameters.Count; idx++) { var p = c.Method.Parameters[idx]; var value = c.Arguments[idx]; var argType = TypeInference.GetInstType(value); var pType = p.Type; if (argType != null && argType != pType) { value.ReplaceWith(new CastClass(value.Clone(), pType)); } } } }