ILFunction TransformDelegateConstruction( ILInstruction value, IMethod targetMethod, ILInstruction target, IType delegateType) { if (!IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod)) { return(null); } if (targetMethod.MetadataToken.IsNil) { return(null); } if (LocalFunctionDecompiler.IsLocalFunctionMethod(targetMethod, context)) { return(null); } if (!ValidateDelegateTarget(target)) { return(null); } var handle = (MethodDefinitionHandle)targetMethod.MetadataToken; if (activeMethods.Contains(handle)) { this.context.Function.Warnings.Add(" Found self-referencing delegate construction. Abort transformation to avoid stack overflow."); return(null); } var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken); if (!methodDefinition.HasBody()) { return(null); } var genericContext = GenericContextFromTypeArguments(targetMethod.Substitution); if (genericContext == null) { return(null); } var ilReader = context.CreateILReader(); var body = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress); var function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.Value, ILFunctionKind.Delegate, context.CancellationToken); function.DelegateType = delegateType; // Embed the lambda into the parent function's ILAst, so that "Show steps" can show // how the lambda body is being transformed. value.ReplaceWith(function); function.CheckInvariant(ILPhase.Normal); var contextPrefix = targetMethod.Name; foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter)) { v.Name = contextPrefix + v.Name; } var nestedContext = new ILTransformContext(context, function); function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is DelegateConstruction)).Concat(GetTransforms()), nestedContext); nestedContext.Step("DelegateConstruction (ReplaceDelegateTargetVisitor)", function); function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(VariableKindExtensions.IsThis))); // handle nested lambdas nestedContext.StepStartGroup("DelegateConstruction (nested lambdas)", function); ((IILTransform)this).Run(function, nestedContext); nestedContext.StepEndGroup(); function.AddILRange(target); function.AddILRange(value); if (value is Call call) { function.AddILRange(call.Arguments[1]); } return(function); }
ILFunction TransformDelegateConstruction(NewObj value, out ILInstruction target) { target = null; if (!IsDelegateConstruction(value)) { return(null); } var targetMethod = ((IInstructionWithMethodOperand)value.Arguments[1]).Method; if (!IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod)) { return(null); } if (LocalFunctionDecompiler.IsLocalFunctionMethod(targetMethod.ParentModule.PEFile, (MethodDefinitionHandle)targetMethod.MetadataToken)) { return(null); } target = value.Arguments[0]; if (targetMethod.MetadataToken.IsNil) { return(null); } var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken); if (!methodDefinition.HasBody()) { return(null); } var genericContext = GenericContextFromTypeArguments(targetMethod.Substitution); if (genericContext == null) { return(null); } var ilReader = context.CreateILReader(); var body = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress); var function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.Value, context.CancellationToken); function.DelegateType = value.Method.DeclaringType; function.CheckInvariant(ILPhase.Normal); // Embed the lambda into the parent function's ILAst, so that "Show steps" can show // how the lambda body is being transformed. value.ReplaceWith(function); var contextPrefix = targetMethod.Name; foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter)) { v.Name = contextPrefix + v.Name; } var nestedContext = new ILTransformContext(context, function); function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is DelegateConstruction)).Concat(GetTransforms()), nestedContext); nestedContext.Step("DelegateConstruction (ReplaceDelegateTargetVisitor)", function); function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter))); // handle nested lambdas nestedContext.StepStartGroup("DelegateConstruction (nested lambdas)", function); ((IILTransform) new DelegateConstruction()).Run(function, nestedContext); nestedContext.StepEndGroup(); function.AddILRange(target); function.AddILRange(value); function.AddILRange(value.Arguments[1]); return(function); }
void PerformAssignment(ILFunction function) { // remove unused variables before assigning names function.Variables.RemoveDead(); int numDisplayClassLocals = 0; foreach (var v in function.Variables) { switch (v.Kind) { case VariableKind.Parameter: // ignore break; case VariableKind.InitializerTarget: // keep generated names AddExistingName(reservedVariableNames, v.Name); break; case VariableKind.DisplayClassLocal: v.Name = "CS$<>8__locals" + (numDisplayClassLocals++); break; default: if (v.HasGeneratedName || !IsValidName(v.Name) || ConflictWithLocal(v)) { // don't use the name from the debug symbols if it looks like a generated name v.Name = null; } else { // use the name from the debug symbols // (but ensure we don't use the same name for two variables) v.Name = GetAlternativeName(v.Name); } break; } } foreach (var localFunction in function.LocalFunctions) { if (!LocalFunctionDecompiler.ParseLocalFunctionName(localFunction.Name, out _, out var newName) || !IsValidName(newName)) { newName = null; } localFunction.Name = newName; } // Now generate names: var mapping = new Dictionary <ILVariable, string>(ILVariableEqualityComparer.Instance); foreach (var inst in function.Descendants.OfType <IInstructionWithVariableOperand>()) { var v = inst.Variable; if (!mapping.TryGetValue(v, out string name)) { if (string.IsNullOrEmpty(v.Name)) { v.Name = GenerateNameForVariable(v); } mapping.Add(v, v.Name); } else { v.Name = name; } } foreach (var localFunction in function.LocalFunctions) { var newName = localFunction.Name; if (newName == null) { newName = GetAlternativeName("f"); } localFunction.Name = newName; } }
public void Run(ILFunction function, ILTransformContext context) { try { if (this.context != null) { throw new InvalidOperationException("Reentrancy in " + nameof(TransformDisplayClassUsage)); } this.context = context; var decompilationContext = new SimpleTypeResolveContext(context.Function.Method); // Traverse nested functions in post-order: // Inner functions are transformed before outer functions foreach (var f in function.Descendants.OfType <ILFunction>()) { foreach (var v in f.Variables.ToArray()) { if (HandleMonoStateMachine(function, v, decompilationContext, f)) { continue; } if (IsClosure(v, out ITypeDefinition closureType, out var inst)) { AddOrUpdateDisplayClass(f, v, closureType, inst, localFunctionClosureParameter: false); } if (context.Settings.LocalFunctions && f.Kind == ILFunctionKind.LocalFunction && v.Kind == VariableKind.Parameter && v.Index > -1 && f.Method.Parameters[v.Index.Value] is IParameter p && LocalFunctionDecompiler.IsClosureParameter(p, decompilationContext)) { AddOrUpdateDisplayClass(f, v, ((ByReferenceType)p.Type).ElementType.GetDefinition(), f.Body, localFunctionClosureParameter: true); } } } VisitILFunction(function); if (instructionsToRemove.Count > 0) { context.Step($"Remove instructions", function); foreach (var store in instructionsToRemove) { if (store.Parent is Block containingBlock) { containingBlock.Instructions.Remove(store); } } } RemoveDeadVariableInit.ResetHasInitialValueFlag(function, context); } finally { instructionsToRemove.Clear(); displayClasses.Clear(); this.context = null; } }
void PerformAssignment(ILFunction function) { // remove unused variables before assigning names function.Variables.RemoveDead(); int numDisplayClassLocals = 0; Dictionary <int, string> assignedLocalSignatureIndices = new Dictionary <int, string>(); foreach (var v in function.Variables.OrderBy(v => v.Name)) { switch (v.Kind) { case VariableKind.Parameter: // ignore break; case VariableKind.InitializerTarget: // keep generated names AddExistingName(reservedVariableNames, v.Name); break; case VariableKind.DisplayClassLocal: v.Name = "CS$<>8__locals" + (numDisplayClassLocals++); break; case VariableKind.Local when v.Index != null: if (assignedLocalSignatureIndices.TryGetValue(v.Index.Value, out string name)) { // make sure all local ILVariables that refer to the same slot in the locals signature // are assigned the same name. v.Name = name; } else { AssignName(); // Remember the newly assigned name: assignedLocalSignatureIndices.Add(v.Index.Value, v.Name); } break; default: AssignName(); break; } void AssignName() { if (v.HasGeneratedName || !IsValidName(v.Name) || ConflictWithLocal(v)) { // don't use the name from the debug symbols if it looks like a generated name v.Name = null; } else { // use the name from the debug symbols // (but ensure we don't use the same name for two variables) v.Name = GetAlternativeName(v.Name); } } } foreach (var localFunction in function.LocalFunctions) { if (!LocalFunctionDecompiler.ParseLocalFunctionName(localFunction.Name, out _, out var newName) || !IsValidName(newName)) { newName = null; } localFunction.Name = newName; localFunction.ReducedMethod.Name = newName; } // Now generate names: var mapping = new Dictionary <ILVariable, string>(ILVariableEqualityComparer.Instance); foreach (var inst in function.Descendants.OfType <IInstructionWithVariableOperand>()) { var v = inst.Variable; if (!mapping.TryGetValue(v, out string name)) { if (string.IsNullOrEmpty(v.Name)) { v.Name = GenerateNameForVariable(v); } mapping.Add(v, v.Name); } else { v.Name = name; } } foreach (var localFunction in function.LocalFunctions) { var newName = localFunction.Name; if (newName == null) { newName = GetAlternativeName("f"); } localFunction.Name = newName; localFunction.ReducedMethod.Name = newName; localFunctionMapping[(MethodDefinitionHandle)localFunction.ReducedMethod.MetadataToken] = newName; } foreach (var inst in function.Descendants) { LocalFunctionMethod localFunction; switch (inst) { case Call call: localFunction = call.Method as LocalFunctionMethod; break; case LdFtn ldftn: localFunction = ldftn.Method as LocalFunctionMethod; break; default: localFunction = null; break; } if (localFunction == null || !localFunctionMapping.TryGetValue((MethodDefinitionHandle)localFunction.MetadataToken, out var name)) { continue; } localFunction.Name = name; } }