Browse Source

Add 'ldelem' support

pull/728/head
Daniel Grunwald 10 years ago
parent
commit
8b2176d81a
  1. 40
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 3
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  3. 18
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 26
      ICSharpCode.Decompiler/IL/Instructions.cs
  5. 2
      ICSharpCode.Decompiler/IL/Instructions.tt

40
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -457,7 +457,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -457,7 +457,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdObj(LdObj inst)
{
var target = Translate(inst.Target);
if (target.Type.Equals(new ByReferenceType(inst.Type)) && target.Expression is DirectionExpression) {
if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can deference the managed reference by stripping away the 'ref'
var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
result = result.ConvertTo(inst.Type, this);
@ -472,12 +472,26 @@ namespace ICSharpCode.Decompiler.CSharp @@ -472,12 +472,26 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
bool IsCompatibleTypeForMemoryAccess(IType pointerType, IType accessType)
{
IType memoryType;
if (pointerType is PointerType)
memoryType = ((PointerType)pointerType).ElementType;
else if (pointerType is ByReferenceType)
memoryType = ((ByReferenceType)pointerType).ElementType;
else
return false;
if (memoryType.IsReferenceType == true && accessType.IsReferenceType == true)
return true;
return memoryType.Equals(accessType);
}
protected internal override TranslatedExpression VisitStObj(StObj inst)
{
var target = Translate(inst.Target);
var value = Translate(inst.Value);
TranslatedExpression result;
if (target.Type.Equals(new ByReferenceType(inst.Type)) && target.Expression is DirectionExpression) {
if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can deference the managed reference by stripping away the 'ref'
result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
} else {
@ -510,6 +524,28 @@ namespace ICSharpCode.Decompiler.CSharp @@ -510,6 +524,28 @@ namespace ICSharpCode.Decompiler.CSharp
return Assignment(ConvertField(inst.Field).WithoutILInstruction(), Translate(inst.Value)).WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitLdLen(LdLen inst)
{
TranslatedExpression arrayExpr = Translate(inst.Array);
// TODO: what if arrayExpr is not an array type?
var lenExpr = arrayExpr.Expression.Member("LongLength")
.WithILInstruction(inst)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Int64)));
return lenExpr.ConvertTo(compilation.FindType(KnownTypeCode.IntPtr), this);
}
protected internal override TranslatedExpression VisitLdElema(LdElema inst)
{
TranslatedExpression arrayExpr = Translate(inst.Array);
var arrayType = arrayExpr.Type as ArrayType;
// TODO: what if arrayExpr is not an array type?
// TODO: what if the type of the ldelema instruction does not match the array type?
TranslatedExpression expr = new IndexerExpression(arrayExpr, Translate(inst.Index))
.WithILInstruction(inst).WithRR(new ResolveResult(arrayType != null ? arrayType.ElementType : SpecialType.UnknownType));
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ResolveResult(new ByReferenceType(expr.Type)));
}
protected internal override TranslatedExpression VisitUnboxAny(UnboxAny inst)
{
var arg = Translate(inst.Argument);

3
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -171,7 +171,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -171,7 +171,8 @@ namespace ICSharpCode.Decompiler.CSharp
foreach (var inst in block.Instructions) {
blockStatement.Add(Convert(inst));
}
blockStatement.Add(Convert(block.FinalInstruction));
if (block.FinalInstruction.OpCode != OpCode.Nop)
blockStatement.Add(Convert(block.FinalInstruction));
return blockStatement;
}

18
ICSharpCode.Decompiler/IL/ILReader.cs

