Browse Source

Port ProxyCallReplacer and TextTokenWriter to SRM

pull/1198/head
Siegfried Pammer 7 years ago
parent
commit
a2e27dd7ed
  1. 131
      ICSharpCode.Decompiler/IL/Transforms/ProxyCallReplacer.cs
  2. 48
      ICSharpCode.Decompiler/Output/TextTokenWriter.cs

131
ICSharpCode.Decompiler/IL/Transforms/ProxyCallReplacer.cs

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.IL.Transforms
{
@ -12,69 +12,84 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -12,69 +12,84 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public void Run(ILFunction function, ILTransformContext context)
{
this.context = context;
var module = context.TypeSystem.ModuleDefinition;
var metadata = context.TypeSystem.GetMetadata();
foreach (var inst in function.Descendants.OfType<CallInstruction>()) {
MethodDefinition methodDef = context.TypeSystem.GetCecil(inst.Method) as MethodDefinition;
if (methodDef != null && methodDef.Body != null) {
if (inst.Method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) {
// partially copied from CSharpDecompiler
var specializingTypeSystem = this.context.TypeSystem.GetSpecializingTypeSystem(inst.Method.Substitution);
var ilReader = new ILReader(specializingTypeSystem);
System.Threading.CancellationToken cancellationToken = new System.Threading.CancellationToken();
var proxyFunction = ilReader.ReadIL(methodDef.Body, cancellationToken);
var transformContext = new ILTransformContext(proxyFunction, specializingTypeSystem, this.context.Settings) {
CancellationToken = cancellationToken,
DecompileRun = context.DecompileRun
};
foreach (var transform in CSharp.CSharpDecompiler.GetILTransforms()) {
if (transform.GetType() != typeof(ProxyCallReplacer)) { // don't call itself on itself
cancellationToken.ThrowIfCancellationRequested();
transform.Run(proxyFunction, transformContext);
}
}
if (!(proxyFunction.Body is BlockContainer blockContainer))
return;
if (blockContainer.Blocks.Count != 1)
return;
var block = blockContainer.Blocks[0];
Call call = null;
if (block.Instructions.Count == 1) {
// leave IL_0000 (call Test(ldloc this, ldloc A_1))
if (!block.Instructions[0].MatchLeave(blockContainer, out ILInstruction returnValue))
return;
call = returnValue as Call;
} else if (block.Instructions.Count == 2) {
// call Test(ldloc this, ldloc A_1)
// leave IL_0000(nop)
call = block.Instructions[0] as Call;
if (!block.Instructions[1].MatchLeave(blockContainer, out ILInstruction returnValue))
return;
if (!returnValue.MatchNop())
return;
}
if (call == null) {
return;
}
if (call.Method.IsConstructor)
return;
// check if original arguments are only correct ldloc calls
for (int i = 0; i < call.Arguments.Count; i++) {
var originalArg = call.Arguments[i];
if (!originalArg.MatchLdLoc(out ILVariable var) ||
var.Kind != VariableKind.Parameter ||
var.Index != i - 1) {
return;
}
}
var handle = (MethodDefinitionHandle)inst.Method.MetadataToken;
if (handle.IsNil
|| !IsDefinedInCurrentOrOuterClass(inst.Method, context.Function.Method.DeclaringTypeDefinition)
|| !inst.Method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) {
continue;
}
MethodDefinition methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)inst.Method.MetadataToken);
if (!methodDef.HasBody()) continue;
// partially copied from CSharpDecompiler
var specializingTypeSystem = this.context.TypeSystem.GetSpecializingTypeSystem(inst.Method.Substitution);
var ilReader = new ILReader(specializingTypeSystem);
System.Threading.CancellationToken cancellationToken = new System.Threading.CancellationToken();
var proxyFunction = ilReader.ReadIL(module, handle, module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress), cancellationToken);
var transformContext = new ILTransformContext(proxyFunction, specializingTypeSystem, this.context.Settings) {
CancellationToken = cancellationToken,
DecompileRun = context.DecompileRun
};
foreach (var transform in CSharp.CSharpDecompiler.GetILTransforms()) {
if (transform.GetType() != typeof(ProxyCallReplacer)) { // don't call itself on itself
cancellationToken.ThrowIfCancellationRequested();
transform.Run(proxyFunction, transformContext);
}
}
Call newInst = (Call)call.Clone();
if (!(proxyFunction.Body is BlockContainer blockContainer))
return;
if (blockContainer.Blocks.Count != 1)
return;
var block = blockContainer.Blocks[0];
Call call = null;
if (block.Instructions.Count == 1) {
// leave IL_0000 (call Test(ldloc this, ldloc A_1))
if (!block.Instructions[0].MatchLeave(blockContainer, out ILInstruction returnValue))
return;
call = returnValue as Call;
} else if (block.Instructions.Count == 2) {
// call Test(ldloc this, ldloc A_1)
// leave IL_0000(nop)
call = block.Instructions[0] as Call;
if (!block.Instructions[1].MatchLeave(blockContainer, out ILInstruction returnValue))
return;
if (!returnValue.MatchNop())
return;
}
if (call == null) {
return;
}
if (call.Method.IsConstructor)
return;
newInst.Arguments.ReplaceList(inst.Arguments);
inst.ReplaceWith(newInst);
// check if original arguments are only correct ldloc calls
for (int i = 0; i < call.Arguments.Count; i++) {
var originalArg = call.Arguments[i];
if (!originalArg.MatchLdLoc(out ILVariable var) ||
var.Kind != VariableKind.Parameter ||
var.Index != i - 1) {
return;
}
}
Call newInst = (Call)call.Clone();
newInst.Arguments.ReplaceList(inst.Arguments);
inst.ReplaceWith(newInst);
}
}
static bool IsDefinedInCurrentOrOuterClass(IMethod method, ITypeDefinition declaringTypeDefinition)
{
while (declaringTypeDefinition != null) {
if (method.DeclaringTypeDefinition == declaringTypeDefinition)
return true;
declaringTypeDefinition = declaringTypeDefinition.DeclaringTypeDefinition;
}
return false;
}
}
}

