public static void RunStep1(DecompilerContext context, ILBlock method) { if (!context.Settings.AsyncAwait) return; // abort if async decompilation is disabled var yrd = new AsyncDecompiler(); yrd.context = context; if (!yrd.MatchTaskCreationPattern(method)) return; #if DEBUG if (Debugger.IsAttached) { yrd.Run(); } else { #endif try { yrd.Run(); } catch (SymbolicAnalysisFailedException) { return; } #if DEBUG } #endif context.CurrentMethodIsAsync = true; method.Body.Clear(); method.EntryGoto = null; method.Body.AddRange(yrd.newTopLevelBody); ILAstOptimizer.RemoveRedundantCode(method); }
HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition /// <summary> /// Creates the body for the method definition. /// </summary> /// <param name="methodDef">Method definition to decompile.</param> /// <param name="context">Decompilation context.</param> /// <param name="parameters">Parameter declarations of the method being decompiled. /// These are used to update the parameter names when the decompiler generates names for the parameters.</param> /// <param name="localVariables">Local variables storage that will be filled/updated with the local variables.</param> /// <returns>Block for the method body</returns> public static BlockStatement CreateMethodBody(MethodDefinition methodDef, DecompilerContext context, IEnumerable<ParameterDeclaration> parameters = null, ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables = null) { if (localVariables == null) localVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>(); MethodDefinition oldCurrentMethod = context.CurrentMethod; Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); context.CurrentMethod = methodDef; try { AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); builder.methodDef = methodDef; builder.context = context; builder.typeSystem = methodDef.Module.TypeSystem; if (Debugger.IsAttached) { return builder.CreateMethodBody(parameters, localVariables); } else { try { return builder.CreateMethodBody(parameters, localVariables); } catch (OperationCanceledException) { throw; } catch (Exception ex) { throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex); } } } finally { context.CurrentMethod = oldCurrentMethod; } }
public static void Run(DecompilerContext context, ILBlock method) { if (!context.Settings.YieldReturn) return; // abort if enumerator decompilation is disabled var yrd = new YieldReturnDecompiler(); yrd.context = context; if (!yrd.MatchEnumeratorCreationPattern(method)) return; yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType; #if DEBUG if (Debugger.IsAttached) { yrd.Run(); } else { #endif try { yrd.Run(); } catch (YieldAnalysisFailedException) { return; } #if DEBUG } #endif method.Body.Clear(); method.EntryGoto = null; method.Body.AddRange(yrd.newBody); }
public static void Run(DecompilerContext context, ILBlock method) { if (!context.Settings.YieldReturn) return; // abort if enumerator decompilation is disabled var yrd = new YieldReturnDecompiler(); yrd.context = context; if (!yrd.MatchEnumeratorCreationPattern(method)) return; yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType; #if DEBUG if (Debugger.IsAttached) { yrd.Run(); } else { #endif try { yrd.Run(); } catch (SymbolicAnalysisFailedException) { return; } #if DEBUG } #endif method.Body.Clear(); method.EntryGoto = null; method.Body.AddRange(yrd.newBody); // Repeat the inlining/copy propagation optimization because the conversion of field access // to local variables can open up additional inlining possibilities. ILInlining inlining = new ILInlining(method); inlining.InlineAllVariables(); inlining.CopyPropagation(); }
HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition /// <summary> /// Creates the body for the method definition. /// </summary> /// <param name="methodDef">Method definition to decompile.</param> /// <param name="context">Decompilation context.</param> /// <param name="parameters">Parameter declarations of the method being decompiled. /// These are used to update the parameter names when the decompiler generates names for the parameters.</param> /// <returns>Block for the method body</returns> public static BlockStatement CreateMethodBody(MethodDef methodDef, DecompilerContext context, IEnumerable<ParameterDeclaration> parameters, out MemberMapping mm) { MethodDef oldCurrentMethod = context.CurrentMethod; Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); context.CurrentMethod = methodDef; context.CurrentMethodIsAsync = false; try { AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); builder.methodDef = methodDef; builder.context = context; builder.corLib = methodDef.Module.CorLibTypes; if (Debugger.IsAttached) { return builder.CreateMethodBody(parameters, out mm); } else { try { return builder.CreateMethodBody(parameters, out mm); } catch (OperationCanceledException) { throw; } catch (Exception ex) { throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex); } } } finally { context.CurrentMethod = oldCurrentMethod; } }
public static void Run(DecompilerContext context, ILBlock method, List<ILNode> list_ILNode, Func<ILBlock, ILInlining> getILInlining) { if (!context.Settings.YieldReturn) return; // abort if enumerator decompilation is disabled var yrd = new YieldReturnDecompiler(); yrd.context = context; if (!yrd.MatchEnumeratorCreationPattern(method)) return; yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType; #if DEBUG && CRASH_IN_DEBUG_MODE if (Debugger.IsAttached) { yrd.Run(); } else { #endif try { yrd.Run(); } catch (SymbolicAnalysisFailedException) { return; } #if DEBUG && CRASH_IN_DEBUG_MODE } #endif method.Body.Clear(); method.EntryGoto = null; method.Body.AddRange(yrd.newBody);//TODO: Make sure that the removed ILRanges from Clear() above is saved in the new body // Repeat the inlining/copy propagation optimization because the conversion of field access // to local variables can open up additional inlining possibilities. var inlining = getILInlining(method); inlining.InlineAllVariables(); inlining.CopyPropagation(list_ILNode); }
HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition public static BlockStatement CreateMethodBody(MethodDefinition methodDef, DecompilerContext context) { MethodDefinition oldCurrentMethod = context.CurrentMethod; Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); context.CurrentMethod = methodDef; try { AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); builder.methodDef = methodDef; builder.context = context; builder.typeSystem = methodDef.Module.TypeSystem; if (Debugger.IsAttached) { return builder.CreateMethodBody(); } else { try { return builder.CreateMethodBody(); } catch (OperationCanceledException) { throw; } catch (Exception ex) { throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex); } } } finally { context.CurrentMethod = oldCurrentMethod; } }
public static void Run(DecompilerContext context, AstBlock method) { var ta = new TypeAnalysis(context); ta.CreateDependencyGraph(method); ta.IdentifySingleLoadVariables(); ta.RunInference(); }
public static void RunTransformationsUntil(AstNode node, Predicate<IAstTransform> abortCondition, DecompilerContext context) { if (node == null) return; for (int i = 0; i < 4; i++) { context.CancellationToken.ThrowIfCancellationRequested(); if (Options.ReduceAstJumps) { node.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); node.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); } if (Options.ReduceAstLoops) { node.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); } if (Options.ReduceAstOther) { node.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null); } } foreach (var transform in CreatePipeline(context)) { context.CancellationToken.ThrowIfCancellationRequested(); if (abortCondition != null && abortCondition(transform)) return; transform.Run(node); } }
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) { if (!method.HasBody) { return; } ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(); ilMethod.Body = astBuilder.Build(method, inlineVariables); if (abortBeforeStep != null) { DecompilerContext context = new DecompilerContext { CurrentType = method.DeclaringType, CurrentMethod = method }; new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value); } var allVariables = astBuilder.Variables .Concat(ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable).Where(v => v != null)).Distinct(); foreach (ILVariable v in allVariables) { output.WriteDefinition(v.Name, v); if (v.Type != null) { output.Write(" : "); v.Type.WriteTo(output, true, true); } output.WriteLine(); } output.WriteLine(); foreach (ILNode node in ilMethod.Body) { node.WriteTo(output); output.WriteLine(); } }
public DecompilerCache(DecompilerContext ctx) { this.pipelinePool = new ObjectPool<IAstTransformPoolObject[]>(() => TransformationPipeline.CreatePipeline(ctx), null); this.ilAstBuilderPool = new ObjectPool<ILAstBuilder>(() => new ILAstBuilder(), a => a.Reset()); this.ilAstOptimizerPool = new ObjectPool<ILAstOptimizer>(() => new ILAstOptimizer(), a => a.Reset()); this.gotoRemovalPool = new ObjectPool<GotoRemoval>(() => new GotoRemoval(ctx), a => a.Reset()); this.astMethodBodyBuilderPool = new ObjectPool<AstMethodBodyBuilder>(() => new AstMethodBodyBuilder(), a => a.Reset()); }
public static Expression TryConvert(DecompilerContext context, Expression expr) { Expression converted = new ExpressionTreeConverter(context).Convert(expr); if (converted != null) { converted.AddAnnotation(new ExpressionTreeLambdaAnnotation()); } return converted; }
public TextTokenWriter(ITextOutput output, DecompilerContext context) { if (output == null) throw new ArgumentNullException("output"); if (context == null) throw new ArgumentNullException("context"); this.output = output; this.context = context; }
static void RunOnCore() { Console.Write("Dry run..."); DateTime startDryRun = DateTime.UtcNow; { var _para = new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = new AssemblyResolver(), ReadSymbols = false }; var sys = AssemblyDefinition.ReadAssembly(typeof(TestingLogic).Assembly.Location, _para); var _dc = new DecompilerContext(sys.MainModule); var _astb = new AstBuilder(_dc); _astb.AddAssembly(sys); _astb.RunTransformations(); _astb.GenerateCode(new DummyOutput()); } TimeSpan dryRunTime = DateTime.UtcNow - startDryRun; Console.WriteLine(" O.K. " + dryRunTime.TotalSeconds.ToString("0.000") + " s."); Console.Write("Press Esc to skip large assembly reading"); if (Console.ReadKey().Key != ConsoleKey.Escape) { Console.Write("Reading assembly..."); DateTime startReading = DateTime.UtcNow; var msco = AssemblyDefinition.ReadAssembly(typeof(int).Assembly.Location); TimeSpan readAssemblyTime = DateTime.UtcNow - startReading; Console.WriteLine(" O.K. " + readAssemblyTime.TotalSeconds.ToString("0.000") + " s."); Console.Write("new DecompilerContext(), new AstBuilder()..."); DateTime startNewContext = DateTime.UtcNow; var dc = new DecompilerContext(msco.MainModule); var astb = new AstBuilder(dc); TimeSpan newContextTime = DateTime.UtcNow - startNewContext; Console.WriteLine(" O.K. " + newContextTime.TotalSeconds.ToString("0.000") + " s."); Console.Write("AstBuilder.AddAssembly()..."); DateTime startAddAssembly = DateTime.UtcNow; astb.AddAssembly(msco); TimeSpan decompilerInitTime = DateTime.UtcNow - startAddAssembly; Console.WriteLine(" O.K. " + decompilerInitTime.TotalSeconds.ToString("0.000") + " s."); Console.Write("AstBuilder.RunTransformations()..."); DateTime startTransform = DateTime.UtcNow; astb.RunTransformations(); TimeSpan transformTime = DateTime.UtcNow - startTransform; Console.WriteLine(" O.K. " + transformTime.TotalSeconds.ToString("0.000") + " s."); Console.Write("AstBuilder.GenerateCode()..."); DateTime startGeneration = DateTime.UtcNow; astb.GenerateCode(new DummyOutput()); TimeSpan generationTime = DateTime.UtcNow - startGeneration; Console.WriteLine(" O.K. " + generationTime.TotalSeconds.ToString("0.000") + " s."); Console.Write("Press any key to exit"); Console.ReadKey(); } }
public static IAstTransform[] CreatePipeline(DecompilerContext context) { return new IAstTransform[] { new PushNegation(), new DelegateConstruction(context), new PatternStatementTransform(), new ConvertConstructorCallIntoInitializer(), new ReplaceMethodCallsWithOperators(), }; }
public static void Run(DecompilerContext context, ILBlock method) { TypeAnalysis ta = new TypeAnalysis(); ta.context = context; ta.module = context.CurrentMethod.Module; ta.typeSystem = ta.module.TypeSystem; ta.method = method; ta.InferTypes(method); ta.InferRemainingStores(); }
public static void Run(DecompilerContext context, ILBlock method) { TypeAnalysis ta = new TypeAnalysis(); ta.context = context; ta.module = context.CurrentMethod.Module; ta.typeSystem = ta.module.TypeSystem; ta.method = method; ta.CreateDependencyGraph(method); ta.IdentifySingleLoadVariables(); ta.RunInference(); }
public static void RunTransformationsUntil(AstNode node, Predicate<IAstTransform> abortCondition, DecompilerContext context) { if (node == null) return; foreach (var transform in CreatePipeline(context)) { context.CancellationToken.ThrowIfCancellationRequested(); if (abortCondition != null && abortCondition(transform)) return; transform.Run(node); } }
public static void RunTransformationsUntil(AstNode node, Predicate<IAstTransform> abortCondition, DecompilerContext context) { if (node == null) return; foreach (var transform in CreatePipeline(context)) { context.VerifyProgress(); if (abortCondition != null && abortCondition(transform)) return; transform.Run(node); } }
public static void Run(DecompilerContext context, ILBlock method) { PeepholeTransforms transforms = new PeepholeTransforms(); transforms.context = context; transforms.method = method; PeepholeTransform[] blockTransforms = { ArrayInitializers.Transform(method), transforms.CachedDelegateInitialization }; Func<ILExpression, ILExpression>[] exprTransforms = { EliminateDups, HandleDecimalConstants }; // Traverse in post order so that nested blocks are transformed first. This is required so that // patterns on the parent block can assume that all nested blocks are already transformed. foreach (var node in TreeTraversal.PostOrder<ILNode>(method, c => c != null ? c.GetChildren() : null)) { ILBlock block = node as ILBlock; ILExpression expr; if (block != null) { // go through the instructions in reverse so that transforms can build up nested structures inside-out for (int i = block.Body.Count - 1; i >= 0; i--) { context.CancellationToken.ThrowIfCancellationRequested(); expr = block.Body[i] as ILExpression; if (expr != null) { // apply expr transforms to top-level expr in block foreach (var t in exprTransforms) expr = t(expr); block.Body[i] = expr; } // apply block transforms foreach (var t in blockTransforms) { t(block, ref i); Debug.Assert(i <= block.Body.Count && i >= 0); if (i == block.Body.Count) // special case: retry all transforms break; } } } expr = node as ILExpression; if (expr != null) { // apply expr transforms to all arguments for (int i = 0; i < expr.Arguments.Count; i++) { ILExpression arg = expr.Arguments[i]; foreach (var t in exprTransforms) arg = t(arg); expr.Arguments[i] = arg; } } } }
public static IAstTransform[] CreatePipeline(DecompilerContext context) { return new IAstTransform[] { new PushNegation(), new DelegateConstruction(context), new PatternStatementTransform(context), new ReplaceMethodCallsWithOperators(), new IntroduceUnsafeModifier(), new AddCheckedBlocks(), new DeclareVariables(context), // should run after most transforms that modify statements new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables new IntroduceUsingDeclarations(context) }; }
public SimpleControlFlow(DecompilerContext context, ILBlock method) { this.context = context; this.typeSystem = context.CurrentMethod.Module.TypeSystem; foreach(ILLabel target in method.GetSelfAndChildrenRecursive<ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) { labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1; } foreach(ILBasicBlock bb in method.GetSelfAndChildrenRecursive<ILBasicBlock>()) { foreach(ILLabel label in bb.GetChildren().OfType<ILLabel>()) { labelToBasicBlock[label] = bb; } } }
public static void AssignNamesToVariables(DecompilerContext context, IEnumerable<ILVariable> parameters, IEnumerable<ILVariable> variables, ILBlock methodBody) { NameVariables nv = new NameVariables(); nv.context = context; nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList(); nv.AddExistingNames(parameters.Select(p => p.Name)); nv.AddExistingNames(variables.Where(v => v.IsGenerated).Select(v => v.Name)); foreach (ILVariable p in parameters) { if (string.IsNullOrEmpty(p.Name)) p.Name = nv.GenerateNameForVariable(p, methodBody); } foreach (ILVariable varDef in variables) { if (!varDef.IsGenerated) { varDef.Name = nv.GenerateNameForVariable(varDef, methodBody); } } }
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) { if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { SplitToBasicBlocks(block); } OptimizeShortCircuits(method); if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { ControlFlowGraph graph; graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); graph.ComputeDominance(context.CancellationToken); graph.ComputeDominanceFrontier(); block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, false); } if (abortBeforeStep == ILAstOptimizationStep.FindConditions) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { ControlFlowGraph graph; graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); // TODO: Fix if (graph == null) continue; graph.ComputeDominance(context.CancellationToken); graph.ComputeDominanceFrontier(); block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint); } if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return; FlattenBasicBlocks(method); if (abortBeforeStep == ILAstOptimizationStep.SimpleGotoRemoval) return; SimpleGotoRemoval(method); if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return; RemoveDeadLabels(method); if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return; ArrayInitializers.Transform(method); if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return; TypeAnalysis.Run(context, method); }
/// <summary> /// Perform all dot42 related Ast conversions. /// </summary> public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler) { if (ast.IsOptimizedForTarget) return; #if DEBUG //Debugger.Launch(); if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase))) { //Debugger.Launch(); } #endif IntPtrConverter.Convert(ast, compiler); TypeOfConverter.Convert(ast, compiler); BranchOptimizer.Convert(ast); CompoundAssignmentConverter.Convert(ast); ByReferenceParamConverter.Convert(context, ast, compiler); CompareUnorderedConverter.Convert(ast); EnumConverter.Convert(ast, compiler); EnumOptimizer.Convert(ast, compiler); // Keep this order NullableConverter.Convert(ast, compiler); PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler); StructCallConverter.Convert(ast, compiler); // end InitializeStructVariablesConverter.Convert(ast); DelegateConverter.Convert(ast); LdcWideConverter.Convert(ast); LdLocWithConversionConverter.Convert(ast); ConvertAfterLoadConversionConverter.Convert(ast); ConvertBeforeStoreConversionConverter.Convert(ast); CleanupConverter.Convert(ast); GenericsConverter.Convert(ast); // Expand cast expressions CastConverter.Convert(ast, currentMethod, compiler); // Expand generic instance information GenericInstanceConverter.Convert(ast, currentMethod, compiler); }
public static IAstTransformPoolObject[] CreatePipeline(DecompilerContext context) { return new IAstTransformPoolObject[] { new PushNegation(), new DelegateConstruction(context), new PatternStatementTransform(context), new ReplaceMethodCallsWithOperators(context), new IntroduceUnsafeModifier(), new AddCheckedBlocks(), new DeclareVariables(context), // should run after most transforms that modify statements new ConvertConstructorCallIntoInitializer(context), // must run after DeclareVariables new DecimalConstantTransform(), new IntroduceUsingDeclarations(context), new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods new CombineQueryExpressions(context), new FlattenSwitchBlocks(), }; }
public static void RunTransformationsUntil(AstNode node, Predicate<IAstTransform> abortCondition, DecompilerContext context) { if (node == null) return; var pipeline = context.Cache.GetPipelinePool(); try { foreach (var transform in pipeline) { transform.Reset(context); context.CancellationToken.ThrowIfCancellationRequested(); if (abortCondition != null && abortCondition(transform)) return; transform.Run(node); } } finally { context.Cache.Return(pipeline); } }
HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition /// <summary> /// Creates the body for the method definition. /// </summary> /// <param name="methodDef">Method definition to decompile.</param> /// <param name="context">Decompilation context.</param> /// <param name="parameters">Parameter declarations of the method being decompiled. /// These are used to update the parameter names when the decompiler generates names for the parameters.</param> /// <param name="localVariables">Local variables storage that will be filled/updated with the local variables.</param> /// <returns>Block for the method body</returns> public static BlockStatement CreateMethodBody(MethodDefinition methodDef, DecompilerContext context, IEnumerable<ParameterDeclaration> parameters = null, /*Concurrent*/Dictionary<int, IEnumerable<ILVariable>> localVariables = null) { if (localVariables == null) localVariables = new /*Concurrent*/Dictionary<int, IEnumerable<ILVariable>>(); MethodDefinition oldCurrentMethod = context.CurrentMethod; Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); context.CurrentMethod = methodDef; try { AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); builder.methodDef = methodDef; builder.context = context; builder.typeSystem = methodDef.Module.TypeSystem; return builder.CreateMethodBody(parameters, localVariables); } finally { context.CurrentMethod = oldCurrentMethod; } }
public static void AssignNamesToVariables(DecompilerContext context, IEnumerable<ILVariable> parameters, IEnumerable<ILVariable> variables, ILBlock methodBody) { NameVariables nv = new NameVariables(); nv.context = context; nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList(); // First mark existing variable names as reserved. foreach (string name in context.ReservedVariableNames) nv.AddExistingName(name); foreach (var p in parameters) nv.AddExistingName(p.Name); foreach (var v in variables) { if (v.IsGenerated) { // don't introduce names for variables generated by ILSpy - keep "expr"/"arg" nv.AddExistingName(v.Name); } else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) { string varName = v.OriginalVariable.Name; if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || !IsValidName(varName)) { // 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 = nv.GetAlternativeName(varName); } } else { v.Name = null; } } // Now generate names: foreach (ILVariable p in parameters) { if (string.IsNullOrEmpty(p.Name)) p.Name = nv.GenerateNameForVariable(p, methodBody); } foreach (ILVariable varDef in variables) { if (string.IsNullOrEmpty(varDef.Name)) varDef.Name = nv.GenerateNameForVariable(varDef, methodBody); } }
public SimpleControlFlow(DecompilerContext context, ILBlock method) { this.context = context; this.typeSystem = context.CurrentMethod.Module.TypeSystem; var labelTargets = from e in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>() where e.IsBranch() from t in e.GetBranchTargets() select t; foreach(ILLabel target in labelTargets) { labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1; } var basicBlocks = method.EnumerateSelfAndChildrenRecursive().OfType<ILBasicBlock>(); foreach(ILBasicBlock bb in basicBlocks) { foreach(ILLabel label in bb.GetChildren().OfType<ILLabel>()) { labelToBasicBlock[label] = bb; } } }
public override void Decompile(MethodDef method, IDecompilerOutput output, DecompilationContext ctx) { WriteCommentBegin(output, true); output.Write("Method: ", BoxedTextColor.Comment); output.Write(IdentifierEscaper.Escape(method.FullName), method, DecompilerReferenceFlags.Definition, BoxedTextColor.Comment); WriteCommentEnd(output, true); output.WriteLine(); if (!method.HasBody) { return; } var bodyInfo = StartKeywordBlock(output, ".body", method); ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(CodeBracesRangeFlags.MethodBraces); DecompilerContext context = new DecompilerContext(settingsVersion, method.Module, MetadataTextColorProvider) { CurrentType = method.DeclaringType, CurrentMethod = method, CalculateILSpans = ctx.CalculateILSpans, }; ilMethod.Body = astBuilder.Build(method, inlineVariables, context); var stateMachineKind = StateMachineKind.None; MethodDef? inlinedMethod = null; AsyncMethodDebugInfo?asyncInfo = null; string? compilerName = null; if (!(abortBeforeStep is null)) { var optimizer = new ILAstOptimizer(); optimizer.Optimize(context, ilMethod, out stateMachineKind, out inlinedMethod, out asyncInfo, abortBeforeStep.Value); compilerName = optimizer.CompilerName; } if (context.CurrentMethodIsYieldReturn) { output.Write("yield", BoxedTextColor.Keyword); output.Write(" ", BoxedTextColor.Text); output.WriteLine("return", BoxedTextColor.Keyword); } if (context.CurrentMethodIsAsync) { output.Write("async", BoxedTextColor.Keyword); output.Write("/", BoxedTextColor.Punctuation); output.WriteLine("await", BoxedTextColor.Keyword); } var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable) .Where(v => !(v is null) && !v.IsParameter).Distinct(); foreach (var v in allVariables) { Debug2.Assert(!(v is null)); output.Write(IdentifierEscaper.Escape(v.Name), v.GetTextReferenceObject(), DecompilerReferenceFlags.Local | DecompilerReferenceFlags.Definition, v.IsParameter ? BoxedTextColor.Parameter : BoxedTextColor.Local); if (!(v.Type is null)) { output.Write(" ", BoxedTextColor.Text); output.Write(":", BoxedTextColor.Punctuation); output.Write(" ", BoxedTextColor.Text); if (v.IsPinned) { output.Write("pinned", BoxedTextColor.Keyword); output.Write(" ", BoxedTextColor.Text); } v.Type.WriteTo(output, ILNameSyntax.ShortTypeName); } if (v.GeneratedByDecompiler) { output.Write(" ", BoxedTextColor.Text); var start = output.NextPosition; output.Write("[", BoxedTextColor.Punctuation); output.Write("generated", BoxedTextColor.Keyword); var end = output.NextPosition; output.Write("]", BoxedTextColor.Punctuation); output.AddBracePair(new TextSpan(start, 1), new TextSpan(end, 1), CodeBracesRangeFlags.SquareBrackets); } output.WriteLine(); } var localVariables = new HashSet <ILVariable>(GetVariables(ilMethod)); var builder = new MethodDebugInfoBuilder(settingsVersion, stateMachineKind, inlinedMethod ?? method, !(inlinedMethod is null) ? method : null, CreateSourceLocals(localVariables), CreateSourceParameters(localVariables), asyncInfo); builder.CompilerName = compilerName; foreach (ILNode node in ilMethod.Body) { node.WriteTo(output, builder); if (!node.WritesNewLine) { output.WriteLine(); } } output.AddDebugInfo(builder.Create()); EndKeywordBlock(output, bodyInfo, CodeBracesRangeFlags.MethodBraces, addLineSeparator: true); }
public ConvertConstructorCallIntoInitializer(DecompilerContext context) { Reset(context); }
public static void AssignNamesToVariables(DecompilerContext context, IEnumerable <ILVariable> parameters, IEnumerable <ILVariable> variables, ILBlock methodBody) { NameVariables nv = new NameVariables(); nv.context = context; nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList(); // First mark existing variable names as reserved. foreach (string name in context.ReservedVariableNames) { nv.AddExistingName(name); } foreach (var p in parameters) { nv.AddExistingName(p.Name); } foreach (var v in variables) { if (v.IsGenerated) { // don't introduce names for variables generated by ILSpy - keep "expr"/"arg" nv.AddExistingName(v.Name); } else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) { string varName = v.OriginalVariable.Name; if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || !IsValidName(varName)) { // 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 = nv.GetAlternativeName(varName); } } else { string name = v.Name.Substring(1, Math.Max(0, v.Name.IndexOf('>') - 1)); if (IsValidName(name)) { v.Name = nv.GetAlternativeName(name); } else { v.Name = null; } } } // Now generate names: foreach (ILVariable p in parameters) { if (string.IsNullOrEmpty(p.Name)) { p.Name = nv.GenerateNameForVariable(p, methodBody); } } foreach (ILVariable varDef in variables) { if (string.IsNullOrEmpty(varDef.Name)) { varDef.Name = nv.GenerateNameForVariable(varDef, methodBody); } } }
void Run(Config config) { if (config.ShowHelp) { Console.WriteLine("Netjs compiler, Copyright 2014 Frank A. Krueger"); Console.WriteLine("netjs [options] assembly-file"); Console.WriteLine(" -help Lists all compiler options (short: -?)"); return; } if (string.IsNullOrEmpty(config.MainAssembly)) { throw new Exception("No assembly specified."); } var asmPath = Path.GetFullPath(config.MainAssembly); asmDir = Path.GetDirectoryName(asmPath); var outPath = Path.ChangeExtension(asmPath, ".ts"); Step("Reading IL"); var parameters = new ReaderParameters { AssemblyResolver = this, }; var asm = AssemblyDefinition.ReadAssembly(asmPath, parameters); mscorlib = AssemblyDefinition.ReadAssembly(typeof(String).Assembly.Location, parameters); system = AssemblyDefinition.ReadAssembly(typeof(INotifyPropertyChanged).Assembly.Location, parameters); systemCore = AssemblyDefinition.ReadAssembly(typeof(Enumerable).Assembly.Location, parameters); Step("Decompiling IL to C#"); var context = new DecompilerContext(asm.MainModule); context.Settings.ForEachStatement = false; context.Settings.ObjectOrCollectionInitializers = false; context.Settings.UsingStatement = false; context.Settings.AsyncAwait = false; context.Settings.AutomaticProperties = true; context.Settings.AutomaticEvents = true; context.Settings.QueryExpressions = false; context.Settings.AlwaysGenerateExceptionVariableForCatchBlocks = true; context.Settings.UsingDeclarations = false; context.Settings.FullyQualifyAmbiguousTypeNames = true; context.Settings.YieldReturn = false; var builder = new AstBuilder(context); builder.AddAssembly(asm); foreach (var a in referencedAssemblies.Values) { if (a != null) { builder.AddAssembly(a); } } builder.RunTransformations(); Step("Translating C# to TypeScript"); new CsToTs().Run(builder.SyntaxTree); Step("Writing"); using (var outputWriter = new StreamWriter(outPath)) { var output = new PlainTextOutput(outputWriter); builder.GenerateCode(output, (s, e) => new TsOutputVisitor(s, e)); } Step("Done"); }
public static void RunTransformationsUntil(AstNode node, Predicate <IAstTransform> abortCondition, DecompilerContext context) { if (node == null) { return; } foreach (var transform in CreatePipeline(context)) { context.CancellationToken.ThrowIfCancellationRequested(); if (abortCondition != null && abortCondition(transform)) { return; } transform.Run(node); } }
public void Initialize(DecompilerContext context) { this.context = context; this.labelToCfNode.Clear(); this.nextLabelIndex = 0; }
public IntroduceExtensionMethods(DecompilerContext context) { this.context = context; }
private ExpressionTreeConverter(DecompilerContext context, StringBuilder sb) { this.context = context; this.stringBuilder = sb; }
public DelegateConstruction(DecompilerContext context) : base(context) { }
bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef) { if (!context.Settings.AnonymousMethods) { return(false); // anonymous method decompilation is disabled } if (target != null && !(target is IdentifierExpression || target is ThisReferenceExpression || target is NullReferenceExpression)) { return(false); // don't copy arbitrary expressions, deal with identifiers only } // Anonymous methods are defined in the same assembly MethodDefinition method = methodRef.ResolveWithinSameModule(); if (!IsAnonymousMethod(context, method)) { return(false); } // Create AnonymousMethodExpression and prepare parameters AnonymousMethodExpression ame = new AnonymousMethodExpression(); ame.CopyAnnotationsFrom(objectCreateExpression); // copy ILRanges etc. ame.RemoveAnnotations <MethodReference>(); // remove reference to delegate ctor ame.AddAnnotation(method); // add reference to anonymous method ame.Parameters.AddRange(AstBuilder.MakeParameters(method, isLambda: true)); ame.HasParameterList = true; // rename variables so that they don't conflict with the parameters: foreach (ParameterDeclaration pd in ame.Parameters) { EnsureVariableNameIsAvailable(objectCreateExpression, pd.Name); } // Decompile the anonymous method: DecompilerContext subContext = context.Clone(); subContext.CurrentMethod = method; subContext.CurrentMethodIsAsync = false; subContext.ReservedVariableNames.AddRange(currentlyUsedVariableNames); BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext, ame.Parameters); TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext); body.AcceptVisitor(this, null); bool isLambda = false; if (ame.Parameters.All(p => p.ParameterModifier == ParameterModifier.None)) { isLambda = (body.Statements.Count == 1 && body.Statements.Single() is ReturnStatement); } // Remove the parameter list from an AnonymousMethodExpression if the original method had no names, // and the parameters are not used in the method body if (!isLambda && method.Parameters.All(p => string.IsNullOrEmpty(p.Name))) { var parameterReferencingIdentifiers = from ident in body.Descendants.OfType <IdentifierExpression>() let v = ident.Annotation <ILVariable>() where v != null && v.IsParameter && method.Parameters.Contains(v.OriginalParameter) select ident; if (!parameterReferencingIdentifiers.Any()) { ame.Parameters.Clear(); ame.HasParameterList = false; } } // Replace all occurrences of 'this' in the method body with the delegate's target: foreach (AstNode node in body.Descendants) { if (node is ThisReferenceExpression) { node.ReplaceWith(target.Clone()); } } Expression replacement; if (isLambda) { LambdaExpression lambda = new LambdaExpression(); lambda.CopyAnnotationsFrom(ame); ame.Parameters.MoveTo(lambda.Parameters); Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression; returnExpr.Remove(); lambda.Body = returnExpr; replacement = lambda; } else { ame.Body = body; replacement = ame; } var expectedType = objectCreateExpression.Annotation <TypeInformation>().ExpectedType.Resolve(); if (expectedType != null && !expectedType.IsDelegate()) { var simplifiedDelegateCreation = (ObjectCreateExpression)objectCreateExpression.Clone(); simplifiedDelegateCreation.Arguments.Clear(); simplifiedDelegateCreation.Arguments.Add(replacement); replacement = simplifiedDelegateCreation; } objectCreateExpression.ReplaceWith(replacement); return(true); }
public override void Decompile(MethodDef method, ITextOutput output, DecompilationContext ctx) { WriteCommentBegin(output, true); output.Write("Method: ", TextTokenKind.Comment); output.WriteDefinition(IdentifierEscaper.Escape(method.FullName), method, TextTokenKind.Comment, false); WriteCommentEnd(output, true); output.WriteLine(); if (!method.HasBody) { return; } StartKeywordBlock(output, ".body", method); ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(); DecompilerContext context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method }; ilMethod.Body = astBuilder.Build(method, inlineVariables, context); if (abortBeforeStep != null) { new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value); } if (context.CurrentMethodIsAsync) { output.Write("async", TextTokenKind.Keyword); output.Write("/", TextTokenKind.Operator); output.WriteLine("await", TextTokenKind.Keyword); } var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable) .Where(v => v != null && !v.IsParameter).Distinct(); foreach (ILVariable v in allVariables) { output.WriteDefinition(IdentifierEscaper.Escape(v.Name), v, v.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local); if (v.Type != null) { output.WriteSpace(); output.Write(":", TextTokenKind.Operator); output.WriteSpace(); if (v.IsPinned) { output.Write("pinned", TextTokenKind.Keyword); output.WriteSpace(); } v.Type.WriteTo(output, ILNameSyntax.ShortTypeName); } if (v.GeneratedByDecompiler) { output.WriteSpace(); output.Write("[", TextTokenKind.Operator); output.Write("generated", TextTokenKind.Keyword); output.Write("]", TextTokenKind.Operator); } output.WriteLine(); } var memberMapping = new MemberMapping(method); foreach (ILNode node in ilMethod.Body) { node.WriteTo(output, memberMapping); if (!node.WritesNewLine) { output.WriteLine(); } } output.AddDebugSymbols(memberMapping); EndKeywordBlock(output); }
Dictionary <int, Action <XamlContext, XElement> > ExtractConnectionId(XamlContext ctx, MethodDef method) { var context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method, CancellationToken = ctx.CancellationToken }; var body = new ILBlock(new ILAstBuilder().Build(method, true, context)); new ILAstOptimizer().Optimize(context, body); var sw = body.GetSelfAndChildrenRecursive <ILSwitch>().FirstOrDefault(); if (sw == null) { return(null); } var connIds = new Dictionary <int, Action <XamlContext, XElement> >(); foreach (var cas in sw.CaseBlocks) { if (cas.Values == null) { continue; } Action <XamlContext, XElement> cb = null; foreach (var node in cas.Body) { var expr = node as ILExpression; if (expr == null) { continue; } switch (expr.Code) { case ILCode.Stfld: cb += new FieldAssignment { FieldName = ((IField)expr.Operand).Name }.Callback; break; case ILCode.Call: case ILCode.Callvirt: var operand = (IMethod)expr.Operand; if (operand.Name == "AddHandler" && operand.DeclaringType.FullName == "System.Windows.UIElement") { // Attached event var re = expr.Arguments[1]; var ctor = expr.Arguments[2]; var reField = re.Operand as IField; if (re.Code != ILCode.Ldsfld || ctor.Code != ILCode.Newobj || ctor.Arguments.Count != 2 || ctor.Arguments[1].Code != ILCode.Ldftn) { cb += new Error { Msg = string.Format(dnSpy_BamlDecompiler_Resources.Error_AttachedEvent, reField.Name) }.Callback; break; } var handler = (IMethod)ctor.Arguments[1].Operand; string evName = reField.Name; if (evName.EndsWith("Event")) { evName = evName.Substring(0, evName.Length - 5); } cb += new EventAttachment { AttachedType = reField.DeclaringType.ResolveTypeDefThrow(), EventName = evName, MethodName = handler.Name }.Callback; } else { // CLR event var add = operand.ResolveMethodDefThrow(); var ev = add.DeclaringType.Events.FirstOrDefault(e => e.AddMethod == add); var ctor = expr.Arguments[1]; if (ev == null || ctor.Code != ILCode.Newobj || ctor.Arguments.Count != 2 || ctor.Arguments[1].Code != ILCode.Ldftn) { cb += new Error { Msg = string.Format(dnSpy_BamlDecompiler_Resources.Error_AttachedEvent, add.Name) }.Callback; break; } var handler = (IMethod)ctor.Arguments[1].Operand; cb += new EventAttachment { EventName = ev.Name, MethodName = handler.Name }.Callback; } break; } } if (cb != null) { foreach (var id in cas.Values) { connIds[id] = cb; } } } return(connIds.Count == 0 ? null : connIds); }
public CombineQueryExpressions(DecompilerContext context) { this.context = context; }
private static bool ProcessStatement(Statement general, Dictionary <int, HashSet <int > > mapExtPost) { if (general.type == Statement.Type_Root) { Statement stat = general.GetFirst(); if (stat.type != Statement.Type_General) { return(true); } else { bool complete = ProcessStatement(stat, mapExtPost); if (complete) { // replace general purpose statement with simple one general.ReplaceStatement(stat, stat.GetFirst()); } return(complete); } } bool mapRefreshed = (mapExtPost.Count == 0); for (int mapstage = 0; mapstage < 2; mapstage++) { for (int reducibility = 0; reducibility < 5; reducibility++) { // FIXME: implement proper node splitting. For now up to 5 nodes in sequence are splitted. if (reducibility > 0) { // try { // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot")); // } catch(Exception ex) {ex.printStackTrace();} // take care of irreducible control flow graphs if (IrreducibleCFGDeobfuscator.IsStatementIrreducible(general)) { if (!IrreducibleCFGDeobfuscator.SplitIrreducibleNode(general)) { DecompilerContext.GetLogger().WriteMessage("Irreducible statement cannot be decomposed!" , IFernflowerLogger.Severity.Error); break; } } else { if (mapstage == 2 || mapRefreshed) { // last chance lost DecompilerContext.GetLogger().WriteMessage("Statement cannot be decomposed although reducible!" , IFernflowerLogger.Severity.Error); } break; } // try { // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot")); // } catch(Exception ex) {ex.printStackTrace();} mapExtPost = new Dictionary <int, HashSet <int> >(); mapRefreshed = true; } for (int i = 0; i < 2; i++) { bool forceall = i != 0; while (true) { if (FindSimpleStatements(general, mapExtPost)) { reducibility = 0; } if (general.type == Statement.Type_Placeholder) { return(true); } Statement stat = FindGeneralStatement(general, forceall, mapExtPost); if (stat != null) { bool complete = ProcessStatement(stat, general.GetFirst() == stat ? mapExtPost : new Dictionary <int, HashSet <int> >()); if (complete) { // replace general purpose statement with simple one general.ReplaceStatement(stat, stat.GetFirst()); } else { return(false); } mapExtPost = new Dictionary <int, HashSet <int> >(); mapRefreshed = true; reducibility = 0; } else { break; } } } } // try { // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot")); // } catch (Exception ex) { // ex.printStackTrace(); // } if (mapRefreshed) { break; } else { mapExtPost = new Dictionary <int, HashSet <int> >(); } } return(false); }
public LoopsAndConditions(DecompilerContext context) { Initialize(context); }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(DecompilerContext context, AstBlock ast, AssemblyCompiler compiler) { // Convert stobj/stind_ref foreach (var node in ast.GetExpressions(x => (x.Arguments.Count == 2) && ((x.Code == AstCode.Stobj) || (x.Code == AstCode.Stind_Ref)))) { var addrNode = node.Arguments[0]; var valueNode = node.Arguments[1]; AstVariable variable; if ((addrNode.GetResultType().IsByReference) && addrNode.Match(AstCode.Ldloc, out variable)) { if (variable.IsThis && valueNode.Match(AstCode.DefaultValue)) { // Struct init : this() node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Nop, null)); } else if (!variable.IsThis) { // Convert byref type to array type var addrType = (XByReferenceType)addrNode.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); addrNode.ExpectedType = arrayType; addrNode.InferredType = arrayType; // Convert to stelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetStElemCode(); } else { // Convert to stloc } } } // Convert ldobj var resetTypes = false; var processed = new HashSet <AstExpression>(); foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; if ((node.Arguments.Count == 1) && ((node.Code == AstCode.Ldobj) || (node.Code == AstCode.Ldind_Ref))) { var parent = pair.Parent; var useAsValue = true; var isCallArgument = (parent != null) && (parent.Code.IsCall()); var isBoxArgument = (parent != null) && (parent.Match(AstCode.Box)); if (isCallArgument && (node.Code == AstCode.Ldobj)) { if (IsArgByRefOrOut(node, parent)) { useAsValue = false; } } if (isBoxArgument) { var boxType = (XTypeReference)parent.Operand; if (!boxType.IsGenericParameter) { useAsValue = false; } } var ldlocNode = node.Arguments[0]; processed.Add(ldlocNode); var addrNodeType = ldlocNode.GetResultType(); if (ldlocNode.MatchThis()) { useAsValue = false; } if (useAsValue) { if ((addrNodeType.IsByReference) && (ldlocNode.Code == AstCode.Ldloc)) { // Convert byref type to array type var addrType = (XByReferenceType)ldlocNode.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); ldlocNode.ExpectedType = arrayType; ldlocNode.InferredType = arrayType; // Convert to ldelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetLdElemCode(); node.SetType(arrayType.ElementType); resetTypes = true; } } else if (isCallArgument && (ldlocNode.Code == AstCode.Ldloc)) { var typeRef = (XTypeReference)node.Operand; XTypeDefinition typeDef; if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsValueType && !typeDef.IsPrimitive) { // Replace by ldloc node.Code = AstCode.Ldloc; node.Operand = ldlocNode.Operand; node.Arguments.Clear(); } } } else if ((node.Code == AstCode.Ldloc) && ((AstVariable)node.Operand).IsParameter && (node.GetResultType().IsByReference)) { var parent = pair.Parent; if ((parent != null) && (parent.Code == AstCode.Ldobj)) { continue; } var useAsValue = true; var isCallArgument = (parent != null) && (parent.Code.IsCall()); var isBoxArgument = (parent != null) && (parent.Match(AstCode.Box)); if (isCallArgument) { if (IsArgByRefOrOut(node, parent)) { useAsValue = false; } } if (isBoxArgument) { useAsValue = false; } if (node.MatchThis()) { useAsValue = false; } if (useAsValue) { // Convert byref type to array type var addrType = (XByReferenceType)node.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); var clone = new AstExpression(node).SetType(arrayType); // Convert to ldelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.SetArguments(clone, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetLdElemCode(); node.SetType(arrayType.ElementType); resetTypes = true; } } } if (resetTypes) { TypeAnalysis.Run(context, ast); } }
public bool Compile() { LogLine(1, "Compiling Xaml"); LogLine(1, "\nAssembly: {0}", Assembly); if (!string.IsNullOrEmpty(DependencyPaths)) { LogLine(1, "DependencyPaths: \t{0}", DependencyPaths); } if (!string.IsNullOrEmpty(ReferencePath)) { LogLine(1, "ReferencePath: \t{0}", ReferencePath.Replace("//", "/")); } LogLine(3, "DebugSymbols:\"{0}\"", DebugSymbols); var skipassembly = true; //change this to false to enable XamlC by default bool success = true; if (!File.Exists(Assembly)) { LogLine(1, "Assembly file not found. Skipping XamlC."); return(true); } var resolver = new XamlCAssemblyResolver(); if (!string.IsNullOrEmpty(DependencyPaths)) { foreach (var dep in DependencyPaths.Split(';')) { LogLine(3, "Adding searchpath {0}", dep); resolver.AddSearchDirectory(dep); } } if (!string.IsNullOrEmpty(ReferencePath)) { var paths = ReferencePath.Replace("//", "/").Split(';'); foreach (var p in paths) { var searchpath = Path.GetDirectoryName(p); LogLine(3, "Adding searchpath {0}", searchpath); resolver.AddSearchDirectory(searchpath); // LogLine (3, "Referencing {0}", p); // resolver.AddAssembly (p); } } var assemblyDefinition = AssemblyDefinition.ReadAssembly(Path.GetFullPath(Assembly), new ReaderParameters { AssemblyResolver = resolver, ReadSymbols = DebugSymbols }); CustomAttribute xamlcAttr; if (assemblyDefinition.HasCustomAttributes && (xamlcAttr = assemblyDefinition.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) { skipassembly = true; } if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) { skipassembly = false; } } foreach (var module in assemblyDefinition.Modules) { var skipmodule = skipassembly; if (module.HasCustomAttributes && (xamlcAttr = module.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) { skipmodule = true; } if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) { skipmodule = false; } } LogLine(2, " Module: {0}", module.Name); var resourcesToPrune = new List <EmbeddedResource>(); foreach (var resource in module.Resources.OfType <EmbeddedResource>()) { LogString(2, " Resource: {0}... ", resource.Name); string classname; if (!resource.IsXaml(out classname)) { LogLine(2, "skipped."); continue; } TypeDefinition typeDef = module.GetType(classname); if (typeDef == null) { LogLine(2, "no type found... skipped."); continue; } var skiptype = skipmodule; if (typeDef.HasCustomAttributes && (xamlcAttr = typeDef.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) { skiptype = true; } if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) { skiptype = false; } } if (skiptype) { LogLine(2, "Has XamlCompilationAttribute set to Skip and not Compile... skipped"); continue; } var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent"); if (initComp == null) { LogLine(2, "no InitializeComponent found... skipped."); continue; } LogLine(2, ""); var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime"); if (initCompRuntime != null) { LogLine(2, " __InitComponentRuntime already exists... not duplicating"); } else { LogString(2, " Duplicating {0}.InitializeComponent () into {0}.__InitComponentRuntime ... ", typeDef.Name); initCompRuntime = DuplicateMethodDef(typeDef, initComp, "__InitComponentRuntime"); LogLine(2, "done."); } LogString(2, " Parsing Xaml... "); var rootnode = ParseXaml(resource.GetResourceStream(), typeDef); if (rootnode == null) { LogLine(2, "failed."); continue; } LogLine(2, "done."); hasCompiledXamlResources = true; try { LogString(2, " Replacing {0}.InitializeComponent ()... ", typeDef.Name); var body = new MethodBody(initComp); var il = body.GetILProcessor(); il.Emit(OpCodes.Nop); // Generating branching code for the Previewer // IL_0007: call class [mscorlib]System.Func`2<class [mscorlib]System.Type,string> class [Xamarin.Forms.Xaml.Internals]Xamarin.Forms.Xaml.XamlLoader::get_XamlFileProvider() // IL_000c: brfalse IL_0031 // IL_0011: call class [mscorlib]System.Func`2<class [mscorlib]System.Type,string> class [Xamarin.Forms.Xaml.Internals]Xamarin.Forms.Xaml.XamlLoader::get_XamlFileProvider() // IL_0016: ldarg.0 // IL_0017: call instance class [mscorlib]System.Type object::GetType() // IL_001c: callvirt instance !1 class [mscorlib]System.Func`2<class [mscorlib]System.Type, string>::Invoke(!0) // IL_0021: brfalse IL_0031 // IL_0026: ldarg.0 // IL_0027: call instance void class Xamarin.Forms.Xaml.UnitTests.XamlLoaderGetXamlForTypeTests::__InitComponentRuntime() // IL_002c: ret // IL_0031: nop var nop = Instruction.Create(OpCodes.Nop); var getXamlFileProvider = body.Method.Module.Import(body.Method.Module.Import(typeof(Xamarin.Forms.Xaml.Internals.XamlLoader)) .Resolve() .Properties.FirstOrDefault(pd => pd.Name == "XamlFileProvider") .GetMethod); il.Emit(OpCodes.Call, getXamlFileProvider); il.Emit(OpCodes.Brfalse, nop); il.Emit(OpCodes.Call, getXamlFileProvider); il.Emit(OpCodes.Ldarg_0); var getType = body.Method.Module.Import(body.Method.Module.Import(typeof(object)) .Resolve() .Methods.FirstOrDefault(md => md.Name == "GetType")); il.Emit(OpCodes.Call, getType); var func = body.Method.Module.Import(body.Method.Module.Import(typeof(Func <Type, string>)) .Resolve() .Methods.FirstOrDefault(md => md.Name == "Invoke")); func = func.ResolveGenericParameters(body.Method.Module.Import(typeof(Func <Type, string>)), body.Method.Module); il.Emit(OpCodes.Callvirt, func); il.Emit(OpCodes.Brfalse, nop); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, initCompRuntime); il.Emit(OpCodes.Ret); il.Append(nop); var visitorContext = new ILContext(il, body); rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null); rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null); rootnode.Accept(new PruneIgnoredNodesVisitor(), null); rootnode.Accept(new CreateObjectVisitor(visitorContext), null); rootnode.Accept(new SetNamescopesAndRegisterNamesVisitor(visitorContext), null); rootnode.Accept(new SetFieldVisitor(visitorContext), null); rootnode.Accept(new SetResourcesVisitor(visitorContext), null); rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null); il.Emit(OpCodes.Ret); initComp.Body = body; } catch (XamlParseException xpe) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source); LogLine(4, xpe.StackTrace); success = false; continue; } catch (XmlException xe) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source); LogLine(4, xe.StackTrace); success = false; continue; } catch (Exception e) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source); LogLine(4, e.StackTrace); success = false; continue; } LogLine(2, "done."); if (OptimizeIL) { LogString(2, " Optimizing IL... "); initComp.Body.OptimizeMacros(); LogLine(2, "done"); } if (OutputGeneratedILAsCode) { var filepath = Path.Combine(Path.GetDirectoryName(Assembly), typeDef.FullName + ".decompiled.cs"); LogString(2, " Decompiling {0} into {1}...", typeDef.FullName, filepath); var decompilerContext = new DecompilerContext(module); using (var writer = new StreamWriter(filepath)) { var output = new PlainTextOutput(writer); var codeDomBuilder = new AstBuilder(decompilerContext); codeDomBuilder.AddType(typeDef); codeDomBuilder.GenerateCode(output); } LogLine(2, "done"); } resourcesToPrune.Add(resource); } if (!KeepXamlResources) { if (resourcesToPrune.Any()) { LogLine(2, " Removing compiled xaml resources"); } foreach (var resource in resourcesToPrune) { LogString(2, " Removing {0}... ", resource.Name); module.Resources.Remove(resource); LogLine(2, "done"); } } LogLine(2, ""); } if (!hasCompiledXamlResources) { LogLine(1, "No compiled resources. Skipping writing assembly."); return(success); } LogString(1, "Writing the assembly... "); try { assemblyDefinition.Write(Assembly, new WriterParameters { WriteSymbols = DebugSymbols }); LogLine(1, "done."); } catch (Exception e) { LogLine(1, "failed."); LogError(null, null, null, null, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source); LogLine(4, e.StackTrace); success = false; } return(success); }
void Run(Config config) { if (config.AssembliesToDecompile.Count == 0) { config.ShowHelp = true; } if (config.ShowHelp) { Console.WriteLine("Netjs compiler, Copyright 2014-2016 Frank A. Krueger"); Console.WriteLine("netjs [options] assembly-files"); Console.WriteLine(" --help, -h Show usage information"); Console.WriteLine(" --includerefs, -r Decompile referenced assemblies"); return; } string outPath = ""; var asmPaths = new List <string> (); foreach (var asmRelPath in config.AssembliesToDecompile) { var asmPath = Path.GetFullPath(asmRelPath); asmPaths.Add(asmPath); if (string.IsNullOrEmpty(outPath)) { outPath = Path.ChangeExtension(asmPath, ".ts"); } var asmDir = Path.GetDirectoryName(asmPath); if (!asmSearchPaths.Exists(x => x.Item1 == asmDir)) { asmSearchPaths.Add(Tuple.Create(asmDir, config.IncludeRefs)); } } Step("Reading IL"); globalReaderParameters.AssemblyResolver = this; globalReaderParameters.ReadingMode = ReadingMode.Immediate; var libDir = Path.GetDirectoryName(typeof(String).Assembly.Location); asmSearchPaths.Add(Tuple.Create(libDir, false)); asmSearchPaths.Add(Tuple.Create(Path.Combine(libDir, "Facades"), false)); AssemblyDefinition firstAsm = null; foreach (var asmPath in asmPaths) { var asm = AssemblyDefinition.ReadAssembly(asmPath, globalReaderParameters); if (firstAsm == null) { firstAsm = asm; } referencedAssemblies[asm.Name.Name] = asm; decompileAssemblies.Add(asm); } Step("Decompiling IL to C#"); var context = new DecompilerContext(firstAsm.MainModule); context.Settings.ForEachStatement = false; context.Settings.ObjectOrCollectionInitializers = false; context.Settings.UsingStatement = false; context.Settings.AsyncAwait = false; context.Settings.AutomaticProperties = true; context.Settings.AutomaticEvents = true; context.Settings.QueryExpressions = false; context.Settings.AlwaysGenerateExceptionVariableForCatchBlocks = true; context.Settings.UsingDeclarations = false; context.Settings.FullyQualifyAmbiguousTypeNames = true; context.Settings.YieldReturn = false; var builder = new AstBuilder(context); var decompiled = new HashSet <string> (); for (;;) { var a = decompileAssemblies.FirstOrDefault(x => !decompiled.Contains(x.FullName)); if (a != null) { Info(" Decompiling {0}", a.FullName); builder.AddAssembly(a); decompiled.Add(a.FullName); } else { break; } } builder.RunTransformations(); Step("Translating C# to TypeScript"); new CsToTs().Run(builder.SyntaxTree); Step("Writing"); using (var outputWriter = new StreamWriter(outPath)) { var output = new PlainTextOutput(outputWriter); builder.GenerateCode(output, (s, e) => new TsOutputVisitor(s, e)); } Step("Done"); }
public AstOptimizer(DecompilerContext context, AstBlock method) { this.context = context; this.method = method; }
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) { this.context = context; this.typeSystem = context.CurrentMethod.Module.TypeSystem; this.method = method; if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode) { return; } RemoveRedundantCode(method); if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { ReduceBranchInstructionSet(block); } // ReduceBranchInstructionSet runs before inlining because the non-aggressive inlining heuristic // looks at which type of instruction consumes the inlined variable. if (abortBeforeStep == ILAstOptimizationStep.InlineVariables) { return; } // Works better after simple goto removal because of the following debug pattern: stloc X; br Next; Next:; ldloc X ILInlining inlining1 = new ILInlining(method); inlining1.InlineAllVariables(); if (abortBeforeStep == ILAstOptimizationStep.CopyPropagation) { return; } inlining1.CopyPropagation(); if (abortBeforeStep == ILAstOptimizationStep.YieldReturn) { return; } YieldReturnDecompiler.Run(context, method); AsyncDecompiler.RunStep1(context, method); if (abortBeforeStep == ILAstOptimizationStep.AsyncAwait) { return; } AsyncDecompiler.RunStep2(context, method); //if (abortBeforeStep == ILAstOptimizationStep.PropertyAccessInstructions) return; //IntroducePropertyAccessInstructions(method); if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { SplitToBasicBlocks(block); } if (abortBeforeStep == ILAstOptimizationStep.TypeInference) { return; } // Types are needed for the ternary operator optimization TypeAnalysis.Run(context, method); foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { bool modified; do { modified = false; if (abortBeforeStep == ILAstOptimizationStep.SimplifyShortCircuit) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyShortCircuit); if (abortBeforeStep == ILAstOptimizationStep.SimplifyTernaryOperator) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyTernaryOperator); if (abortBeforeStep == ILAstOptimizationStep.SimplifyNullCoalescing) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyNullCoalescing); if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks); if (abortBeforeStep == ILAstOptimizationStep.SimplifyLogicNot) { return; } modified |= block.RunOptimization(SimplifyLogicNot); if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) { return; } modified |= block.RunOptimization(SimplifyShiftOperators); if (abortBeforeStep == ILAstOptimizationStep.TypeConversionSimplifications) { return; } modified |= block.RunOptimization(TypeConversionSimplifications); if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) { return; } modified |= block.RunOptimization(SimplifyLdObjAndStObj); if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit); if (abortBeforeStep == ILAstOptimizationStep.SimplifyLiftedOperators) { return; } modified |= block.RunOptimization(SimplifyLiftedOperators); //if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return; //modified |= block.RunOptimization(TransformArrayInitializers); //if (abortBeforeStep == ILAstOptimizationStep.TransformMultidimensionalArrayInitializers) return; //modified |= block.RunOptimization(TransformMultidimensionalArrayInitializers); //if (abortBeforeStep == ILAstOptimizationStep.TransformObjectInitializers) return; //modified |= block.RunOptimization(TransformObjectInitializers); if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression) { return; } modified |= block.RunOptimization(MakeAssignmentExpression); modified |= block.RunOptimization(MakeCompoundAssignments); if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) { return; } modified |= block.RunOptimization(IntroducePostIncrement); if (abortBeforeStep == ILAstOptimizationStep.InlineExpressionTreeParameterDeclarations) { return; } if (context.Settings.ExpressionTrees) { modified |= block.RunOptimization(InlineExpressionTreeParameterDeclarations); } if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) { return; } modified |= new ILInlining(method).InlineAllInBlock(block); new ILInlining(method).CopyPropagation(); } while(modified); } if (abortBeforeStep == ILAstOptimizationStep.FindLoops) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { new LoopsAndConditions(context).FindLoops(block); } if (abortBeforeStep == ILAstOptimizationStep.FindConditions) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { new LoopsAndConditions(context).FindConditions(block); } if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) { return; } FlattenBasicBlocks(method); if (abortBeforeStep == ILAstOptimizationStep.RemoveEndFinally) { return; } RemoveEndFinally(method); if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) { return; } RemoveRedundantCode(method); if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval) { return; } new GotoRemoval().RemoveGotos(method); if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) { return; } DuplicateReturnStatements(method); if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval2) { return; } new GotoRemoval().RemoveGotos(method); if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting) { return; } ReduceIfNesting(method); if (abortBeforeStep == ILAstOptimizationStep.InlineVariables3) { return; } // The 2nd inlining pass is necessary because DuplicateReturns and the introduction of ternary operators // open up additional inlining possibilities. new ILInlining(method).InlineAllVariables(); if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { for (int i = 0; i < block.Body.Count; i++) { // TODO: Move before loops CachedDelegateInitializationWithField(block, ref i); CachedDelegateInitializationWithLocal(block, ref i); } } if (abortBeforeStep == ILAstOptimizationStep.IntroduceFixedStatements) { return; } // we need post-order traversal, not pre-order, for "fixed" to work correctly foreach (ILBlock block in TreeTraversal.PostOrder <ILNode>(method, n => n.GetChildren()).OfType <ILBlock>()) { for (int i = block.Body.Count - 1; i >= 0; i--) { // TODO: Move before loops if (i < block.Body.Count) { IntroduceFixedStatements(block.Body, i); } } } if (abortBeforeStep == ILAstOptimizationStep.RecombineVariables) { return; } RecombineVariables(method); if (abortBeforeStep == ILAstOptimizationStep.TypeInference2) { return; } TypeAnalysis.Reset(method); TypeAnalysis.Run(context, method); if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode3) { return; } GotoRemoval.RemoveRedundantCode(method); // ReportUnassignedILRanges(method); }
public bool Compile(IList <Exception> thrownExceptions = null) { LogLine(1, "Compiling Xaml"); LogLine(1, "\nAssembly: {0}", Assembly); if (!string.IsNullOrEmpty(DependencyPaths)) { LogLine(1, "DependencyPaths: \t{0}", DependencyPaths); } if (!string.IsNullOrEmpty(ReferencePath)) { LogLine(1, "ReferencePath: \t{0}", ReferencePath.Replace("//", "/")); } LogLine(3, "DebugSymbols:\"{0}\"", DebugSymbols); var skipassembly = true; //change this to false to enable XamlC by default bool success = true; if (!File.Exists(Assembly)) { LogLine(1, "Assembly file not found. Skipping XamlC."); return(true); } var resolver = new XamlCAssemblyResolver(); if (!string.IsNullOrEmpty(DependencyPaths)) { foreach (var dep in DependencyPaths.Split(';')) { LogLine(3, "Adding searchpath {0}", dep); resolver.AddSearchDirectory(dep); } } if (!string.IsNullOrEmpty(ReferencePath)) { var paths = ReferencePath.Replace("//", "/").Split(';'); foreach (var p in paths) { var searchpath = Path.GetDirectoryName(p); LogLine(3, "Adding searchpath {0}", searchpath); resolver.AddSearchDirectory(searchpath); } } var assemblyDefinition = AssemblyDefinition.ReadAssembly(Path.GetFullPath(Assembly), new ReaderParameters { AssemblyResolver = resolver, ReadSymbols = DebugSymbols }); CustomAttribute xamlcAttr; if (assemblyDefinition.HasCustomAttributes && (xamlcAttr = assemblyDefinition.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) { skipassembly = true; } if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) { skipassembly = false; } } foreach (var module in assemblyDefinition.Modules) { var skipmodule = skipassembly; if (module.HasCustomAttributes && (xamlcAttr = module.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) { skipmodule = true; } if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) { skipmodule = false; } } LogLine(2, " Module: {0}", module.Name); var resourcesToPrune = new List <EmbeddedResource>(); foreach (var resource in module.Resources.OfType <EmbeddedResource>()) { LogString(2, " Resource: {0}... ", resource.Name); string classname; if (!resource.IsXaml(out classname)) { LogLine(2, "skipped."); continue; } TypeDefinition typeDef = module.GetType(classname); if (typeDef == null) { LogLine(2, "no type found... skipped."); continue; } var skiptype = skipmodule; if (typeDef.HasCustomAttributes && (xamlcAttr = typeDef.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) { skiptype = true; } if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) { skiptype = false; } } if (Type != null) { skiptype = !(Type == classname); } if (skiptype) { LogLine(2, "Has XamlCompilationAttribute set to Skip and not Compile... skipped"); continue; } var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent"); if (initComp == null) { LogLine(2, "no InitializeComponent found... skipped."); continue; } LogLine(2, ""); var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime"); if (initCompRuntime != null) { LogLine(2, " __InitComponentRuntime already exists... not duplicating"); } else { LogString(2, " Duplicating {0}.InitializeComponent () into {0}.__InitComponentRuntime ... ", typeDef.Name); initCompRuntime = DuplicateMethodDef(typeDef, initComp, "__InitComponentRuntime"); LogLine(2, "done."); } LogString(2, " Parsing Xaml... "); var rootnode = ParseXaml(resource.GetResourceStream(), typeDef); if (rootnode == null) { LogLine(2, "failed."); continue; } LogLine(2, "done."); hasCompiledXamlResources = true; LogString(2, " Replacing {0}.InitializeComponent ()... ", typeDef.Name); Exception e; if (!TryCoreCompile(initComp, initCompRuntime, rootnode, out e)) { success = false; LogLine(2, "failed."); thrownExceptions?.Add(e); LogException(null, null, null, resource.Name, e); LogLine(4, e.StackTrace); continue; } LogLine(2, "done."); if (OptimizeIL) { LogString(2, " Optimizing IL... "); initComp.Body.OptimizeMacros(); LogLine(2, "done"); } if (OutputGeneratedILAsCode) { var filepath = Path.Combine(Path.GetDirectoryName(Assembly), typeDef.FullName + ".decompiled.cs"); LogString(2, " Decompiling {0} into {1}...", typeDef.FullName, filepath); var decompilerContext = new DecompilerContext(module); using (var writer = new StreamWriter(filepath)) { var output = new PlainTextOutput(writer); var codeDomBuilder = new AstBuilder(decompilerContext); codeDomBuilder.AddType(typeDef); codeDomBuilder.GenerateCode(output); } LogLine(2, "done"); } resourcesToPrune.Add(resource); } if (!KeepXamlResources) { if (resourcesToPrune.Any()) { LogLine(2, " Removing compiled xaml resources"); } foreach (var resource in resourcesToPrune) { LogString(2, " Removing {0}... ", resource.Name); module.Resources.Remove(resource); LogLine(2, "done"); } } LogLine(2, ""); } if (!hasCompiledXamlResources) { LogLine(1, "No compiled resources. Skipping writing assembly."); return(success); } LogString(1, "Writing the assembly... "); try { assemblyDefinition.Write(Assembly, new WriterParameters { WriteSymbols = DebugSymbols }); LogLine(1, "done."); } catch (Exception e) { LogLine(1, "failed."); LogException(null, null, null, null, e); thrownExceptions?.Add(e); LogLine(4, e.StackTrace); success = false; } return(success); }
public VBTextOutputFormatter(IDecompilerOutput output, DecompilerContext context) { this.output = output ?? throw new ArgumentNullException(nameof(output)); this.context = context ?? throw new ArgumentNullException(nameof(context)); }
public static void RunTransformationsUntil(AstNode node, Predicate <IAstTransform> abortCondition, DecompilerContext context) { if (node == null) { return; } var pipeline = context.Cache.GetPipelinePool(); try { foreach (var transform in pipeline) { transform.Reset(context); context.CancellationToken.ThrowIfCancellationRequested(); if (abortCondition != null && abortCondition(transform)) { return; } transform.Run(node); } } finally { context.Cache.Return(pipeline); } }
CodeGeneratorMemberResult GenerateCode(IMethod method, CodeGenerationOptions options) { int bodyStartOffset = -1, bodyEndOffset = -1; StringBuilder result = new StringBuilder(); AppendModifiers(result, options, method); AppendReturnType(result, options, method.ReturnType); result.Append(" "); if (options.ExplicitDeclaration) { AppendReturnType(result, options, method.DeclaringType); result.Append("."); } result.Append(CSharpAmbience.FilterName(method.Name)); if (method.TypeParameters.Count > 0) { result.Append("<"); for (int i = 0; i < method.TypeParameters.Count; i++) { if (i > 0) { result.Append(", "); } var p = method.TypeParameters [i]; result.Append(CSharpAmbience.FilterName(p.Name)); } result.Append(">"); } if (Policy.BeforeMethodDeclarationParentheses) { result.Append(" "); } result.Append("("); AppendParameterList(result, options, method.Parameters); result.Append(")"); var typeParameters = method.TypeParameters; // This should also check the types are in the correct mscorlib Func <IType, bool> validBaseType = t => t.FullName != "System.Object" && t.FullName != "System.ValueType"; bool isFromInterface = method.DeclaringType != null && method.DeclaringTypeDefinition.Kind == TypeKind.Interface; if (!options.ExplicitDeclaration && isFromInterface && typeParameters.Any(p => p.HasDefaultConstructorConstraint || p.HasReferenceTypeConstraint || p.HasValueTypeConstraint || p.DirectBaseTypes.Any(validBaseType))) { result.Append(" where "); int typeParameterCount = 0; foreach (var p in typeParameters) { if (typeParameterCount != 0) { result.Append(", "); } typeParameterCount++; result.Append(CSharpAmbience.FilterName(p.Name)); result.Append(" : "); int constraintCount = 0; if (p.HasDefaultConstructorConstraint) { result.Append("new ()"); constraintCount++; } if (p.HasValueTypeConstraint) { if (constraintCount != 0) { result.Append(", "); } result.Append("struct"); constraintCount++; } if (p.HasReferenceTypeConstraint) { if (constraintCount != 0) { result.Append(", "); } result.Append("class"); constraintCount++; } // bool hadInterfaces = false; foreach (var c in p.DirectBaseTypes.Where(validBaseType)) { if (constraintCount != 0) { result.Append(", "); } constraintCount++; AppendReturnType(result, options, c); // if (c.Kind == TypeKind.Interface) // hadInterfaces = true; } } } if (options.ImplementingType.Kind == TypeKind.Interface) { result.Append(";"); } else { AppendBraceStart(result, Policy.MethodBraceStyle); if (method.Name == "ToString" && (method.Parameters == null || method.Parameters.Count == 0) && method.ReturnType != null /* && method.ReturnType.FullName == "System.String"*/) { AppendIndent(result); bodyStartOffset = result.Length; result.Append("return string.Format"); if (Policy.BeforeMethodDeclarationParentheses) { result.Append(" "); } result.Append("(\"["); result.Append(options.ImplementingType.Name); if (options.ImplementingType.Properties.Any()) { result.Append(": "); } int i = 0; foreach (IProperty property in options.ImplementingType.Properties) { if (property.IsStatic || !property.IsPublic) { continue; } if (i > 0) { result.Append(", "); } result.Append(property.Name); result.Append("={"); result.Append(i++); result.Append("}"); } result.Append("]\""); foreach (IProperty property in options.ImplementingType.Properties) { if (property.IsStatic || !property.IsPublic) { continue; } result.Append(", "); result.Append(property.Name); } result.Append(");"); bodyEndOffset = result.Length; AppendLine(result); } else if (IsMonoTouchModelMember(method)) { AppendMonoTouchTodo(result, out bodyStartOffset, out bodyEndOffset); } else if (method.IsAbstract || !(method.IsVirtual || method.IsOverride) || method.DeclaringTypeDefinition.Kind == TypeKind.Interface) { AppendNotImplementedException(result, options, out bodyStartOffset, out bodyEndOffset); } else { bool skipBody = false; // Analyze if the body consists just of a single throw instruction // See: Bug 1373 - overriding [Model] class methods shouldn't insert base.Methods // TODO: Extend this to user defined code. try { if (method.Region.FileName == null) { var asm = AssemblyDefinition.ReadAssembly(method.ParentAssembly.UnresolvedAssembly.Location); foreach (var type in asm.MainModule.Types) { if (type.FullName != method.DeclaringType.FullName) { continue; } foreach (var m in type.Resolve().Methods) { if (m.HasBody && m.Name == method.Name) { var context = new DecompilerContext(asm.MainModule); context.CurrentType = type; context.Settings = new DecompilerSettings() { AnonymousMethods = true, AutomaticEvents = true, AutomaticProperties = true, ForEachStatement = true, LockStatement = true }; var astBuilder = new AstBuilder(context); astBuilder.AddMethod(m); astBuilder.RunTransformations(o => false); var visitor = new ThrowsExceptionVisitor(); astBuilder.CompilationUnit.AcceptVisitor(visitor); skipBody = visitor.Throws; if (skipBody) { break; } } } if (skipBody) { break; } } } } catch (Exception) { } AppendIndent(result); bodyStartOffset = result.Length; if (!skipBody) { if (method.ReturnType.ReflectionName != typeof(void).FullName) { result.Append("return "); } result.Append("base."); result.Append(CSharpAmbience.FilterName(method.Name)); if (Policy.BeforeMethodCallParentheses) { result.Append(" "); } result.Append("("); for (int i = 0; i < method.Parameters.Count; i++) { if (i > 0) { result.Append(", "); } var p = method.Parameters [i]; if (p.IsOut) { result.Append("out "); } if (p.IsRef) { result.Append("ref "); } result.Append(CSharpAmbience.FilterName(p.Name)); } result.Append(");"); } else { result.Append("throw new System.NotImplementedException ();"); } bodyEndOffset = result.Length; AppendLine(result); } AppendBraceEnd(result, Policy.MethodBraceStyle); } return(new CodeGeneratorMemberResult(result.ToString(), bodyStartOffset, bodyEndOffset)); }
public void Reset(DecompilerContext context) { this.context = context; }
private bool SimplifyStackVarsExprents(List <Exprent> list, StructClass cl) { bool res = false; int index = 0; while (index < list.Count) { Exprent current = list[index]; Exprent ret = IsSimpleConstructorInvocation(current); if (ret != null) { list[index] = ret; res = true; continue; } // lambda expression (Java 8) ret = IsLambda(current, cl); if (ret != null) { list[index] = ret; res = true; continue; } // remove monitor exit if (IsMonitorExit(current)) { list.RemoveAtReturningValue(index); res = true; continue; } // trivial assignment of a stack variable if (IsTrivialStackAssignment(current)) { list.RemoveAtReturningValue(index); res = true; continue; } if (index == list.Count - 1) { break; } Exprent next = list[index + 1]; // constructor invocation if (IsConstructorInvocationRemote(list, index)) { list.RemoveAtReturningValue(index); res = true; continue; } // remove getClass() invocation, which is part of a qualified new if (DecompilerContext.GetOption(IFernflowerPreferences.Remove_Get_Class_New)) { if (IsQualifiedNewGetClass(current, next)) { list.RemoveAtReturningValue(index); res = true; continue; } } // direct initialization of an array int arrCount = IsArrayInitializer(list, index); if (arrCount > 0) { for (int i = 0; i < arrCount; i++) { list.RemoveAtReturningValue(index + 1); } res = true; continue; } // add array initializer expression if (AddArrayInitializer(current, next)) { list.RemoveAtReturningValue(index + 1); res = true; continue; } // integer ++expr and --expr (except for vars!) Exprent func = IsPPIorMMI(current); if (func != null) { list[index] = func; res = true; continue; } // expr++ and expr-- if (IsIPPorIMM(current, next) || IsIPPorIMM2(current, next)) { list.RemoveAtReturningValue(index + 1); res = true; continue; } // assignment on stack if (IsStackAssignment(current, next)) { list.RemoveAtReturningValue(index + 1); res = true; continue; } if (!firstInvocation && IsStackAssignment2(current, next)) { list.RemoveAtReturningValue(index + 1); res = true; continue; } index++; } return(res); }
protected abstract void WriteResult(TextWriter writer, IEnumerable <AstNode> ast, DecompilerContext context);
public IntroduceUsingDeclarations(DecompilerContext context) { this.context = context; }
public PatternMatcher(DecompilerContext context, ICorLibTypes corLib) { this.context = context; this.corLib = corLib; }
public ReplaceMethodCallsWithOperators(DecompilerContext context) { this.context = context; }