@ -601,18 +601,29 @@ namespace ICSharpCode.Decompiler.IL @@ -601,18 +601,29 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Isinst:
return new IsInst(Pop(), ReadAndDecodeTypeReference());
case ILOpCode.Ldelem:
return LdElem(index: Pop(), array: Pop(), type: ReadAndDecodeTypeReference());
case ILOpCode.Ldelem_I1:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.SByte));
case ILOpCode.Ldelem_I2:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int16));
case ILOpCode.Ldelem_I4:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int32));
case ILOpCode.Ldelem_I8:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int64));
case ILOpCode.Ldelem_U1:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Byte));
case ILOpCode.Ldelem_U2:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.UInt16));
case ILOpCode.Ldelem_U4:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.UInt32));
case ILOpCode.Ldelem_R4:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Single));
case ILOpCode.Ldelem_R8:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Double));
case ILOpCode.Ldelem_I:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.IntPtr));
case ILOpCode.Ldelem_Ref:
throw new NotImplementedException();
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Object));
case ILOpCode.Ldelema:
return new LdElema(index: Pop(), array: Pop(), type: ReadAndDecodeTypeReference());
case ILOpCode.Ldfld:
@ -731,6 +742,11 @@ namespace ICSharpCode.Decompiler.IL @@ -731,6 +742,11 @@ namespace ICSharpCode.Decompiler.IL
{
return new Void(new StLoc(Pop(), localVariables[v]));
}
private ILInstruction LdElem(ILInstruction array, ILInstruction index, IType type)
{
return new LdObj(new LdElema(array, index, type), type);
}
private ILInstruction DecodeConstrainedCall()
{

26
ICSharpCode.Decompiler/IL/Instructions.cs

@ -2449,16 +2449,16 @@ namespace ICSharpCode.Decompiler.IL @@ -2449,16 +2449,16 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns the length of an array as 'native unsigned int'.</summary>
public sealed partial class LdLen : ILInstruction
{
public LdLen(ILInstruction target) : base(OpCode.LdLen)
public LdLen(ILInstruction array) : base(OpCode.LdLen)
{
this.Target = target;
this.Array = array;
}
ILInstruction target;
public ILInstruction Target {
get { return this.target; }
ILInstruction array;
public ILInstruction Array {
get { return this.array; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.target, value, 0);
SetChildInstruction(ref this.array, value, 0);
}
}
protected sealed override int GetChildCount()
@ -2469,7 +2469,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2469,7 +2469,7 @@ namespace ICSharpCode.Decompiler.IL
{
switch (index) {
case 0:
return this.target;
return this.array;
default:
throw new IndexOutOfRangeException();
}
@ -2478,7 +2478,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2478,7 +2478,7 @@ namespace ICSharpCode.Decompiler.IL
{
switch (index) {
case 0:
this.Target = value;
this.Array = value;
break;
default:
throw new IndexOutOfRangeException();
@ -2487,28 +2487,28 @@ namespace ICSharpCode.Decompiler.IL @@ -2487,28 +2487,28 @@ namespace ICSharpCode.Decompiler.IL
public sealed override ILInstruction Clone()
{
var clone = (LdLen)ShallowClone();
clone.Target = this.target.Clone();
clone.Array = this.array.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
this.Array = this.array.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
Array.TransformStackIntoVariables(state);
}
public override StackType ResultType { get { return StackType.I; } }
protected override InstructionFlags ComputeFlags()
{
return target.Flags | InstructionFlags.MayThrow;
return array.Flags | InstructionFlags.MayThrow;
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
this.target.WriteTo(output);
this.array.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -182,7 +182,7 @@ @@ -182,7 +182,7 @@
CustomClassName("SizeOf"), NoArguments, HasTypeOperand, ResultType("I4")),
new OpCode("ldlen", "Returns the length of an array as 'native unsigned int'.",
CustomClassName("LdLen"), CustomArguments("target"), MayThrow, ResultType("I")),
CustomClassName("LdLen"), CustomArguments("array"), MayThrow, ResultType("I")),
new OpCode("ldelema", "Load address of array element.",
CustomClassName("LdElema"), CustomArguments("array", "index"), HasTypeOperand,
MayThrow, ResultType("Ref"), SupportsReadonlyPrefix),

Loading…
Cancel
Save