Browse Source

Switched to "define-use" naming convention in ILAstBuilder. Refactored variable splitting.

pull/285/merge
David Srbecký 14 years ago
parent
commit
e0e53ae650
  1. 330
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

330
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -28,78 +28,60 @@ using Cecil = Mono.Cecil; @@ -28,78 +28,60 @@ using Cecil = Mono.Cecil;
namespace ICSharpCode.Decompiler.ILAst
{
/// <summary>
/// Converts stack-based bytecode to variable-based bytecode by calculating use-define chains
/// </summary>
public class ILAstBuilder
{
/// <summary> Immutable </summary>
sealed class StackSlot
struct StackSlot
{
public readonly ByteCode[] PushedBy; // One of those
public readonly ILVariable LoadFrom; // Where can we get the value from in AST
public readonly ByteCode[] Definitions; // Reaching definitions of this stack slot
public readonly ILVariable LoadFrom; // Variable used for storage of the value
public StackSlot(ByteCode[] pushedBy, ILVariable loadFrom)
public StackSlot(ByteCode[] definitions, ILVariable loadFrom)
{
this.PushedBy = pushedBy;
this.Definitions = definitions;
this.LoadFrom = loadFrom;
}
public StackSlot(ByteCode pushedBy)
public static StackSlot[] ModifyStack(StackSlot[] stack, int popCount, int pushCount, ByteCode pushDefinition)
{
this.PushedBy = new[] { pushedBy };
this.LoadFrom = null;
}
public static List<StackSlot> CloneStack(List<StackSlot> stack, int? popCount)
{
if (popCount.HasValue) {
return stack.GetRange(0, stack.Count - popCount.Value);
} else {
return new List<StackSlot>(0);
StackSlot[] newStack = new StackSlot[stack.Length - popCount + pushCount];
Array.Copy(stack, newStack, stack.Length - popCount);
for (int i = stack.Length - popCount; i < newStack.Length; i++) {
newStack[i] = new StackSlot(new [] { pushDefinition }, null);
}
return newStack;
}
}
/// <summary> Immutable </summary>
sealed class VariableSlot
struct VariableSlot
{
public readonly ByteCode[] StoredBy; // One of those
public readonly bool StoredByAll; // Overestimate which is useful for exceptional control flow.
public readonly ByteCode[] Definitions; // Reaching deinitions of this variable
public readonly bool UnknownDefinition; // Used for initial state and exceptional control flow
static readonly VariableSlot EmptyInstance = new VariableSlot(new ByteCode[0], false);
public static readonly VariableSlot StoredByAllInstance = new VariableSlot(EmptyInstance.StoredBy, true);
static readonly VariableSlot UnknownInstance = new VariableSlot(new ByteCode[0], true);
public VariableSlot(ByteCode[] storedBy, bool storedByAll)
public VariableSlot(ByteCode[] definitions, bool unknownDefinition)
{
this.StoredBy = storedBy;
this.StoredByAll = storedByAll;
}
public VariableSlot(ByteCode storedBy)
{
this.StoredBy = new[] { storedBy };
this.StoredByAll = false;
this.Definitions = definitions;
this.UnknownDefinition = unknownDefinition;
}
public static VariableSlot[] CloneVariableState(VariableSlot[] state)
{
VariableSlot[] clone = new VariableSlot[state.Length];
Array.Copy(state, 0, clone, 0, state.Length);
Array.Copy(state, clone, state.Length);
return clone;
}
public static VariableSlot[] MakeEmptyState(int varCount)
{
VariableSlot[] emptyVariableState = new VariableSlot[varCount];
for (int i = 0; i < emptyVariableState.Length; i++) {
emptyVariableState[i] = EmptyInstance;
}
return emptyVariableState;
}
public static VariableSlot[] MakeFullState(int varCount)
public static VariableSlot[] MakeUknownState(int varCount)
{
VariableSlot[] unknownVariableState = new VariableSlot[varCount];
for (int i = 0; i < unknownVariableState.Length; i++) {
unknownVariableState[i] = StoredByAllInstance;
unknownVariableState[i] = UnknownInstance;
}
return unknownVariableState;
}
@ -117,11 +99,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -117,11 +99,15 @@ namespace ICSharpCode.Decompiler.ILAst
public string Name { get { return "IL_" + this.Offset.ToString("X2"); } }
public ByteCode Next;
public Instruction[] Prefixes; // Non-null only if needed
public List<StackSlot> StackBefore; // Unique per bytecode; not shared
public List<ILVariable> StoreTo; // Store result of instruction to those AST variables
public StackSlot[] StackBefore; // Unique per bytecode; not shared
public VariableSlot[] VariablesBefore; // Unique per bytecode; not shared
public List<ILVariable> StoreTo; // Store result of instruction to those AST variables
public VariableDefinition OperandAsVariable { get { return (VariableDefinition)this.Operand; } }
public bool IsVariableDefinition {
get {
return (this.Code == ILCode.Stloc) || (this.Code == ILCode.Ldloca && this.Next != null && this.Next.Code == ILCode.Initobj);
}
}
public override string ToString()
{
@ -170,9 +156,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -170,9 +156,9 @@ namespace ICSharpCode.Decompiler.ILAst
foreach (StackSlot slot in this.StackBefore) {
if (!first) sb.Append(",");
bool first2 = true;
foreach(ByteCode pushedBy in slot.PushedBy) {
foreach(ByteCode defs in slot.Definitions) {
if (!first2) sb.Append("|");
sb.AppendFormat("IL_{0:X2}", pushedBy.Offset);
sb.AppendFormat("IL_{0:X2}", defs.Offset);
first2 = false;
}
first = false;
@ -196,13 +182,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -196,13 +182,11 @@ namespace ICSharpCode.Decompiler.ILAst
bool first = true;
foreach (VariableSlot varSlot in this.VariablesBefore) {
if (!first) sb.Append(",");
if (varSlot.StoredByAll) {
sb.Append("*");
} else if (varSlot.StoredBy.Length == 0) {
sb.Append("_");
if (varSlot.UnknownDefinition) {
sb.Append("?");
} else {
bool first2 = true;
foreach (ByteCode storedBy in varSlot.StoredBy) {
foreach (ByteCode storedBy in varSlot.Definitions) {
if (!first2) sb.Append("|");
sb.AppendFormat("IL_{0:X2}", storedBy.Offset);
first2 = false;
@ -289,8 +273,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -289,8 +273,8 @@ namespace ICSharpCode.Decompiler.ILAst
if(methodDef.Body.HasExceptionHandlers) {
foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) {
ByteCode handlerStart = instrToByteCode[ex.HandlerStart];
handlerStart.StackBefore = new List<StackSlot>();
handlerStart.VariablesBefore = VariableSlot.MakeFullState(varCount);
handlerStart.StackBefore = new StackSlot[0];
handlerStart.VariablesBefore = VariableSlot.MakeUknownState(varCount);
if (ex.HandlerType == ExceptionHandlerType.Catch || ex.HandlerType == ExceptionHandlerType.Filter) {
// Catch and Filter handlers start with the exeption on the stack
ByteCode ldexception = new ByteCode() {
@ -300,15 +284,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -300,15 +284,13 @@ namespace ICSharpCode.Decompiler.ILAst
PushCount = 1
};
ldexceptions[ex] = ldexception;
handlerStart.StackBefore.Add(new StackSlot(ldexception));
handlerStart.StackBefore = new StackSlot[] { new StackSlot(new [] { ldexception }, null) };
}
agenda.Push(handlerStart);
if (ex.HandlerType == ExceptionHandlerType.Filter)
{
ByteCode filterStart = instrToByteCode[ex.FilterStart];
filterStart.StackBefore = new List<StackSlot>();
filterStart.VariablesBefore = VariableSlot.MakeFullState(varCount);
ByteCode ldexception = new ByteCode() {
Code = ILCode.Ldexception,
Operand = ex.CatchType,
@ -316,14 +298,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -316,14 +298,15 @@ namespace ICSharpCode.Decompiler.ILAst
PushCount = 1
};
// TODO: ldexceptions[ex] = ldexception;
filterStart.StackBefore.Add(new StackSlot(ldexception));
filterStart.StackBefore = new StackSlot[] { new StackSlot(new [] { ldexception }, null) };
filterStart.VariablesBefore = VariableSlot.MakeUknownState(varCount);
agenda.Push(filterStart);
}
}
}
body[0].StackBefore = new List<StackSlot>();
body[0].VariablesBefore = VariableSlot.MakeEmptyState(varCount);
body[0].StackBefore = new StackSlot[0];
body[0].VariablesBefore = VariableSlot.MakeUknownState(varCount);
agenda.Push(body[0]);
// Process agenda
@ -331,23 +314,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -331,23 +314,17 @@ namespace ICSharpCode.Decompiler.ILAst
ByteCode byteCode = agenda.Pop();
// Calculate new stack
List<StackSlot> newStack = StackSlot.CloneStack(byteCode.StackBefore, byteCode.PopCount);
for (int i = 0; i < byteCode.PushCount; i++) {
newStack.Add(new StackSlot(byteCode));
}
StackSlot[] newStack = StackSlot.ModifyStack(byteCode.StackBefore, byteCode.PopCount ?? byteCode.StackBefore.Length, byteCode.PushCount, byteCode);
// Calculate new variable state
VariableSlot[] newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore);
if (byteCode.Code == ILCode.Stloc || byteCode.Code == ILCode.Ldloca) {
int varIndex = ((VariableReference)byteCode.Operand).Index;
newVariableState[varIndex] = byteCode.Code == ILCode.Stloc || byteCode.Next.Code == ILCode.Initobj ?
new VariableSlot(byteCode) : !newVariableState[varIndex].StoredByAll && IsDeterministicLdloca(byteCode) ?
new VariableSlot(newVariableState[varIndex].StoredBy.Union(byteCode), false) : VariableSlot.StoredByAllInstance;
if (byteCode.IsVariableDefinition) {
newVariableState[((VariableReference)byteCode.Operand).Index] = new VariableSlot(new [] { byteCode }, false);
}
// After the leave, finally block might have touched the variables
if (byteCode.Code == ILCode.Leave) {
newVariableState = VariableSlot.MakeFullState(varCount);
newVariableState = VariableSlot.MakeUknownState(varCount);
}
// Find all successors
@ -386,12 +363,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -386,12 +363,12 @@ namespace ICSharpCode.Decompiler.ILAst
branchTarget.VariablesBefore = newVariableState;
} else {
// Do not share data for several bytecodes
branchTarget.StackBefore = StackSlot.CloneStack(newStack, 0);
branchTarget.StackBefore = StackSlot.ModifyStack(newStack, 0, 0, null);
branchTarget.VariablesBefore = VariableSlot.CloneVariableState(newVariableState);
}
agenda.Push(branchTarget);
} else {
if (branchTarget.StackBefore.Count != newStack.Count) {
if (branchTarget.StackBefore.Length != newStack.Length) {
throw new Exception("Inconsistent stack size at " + byteCode.Name);
}
@ -401,11 +378,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -401,11 +378,11 @@ namespace ICSharpCode.Decompiler.ILAst
bool modified = false;
// Merge stacks - modify the target
for (int i = 0; i < newStack.Count; i++) {
ByteCode[] oldPushedBy = branchTarget.StackBefore[i].PushedBy;
ByteCode[] newPushedBy = oldPushedBy.Union(newStack[i].PushedBy);
if (newPushedBy.Length > oldPushedBy.Length) {
branchTarget.StackBefore[i] = new StackSlot(newPushedBy, null);
for (int i = 0; i < newStack.Length; i++) {
ByteCode[] oldDefs = branchTarget.StackBefore[i].Definitions;
ByteCode[] newDefs = oldDefs.Union(newStack[i].Definitions);
if (newDefs.Length > oldDefs.Length) {
branchTarget.StackBefore[i] = new StackSlot(newDefs, null);
modified = true;
}
}
@ -414,16 +391,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -414,16 +391,15 @@ namespace ICSharpCode.Decompiler.ILAst
for (int i = 0; i < newVariableState.Length; i++) {
VariableSlot oldSlot = branchTarget.VariablesBefore[i];
VariableSlot newSlot = newVariableState[i];
// All can not be unioned further
if (!oldSlot.StoredByAll) {
if (newSlot.StoredByAll) {
if (!oldSlot.UnknownDefinition) {
if (newSlot.UnknownDefinition) {
branchTarget.VariablesBefore[i] = newSlot;
modified = true;
} else {
ByteCode[] oldStoredBy = oldSlot.StoredBy;
ByteCode[] newStoredBy = oldStoredBy.Union(newSlot.StoredBy);
if (newStoredBy.Length > oldStoredBy.Length) {
branchTarget.VariablesBefore[i] = new VariableSlot(newStoredBy, false);
ByteCode[] oldDefs = oldSlot.Definitions;
ByteCode[] newDefs = oldDefs.Union(newSlot.Definitions);
if (newDefs.Length > oldDefs.Length) {
branchTarget.VariablesBefore[i] = new VariableSlot(newDefs, false);
modified = true;
}
}
@ -437,18 +413,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -437,18 +413,18 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
// Occasionally the compilers or obfuscators generate unreachable code (which migt be intentonally invalid)
// Occasionally the compilers or obfuscators generate unreachable code (which might be intentonally invalid)
// I belive it is safe to just remove it
body.RemoveAll(b => b.StackBefore == null);
// Genertate temporary variables to replace stack
foreach(ByteCode byteCode in body) {
int argIdx = 0;
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length;
for (int i = byteCode.StackBefore.Length - popCount; i < byteCode.StackBefore.Length; i++) {
ILVariable tmpVar = new ILVariable() { Name = string.Format("arg_{0:X2}_{1}", byteCode.Offset, argIdx), IsGenerated = true };
byteCode.StackBefore[i] = new StackSlot(byteCode.StackBefore[i].PushedBy, tmpVar);
foreach(ByteCode pushedBy in byteCode.StackBefore[i].PushedBy) {
byteCode.StackBefore[i] = new StackSlot(byteCode.StackBefore[i].Definitions, tmpVar);
foreach(ByteCode pushedBy in byteCode.StackBefore[i].Definitions) {
if (pushedBy.StoreTo == null) {
pushedBy.StoreTo = new List<ILVariable>(1);
}
@ -467,16 +443,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -467,16 +443,16 @@ namespace ICSharpCode.Decompiler.ILAst
var loadedBy = locVars.Select(locVar => body.SelectMany(bc => bc.StackBefore).Single(s => s.LoadFrom == locVar)).ToList();
// We now know that all the variables have a single load,
// Let's make sure that they have also a single store - us
if (loadedBy.All(slot => slot.PushedBy.Length == 1 && slot.PushedBy[0] == byteCode)) {
if (loadedBy.All(slot => slot.Definitions.Length == 1 && slot.Definitions[0] == byteCode)) {
// Great - we can reduce everything into single variable
ILVariable tmpVar = new ILVariable() { Name = string.Format("expr_{0:X2}", byteCode.Offset), IsGenerated = true };
byteCode.StoreTo = new List<ILVariable>() { tmpVar };
foreach(ByteCode bc in body) {
for (int i = 0; i < bc.StackBefore.Count; i++) {
for (int i = 0; i < bc.StackBefore.Length; i++) {
// Is it one of the variable to be merged?
if (locVars.Contains(bc.StackBefore[i].LoadFrom)) {
// Replace with the new temp variable
bc.StackBefore[i] = new StackSlot(bc.StackBefore[i].PushedBy, tmpVar);
bc.StackBefore[i] = new StackSlot(bc.StackBefore[i].Definitions, tmpVar);
}
}
}
@ -531,14 +507,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -531,14 +507,16 @@ namespace ICSharpCode.Decompiler.ILAst
b = b.Next;
if (b == null) return false;
}
if (b.Code == ILCode.Ldfld || b.Code == ILCode.Stfld)
return true;
return (b.Code == ILCode.Call || b.Code == ILCode.Callvirt) && ((MethodReference)b.Operand).HasThis;
}
sealed class VariableInfo
{
public ILVariable Variable;
public List<ByteCode> Stores;
public List<ByteCode> Loads;
public List<ByteCode> Defs;
public List<ByteCode> Uses;
}
/// <summary>
@ -547,111 +525,75 @@ namespace ICSharpCode.Decompiler.ILAst @@ -547,111 +525,75 @@ namespace ICSharpCode.Decompiler.ILAst
/// </summary>
void ConvertLocalVariables(List<ByteCode> body)
{
if (optimize) {
int varCount = methodDef.Body.Variables.Count;
foreach(VariableDefinition varDef in methodDef.Body.Variables) {
for(int variableIndex = 0; variableIndex < varCount; variableIndex++) {
// Find all stores and loads for this variable
var stores = body.Where(b => (b.Code == ILCode.Stloc || b.Code == ILCode.Ldloca) && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
// ldloca on an uninitialized variable or followed by initobj isn't considered a load
var loads = body.Where(b =>
(b.Code == ILCode.Ldloc || (b.Code == ILCode.Ldloca && b.Next.Code != ILCode.Initobj &&
(b.VariablesBefore[variableIndex].StoredBy.Length != 0 || b.VariablesBefore[variableIndex].StoredByAll || !IsDeterministicLdloca(b))))
&& b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
TypeReference varType = methodDef.Body.Variables[variableIndex].VariableType;
// Find all definitions and uses of this variable
var defs = body.Where(b => b.Operand == varDef && b.IsVariableDefinition).ToList();
var uses = body.Where(b => b.Operand == varDef && !b.IsVariableDefinition).ToList();
List<VariableInfo> newVars;
// If the variable is pinned, use single variable.
// If any of the uses is from unknown definition, use single variable
// If any of the uses is ldloca with a nondeterministic usage pattern, use single variable
if (!optimize || varDef.IsPinned || uses.Any(b => b.VariablesBefore[varDef.Index].UnknownDefinition || (b.Code == ILCode.Ldloca && !IsDeterministicLdloca(b)))) {
newVars = new List<VariableInfo>(1) { new VariableInfo() {
Variable = new ILVariable() {
Name = string.IsNullOrEmpty(varDef.Name) ? "var_" + varDef.Index : varDef.Name,
Type = varDef.IsPinned ? ((PinnedType)varDef.VariableType).ElementType : varDef.VariableType,
OriginalVariable = varDef
},
Defs = defs,
Uses = uses
}};
} else {
// Create a new variable for each definition
newVars = defs.Select(def => new VariableInfo() {
Variable = new ILVariable() {
Name = (string.IsNullOrEmpty(varDef.Name) ? "var_" + varDef.Index : varDef.Name) + "_" + def.Offset.ToString("X2"),
Type = varDef.VariableType,
OriginalVariable = varDef
},
Defs = new List<ByteCode>() { def },
Uses = new List<ByteCode>()
}).ToList();
List<VariableInfo> newVars;
// VB.NET uses the 'init' to allow use of uninitialized variables.
// We do not really care about them too much - if the original variable
// was uninitialized at that point it means that no store was called and
// thus all our new variables must be uninitialized as well.
// So it does not matter which one we load.
bool isPinned = methodDef.Body.Variables[variableIndex].IsPinned;
// If the variable is pinned, use single variable.
// If any of the loads is from "all", use single variable
// If any of the loads is ldloca with a nondeterministic usage pattern, use single variable
if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll || (b.Code == ILCode.Ldloca && !IsDeterministicLdloca(b)))) {
newVars = new List<VariableInfo>(1) { new VariableInfo() {
Variable = new ILVariable() {
Name = "var_" + variableIndex,
Type = isPinned ? ((PinnedType)varType).ElementType : varType,
OriginalVariable = methodDef.Body.Variables[variableIndex]
},
Stores = stores,
Loads = loads
}};
} else {
// Create a new variable for each store
newVars = stores.Where(st =>
{
if (st.Code == ILCode.Stloc || st.Next.Code == ILCode.Initobj) return true;
var storedBy = st.VariablesBefore[variableIndex].StoredBy;
return storedBy.Length == 0 || storedBy[0] == st;
}).Select(st => new VariableInfo() {
Variable = new ILVariable() {
Name = "var_" + variableIndex + "_" + st.Offset.ToString("X2"),
Type = varType,
OriginalVariable = methodDef.Body.Variables[variableIndex]
},
Stores = new List<ByteCode>() {st},
Loads = new List<ByteCode>()
}).ToList();
// VB.NET uses the 'init' to allow use of uninitialized variables.
// We do not really care about them too much - if the original variable
// was uninitialized at that point it means that no store was called and
// thus all our new variables must be uninitialized as well.
// So it does not matter which one we load.
// TODO: We should add explicit initialization so that C# code compiles.
// Remember to handle cases where one path inits the variable, but other does not.
// Add loads to the data structure; merge variables if necessary
foreach(ByteCode load in loads) {
ByteCode[] storedBy = load.VariablesBefore[variableIndex].StoredBy;
if (storedBy.Length == 0) {
// Load which always loads the default ('uninitialized') value
// Create a dummy variable just for this load
newVars.Add(new VariableInfo() {
Variable = new ILVariable() {
Name = "var_" + variableIndex + "_" + load.Offset.ToString("X2") + "_default",
Type = varType,
OriginalVariable = methodDef.Body.Variables[variableIndex]
},
Stores = new List<ByteCode>(),
Loads = new List<ByteCode>() { load }
});
} else if (storedBy.Length == 1) {
VariableInfo newVar = newVars.Single(v => v.Stores.Contains(storedBy[0]));
newVar.Loads.Add(load);
if (load.Code == ILCode.Ldloca) newVar.Stores.Add(load);
} else {
List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Intersect(storedBy).Any()).ToList();
VariableInfo mergedVar = new VariableInfo() {
Variable = mergeVars[0].Variable,
Stores = mergeVars.SelectMany(v => v.Stores).ToList(),
Loads = mergeVars.SelectMany(v => v.Loads).ToList()
};
mergedVar.Loads.Add(load);
if (load.Code == ILCode.Ldloca) mergedVar.Stores.Add(load);
newVars = newVars.Except(mergeVars).ToList();
newVars.Add(mergedVar);
}
}
}
// TODO: We should add explicit initialization so that C# code compiles.
// Remember to handle cases where one path inits the variable, but other does not.
// Set bytecode operands
foreach(VariableInfo newVar in newVars) {
foreach(ByteCode store in newVar.Stores) {
store.Operand = newVar.Variable;
}
foreach(ByteCode load in newVar.Loads) {
load.Operand = newVar.Variable;
// Add loads to the data structure; merge variables if necessary
foreach(ByteCode use in uses) {
ByteCode[] useDefs = use.VariablesBefore[varDef.Index].Definitions;
if (useDefs.Length == 1) {
VariableInfo newVar = newVars.Single(v => v.Defs.Contains(useDefs[0]));
newVar.Uses.Add(use);
} else {
List<VariableInfo> mergeVars = newVars.Where(v => v.Defs.Intersect(useDefs).Any()).ToList();
VariableInfo mergedVar = new VariableInfo() {
Variable = mergeVars[0].Variable,
Defs = mergeVars.SelectMany(v => v.Defs).ToList(),
Uses = mergeVars.SelectMany(v => v.Uses).ToList()
};
mergedVar.Uses.Add(use);
newVars = newVars.Except(mergeVars).ToList();
newVars.Add(mergedVar);
}
}
}
} else {
var variables = methodDef.Body.Variables.Select(v => new ILVariable() { Name = string.IsNullOrEmpty(v.Name) ? "var_" + v.Index : v.Name, Type = v.VariableType, OriginalVariable = v }).ToList();
foreach(ByteCode byteCode in body) {
if (byteCode.Code == ILCode.Ldloc || byteCode.Code == ILCode.Stloc || byteCode.Code == ILCode.Ldloca) {
int index = ((VariableDefinition)byteCode.Operand).Index;
byteCode.Operand = variables[index];
// Set bytecode operands
foreach(VariableInfo newVar in newVars) {
foreach(ByteCode def in newVar.Defs) {
def.Operand = newVar.Variable;
}
foreach(ByteCode use in newVar.Uses) {
use.Operand = newVar.Variable;
}
}
}
@ -824,8 +766,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -824,8 +766,8 @@ namespace ICSharpCode.Decompiler.ILAst
}
// Reference arguments using temporary variables
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length;
for (int i = byteCode.StackBefore.Length - popCount; i < byteCode.StackBefore.Length; i++) {
StackSlot slot = byteCode.StackBefore[i];
expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom));
}

Loading…
Cancel
Save