Table of Contents

Namespace ICSharpCode.Decompiler.IL.ControlFlow

Classes

AsyncAwaitDecompiler

Decompiler step for C# 5 async/await.

ConditionDetection

Detects 'if' structure and other non-loop aspects of control flow.

ControlFlowGraph

Holds the control flow graph. A separate graph is computed for each BlockContainer at the start of the block transforms (before loop detection).

ControlFlowSimplification

This transform 'optimizes' the control flow logic in the IL code: it replaces constructs that are generated by the C# compiler in debug mode with shorter constructs that are more straightforward to analyze.

DetectExitPoints

Detect suitable exit points for BlockContainers.

An "exit point" is an instruction that causes control flow to leave the container (a branch or leave instruction).

If an "exit point" instruction is placed immediately following a block container, each equivalent exit point within the container can be replaced with a "leave container" instruction.

This transform performs this replacement: any exit points equivalent to the exit point following the container are replaced with a leave instruction. Additionally, if the container is not yet followed by an exit point, but has room to introduce such an exit point (i.e. iff the container's end point is currently unreachable), we pick one of the non-return exit points within the container, move it to the position following the container, and replace all instances within the container with a leave instruction.

This makes it easier for the following transforms to construct control flow that falls out of blocks instead of using goto/break statements.

DetectPinnedRegions

IL uses 'pinned locals' to prevent the GC from moving objects.

C#:

fixed (int* s = &arr[index]) { use(s); use(s); }

Gets translated into IL:

pinned local P : System.Int32&

stloc(P, ldelema(arr, index)) call use(conv ref->i(ldloc P)) call use(conv ref->i(ldloc P)) stloc(P, conv i4->u(ldc.i4 0))

In C#, the only way to pin something is to use a fixed block (or to mess around with GCHandles). But fixed blocks are scoped, so we need to detect the region affected by the pin. To ensure we'll be able to collect all blocks in that region, we perform this transform early, before building any other control flow constructs that aren't as critical for correctness.

This means this transform must run before LoopDetection. To make our detection job easier, we must run after variable inlining.

LoopDetection

Detect loops in IL AST.

SwitchDetection

C# switch statements are not necessarily compiled into IL switch instructions (e.g. when the integer values are non-contiguous).

Detect sequences of conditional branches that all test a single integer value, and simplify them into a ILAst switch instruction (which like C# does not require contiguous values).

SwitchDetection.LoopContext

When detecting a switch, it is important to distinguish Branch instructions which will eventually decompile to continue; statements.

A LoopContext is constructed for a node and its dominator tree, as for a Branch to be a continue; statement, it must be contained within the target-loop

This class also supplies the depth of the loop targetted by a continue; statement relative to the context node, to avoid (or eventually support) labelled continues to outer loops

YieldReturnDecompiler