48
ICSharpCode.Decompiler/Output/TextTokenWriter.cs

@ -23,8 +23,8 @@ using ICSharpCode.Decompiler.CSharp; @@ -23,8 +23,8 @@ using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using Mono.Cecil;
namespace ICSharpCode.Decompiler
{
@ -63,18 +63,18 @@ namespace ICSharpCode.Decompiler @@ -63,18 +63,18 @@ namespace ICSharpCode.Decompiler
var definition = GetCurrentDefinition();
if (definition != null) {
MemberReference cecil = SymbolToCecil(definition);
if (cecil != null) {
output.WriteDefinition(identifier.Name, cecil, false);
IMetadataEntity entity = SymbolToMetadata(definition);
if (entity != null) {
output.WriteDefinition(identifier.Name, entity, false);
return;
}
}
var member = GetCurrentMemberReference();
if (member != null) {
MemberReference cecil = SymbolToCecil(member);
if (cecil != null) {
output.WriteReference(identifier.Name, cecil);
IMetadataEntity entity = SymbolToMetadata(member);
if (entity != null) {
output.WriteReference(identifier.Name, entity);
return;
}
}
@ -99,14 +99,24 @@ namespace ICSharpCode.Decompiler @@ -99,14 +99,24 @@ namespace ICSharpCode.Decompiler
output.Write(identifier.Name);
}
MemberReference SymbolToCecil(ISymbol symbol)
IMetadataEntity SymbolToMetadata(ISymbol symbol)
{
if (symbol is IType type) {
return typeSystem.GetCecil(type.GetDefinition());
} else if (symbol is IMember member) {
return typeSystem.GetCecil(member);
} else {
return null;
switch (symbol) {
case IType type:
var definition = type.GetDefinition();
if (definition == null)
return null;
return new TypeDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.TypeDefinitionHandle)definition.MetadataToken);
case IMethod method:
return new MethodDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.MethodDefinitionHandle)method.MetadataToken);
case IProperty property:
return new PropertyDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.PropertyDefinitionHandle)property.MetadataToken);
case IEvent @event:
return new EventDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.EventDefinitionHandle)@event.MetadataToken);
case IField field:
return new FieldDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.FieldDefinitionHandle)field.MetadataToken);
default:
return null;
}
}
@ -200,9 +210,9 @@ namespace ICSharpCode.Decompiler @@ -200,9 +210,9 @@ namespace ICSharpCode.Decompiler
//To make reference for 'this' and 'base' keywords in the ClassName():this() expression
if (role == ConstructorInitializer.ThisKeywordRole || role == ConstructorInitializer.BaseKeywordRole) {
if (nodeStack.Peek() is ConstructorInitializer initializer && initializer.GetSymbol() is IMember member) {
var cecil = typeSystem.GetCecil(member);
if (cecil != null) {
output.WriteReference(keyword, cecil);
var entity = SymbolToMetadata(member);
if (entity != null) {
output.WriteReference(keyword, entity);
return;
}
}
@ -235,7 +245,7 @@ namespace ICSharpCode.Decompiler @@ -235,7 +245,7 @@ namespace ICSharpCode.Decompiler
break;
default:
// Attach member reference to token only if there's no identifier in the current node.
var member = SymbolToCecil(GetCurrentMemberReference());
var member = SymbolToMetadata(GetCurrentMemberReference());
var node = nodeStack.Peek();
if (member != null && node.GetChildByRole(Roles.Identifier).IsNull)
output.WriteReference(token, member);
@ -349,7 +359,7 @@ namespace ICSharpCode.Decompiler @@ -349,7 +359,7 @@ namespace ICSharpCode.Decompiler
symbol = nodeStack.Peek().GetSymbol();
}
if (symbol == null) goto default;
output.WriteReference(type, SymbolToCecil(symbol));
output.WriteReference(type, SymbolToMetadata(symbol));
break;
default:
output.Write(type);

Loading…
Cancel
Save