summaryrefslogtreecommitdiff
path: root/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs')
-rw-r--r--ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs257
1 files changed, 0 insertions, 257 deletions
diff --git a/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs b/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs
deleted file mode 100644
index c7c86a57..00000000
--- a/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright (c) 2010 Daniel Grunwald
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this
-// software and associated documentation files (the "Software"), to deal in the Software
-// without restriction, including without limitation the rights to use, copy, modify, merge,
-// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
-// to whom the Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or
-// substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-
-namespace ICSharpCode.Decompiler.FlowAnalysis
-{
- /// <summary>
- /// Constructs "SsaForm" graph for a CFG.
- /// This class transforms the method from stack-based IL to a register-based IL language.
- /// Then it calls into TransformToSsa to convert the resulting graph to static single assignment form.
- /// </summary>
- public sealed class SsaFormBuilder
- {
- public static SsaForm Build(MethodDefinition method)
- {
- if (method == null)
- throw new ArgumentNullException("method");
- var cfg = ControlFlowGraphBuilder.Build(method.Body);
- cfg.ComputeDominance();
- cfg.ComputeDominanceFrontier();
- var ssa = BuildRegisterIL(method, cfg);
- TransformToSsa.Transform(cfg, ssa);
- return ssa;
- }
-
- public static SsaForm BuildRegisterIL(MethodDefinition method, ControlFlowGraph cfg)
- {
- if (method == null)
- throw new ArgumentNullException("method");
- if (cfg == null)
- throw new ArgumentNullException("cfg");
- return new SsaFormBuilder(method, cfg).Build();
- }
-
- readonly MethodDefinition method;
- readonly ControlFlowGraph cfg;
-
- readonly SsaBlock[] blocks; // array index = block index
- readonly int[] stackSizeAtBlockStart; // array index = block index
-
- readonly SsaVariable[] parameters; // array index = parameter number
- readonly SsaVariable[] locals; // array index = local number
- readonly SsaVariable[] stackLocations; // array index = position on the IL evaluation stack
- SsaForm ssaForm;
-
- SsaFormBuilder(MethodDefinition method, ControlFlowGraph cfg)
- {
- this.method = method;
- this.cfg = cfg;
-
- blocks = new SsaBlock[cfg.Nodes.Count];
- stackSizeAtBlockStart = new int[cfg.Nodes.Count];
- for (int i = 0; i < stackSizeAtBlockStart.Length; i++) {
- stackSizeAtBlockStart[i] = -1;
- }
- stackSizeAtBlockStart[cfg.EntryPoint.BlockIndex] = 0;
-
- parameters = new SsaVariable[method.Parameters.Count + (method.HasThis ? 1 : 0)];
- if (method.HasThis)
- parameters[0] = new SsaVariable(method.Body.ThisParameter);
- for (int i = 0; i < method.Parameters.Count; i++)
- parameters[i + (method.HasThis ? 1 : 0)] = new SsaVariable(method.Parameters[i]);
-
- locals = new SsaVariable[method.Body.Variables.Count];
- for (int i = 0; i < locals.Length; i++)
- locals[i] = new SsaVariable(method.Body.Variables[i]);
-
- stackLocations = new SsaVariable[method.Body.MaxStackSize];
- for (int i = 0; i < stackLocations.Length; i++) {
- stackLocations[i] = new SsaVariable(i);
- }
- }
-
- internal SsaForm Build()
- {
- CreateGraphStructure();
- ssaForm = new SsaForm(blocks, parameters, locals, stackLocations, method.HasThis);
- CreateInstructions(cfg.EntryPoint.BlockIndex);
- CreateSpecialInstructions();
- return ssaForm;
- }
-
- void CreateGraphStructure()
- {
- for (int i = 0; i < blocks.Length; i++) {
- blocks[i] = new SsaBlock(cfg.Nodes[i]);
- }
- for (int i = 0; i < blocks.Length; i++) {
- foreach (ControlFlowNode node in cfg.Nodes[i].Successors) {
- blocks[i].Successors.Add(blocks[node.BlockIndex]);
- blocks[node.BlockIndex].Predecessors.Add(blocks[i]);
- }
- }
- }
-
- void CreateInstructions(int blockIndex)
- {
- ControlFlowNode cfgNode = cfg.Nodes[blockIndex];
- SsaBlock block = blocks[blockIndex];
-
- int stackSize = stackSizeAtBlockStart[blockIndex];
- Debug.Assert(stackSize >= 0);
-
- List<Instruction> prefixes = new List<Instruction>();
- foreach (Instruction inst in cfgNode.Instructions) {
- if (inst.OpCode.OpCodeType == OpCodeType.Prefix) {
- prefixes.Add(inst);
- continue;
- }
-
- int popCount = inst.GetPopDelta(method) ?? stackSize;
- stackSize -= popCount;
- if (stackSize < 0)
- throw new InvalidProgramException("IL stack underflow");
-
- int pushCount = inst.GetPushDelta();
- if (stackSize + pushCount > stackLocations.Length)
- throw new InvalidProgramException("IL stack overflow");
-
- SsaVariable target;
- SsaVariable[] operands;
- DetermineOperands(stackSize, inst, popCount, pushCount, out target, out operands);
-
- Instruction[] prefixArray = prefixes.Count > 0 ? prefixes.ToArray() : null;
- prefixes.Clear();
-
- // ignore NOP instructions
- if (!(inst.OpCode == OpCodes.Nop || inst.OpCode == OpCodes.Pop)) {
- block.Instructions.Add(new SsaInstruction(block, inst, target, operands, prefixArray));
- }
- stackSize += pushCount;
- }
-
- foreach (ControlFlowEdge edge in cfgNode.Outgoing) {
- int newStackSize;
- switch (edge.Type) {
- case JumpType.Normal:
- newStackSize = stackSize;
- break;
- case JumpType.EndFinally:
- if (stackSize != 0)
- throw new NotSupportedException("stacksize must be 0 in endfinally edge");
- newStackSize = 0;
- break;
- case JumpType.JumpToExceptionHandler:
- switch (edge.Target.NodeType) {
- case ControlFlowNodeType.FinallyOrFaultHandler:
- newStackSize = 0;
- break;
- case ControlFlowNodeType.ExceptionalExit:
- case ControlFlowNodeType.CatchHandler:
- newStackSize = 1;
- break;
- default:
- throw new NotSupportedException("unsupported target node type: " + edge.Target.NodeType);
- }
- break;
- default:
- throw new NotSupportedException("unsupported jump type: " + edge.Type);
- }
-
- int nextStackSize = stackSizeAtBlockStart[edge.Target.BlockIndex];
- if (nextStackSize == -1) {
- stackSizeAtBlockStart[edge.Target.BlockIndex] = newStackSize;
- CreateInstructions(edge.Target.BlockIndex);
- } else if (nextStackSize != newStackSize) {
- throw new InvalidProgramException("Stack size doesn't match");
- }
- }
- }
-
- void DetermineOperands(int stackSize, Instruction inst, int popCount, int pushCount, out SsaVariable target, out SsaVariable[] operands)
- {
- switch (inst.OpCode.Code) {
- case Code.Ldarg:
- operands = new SsaVariable[] { ssaForm.GetOriginalVariable((ParameterReference)inst.Operand) };
- target = stackLocations[stackSize];
- break;
- case Code.Starg:
- operands = new SsaVariable[] { stackLocations[stackSize] };
- target = ssaForm.GetOriginalVariable((ParameterReference)inst.Operand);
- break;
- case Code.Ldloc:
- operands = new SsaVariable[] { ssaForm.GetOriginalVariable((VariableReference)inst.Operand) };
- target = stackLocations[stackSize];
- break;
- case Code.Stloc:
- operands = new SsaVariable[] { stackLocations[stackSize] };
- target = ssaForm.GetOriginalVariable((VariableReference)inst.Operand);
- break;
- case Code.Dup:
- operands = new SsaVariable[] { stackLocations[stackSize] };
- target = stackLocations[stackSize + 1];
- break;
- default:
- operands = new SsaVariable[popCount];
- for (int i = 0; i < popCount; i++) {
- operands[i] = stackLocations[stackSize + i];
- }
-
- switch (pushCount) {
- case 0:
- target = null;
- break;
- case 1:
- target = stackLocations[stackSize];
- break;
- default:
- throw new NotSupportedException("unsupported pushCount=" + pushCount);
- }
- break;
- }
- }
-
- void CreateSpecialInstructions()
- {
- // Everything needs an initial write for the SSA transformation to work correctly.
- foreach (SsaVariable v in parameters) {
- ssaForm.EntryPoint.Instructions.Add(new SsaInstruction(ssaForm.EntryPoint, null, v, null, specialOpCode: SpecialOpCode.Parameter));
- }
- foreach (SsaVariable v in locals) {
- ssaForm.EntryPoint.Instructions.Add(new SsaInstruction(ssaForm.EntryPoint, null, v, null, specialOpCode: SpecialOpCode.Uninitialized));
- }
- foreach (SsaVariable v in stackLocations) {
- ssaForm.EntryPoint.Instructions.Add(new SsaInstruction(ssaForm.EntryPoint, null, v, null, specialOpCode: SpecialOpCode.Uninitialized));
- }
- foreach (SsaBlock b in blocks) {
- if (b.NodeType == ControlFlowNodeType.CatchHandler) {
- b.Instructions.Add(new SsaInstruction(b, null, stackLocations[0], null,
- specialOpCode: SpecialOpCode.Exception,
- typeOperand: cfg.Nodes[b.BlockIndex].ExceptionHandler.CatchType));
- }
- }
- }
- }
-}