Browse Source

Add 'ldelem' support

pull/728/head
Daniel Grunwald 11 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
protected internal override TranslatedExpression VisitLdObj(LdObj inst) protected internal override TranslatedExpression VisitLdObj(LdObj inst)
{ {
var target = Translate(inst.Target); 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' // we can deference the managed reference by stripping away the 'ref'
var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression); var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
result = result.ConvertTo(inst.Type, this); result = result.ConvertTo(inst.Type, this);
@ -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) protected internal override TranslatedExpression VisitStObj(StObj inst)
{ {
var target = Translate(inst.Target); var target = Translate(inst.Target);
var value = Translate(inst.Value); var value = Translate(inst.Value);
TranslatedExpression result; 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' // we can deference the managed reference by stripping away the 'ref'
result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression); result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
} else { } else {
@ -510,6 +524,28 @@ namespace ICSharpCode.Decompiler.CSharp
return Assignment(ConvertField(inst.Field).WithoutILInstruction(), Translate(inst.Value)).WithILInstruction(inst); 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) protected internal override TranslatedExpression VisitUnboxAny(UnboxAny inst)
{ {
var arg = Translate(inst.Argument); var arg = Translate(inst.Argument);

3
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

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

18
ICSharpCode.Decompiler/IL/ILReader.cs

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

26
ICSharpCode.Decompiler/IL/Instructions.cs

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

2
ICSharpCode.Decompiler/IL/Instructions.tt

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

Loading…
Cancel
Save