e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
1043 lines
42 KiB
C#
1043 lines
42 KiB
C#
/*
|
|
Copyright (C) 2012 Jeroen Frijters
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
Jeroen Frijters
|
|
jeroen@frijters.net
|
|
|
|
*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using IKVM.Reflection;
|
|
using IKVM.Reflection.Emit;
|
|
using Type = IKVM.Reflection.Type;
|
|
using System.Diagnostics;
|
|
|
|
namespace Ildasm
|
|
{
|
|
sealed partial class Disassembler : IComparer<ExceptionHandlingClause>
|
|
{
|
|
static readonly OpCode[] opcodes = GetOpCodes();
|
|
|
|
static OpCode[] GetOpCodes()
|
|
{
|
|
OpCode[] opcodes = new OpCode[768];
|
|
foreach (System.Reflection.FieldInfo field in typeof(OpCodes).GetFields())
|
|
{
|
|
OpCode opc = (OpCode)field.GetValue(null);
|
|
opcodes[opc.Value + 512] = opc;
|
|
}
|
|
return opcodes;
|
|
}
|
|
|
|
void WriteIL(LineWriter lw, MethodBase mb, MethodBody body, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
ParameterInfo[] parameters = mb.GetParameters();
|
|
int level = lw.Column;
|
|
byte[] code = body.GetILAsByteArray();
|
|
lw.GoToColumn(level);
|
|
lw.WriteLine("// Code size {0} (0x{0:x})", code.Length);
|
|
lw.GoToColumn(level);
|
|
lw.WriteLine(".maxstack {0}", body.MaxStackSize);
|
|
|
|
IList<LocalVariableInfo> locals = body.LocalVariables;
|
|
if (locals.Count != 0)
|
|
{
|
|
lw.GoToColumn(level);
|
|
lw.Write(".locals ");
|
|
if (body.InitLocals)
|
|
{
|
|
lw.Write("init ");
|
|
}
|
|
lw.Write("(");
|
|
bool first = true;
|
|
foreach (var local in locals)
|
|
{
|
|
if (!first)
|
|
{
|
|
lw.WriteLine(",");
|
|
lw.GoToColumn(level + 9);
|
|
}
|
|
first = false;
|
|
WriteSignatureType(lw, local.LocalType, TypeLocation.Local);
|
|
if (local.IsPinned)
|
|
{
|
|
lw.Write(" pinned");
|
|
}
|
|
WriteCustomModifiers(lw, local.__GetCustomModifiers());
|
|
lw.Write(" V_{0}", local.LocalIndex);
|
|
}
|
|
lw.WriteLine(")");
|
|
}
|
|
|
|
var exceptions = new List<ExceptionHandlingClause>();
|
|
var exceptions2 = new List<ExceptionHandlingClause>();
|
|
SortExceptions(body.ExceptionHandlingClauses, exceptions, exceptions2);
|
|
|
|
Stack<ExceptionHandlingClause> activeExceptions = new Stack<ExceptionHandlingClause>();
|
|
ExceptionHandlingClause currentException = null;
|
|
bool extraNewLine = false;
|
|
int nextFlatException = 0;
|
|
int nextException = 0;
|
|
bool handler = false;
|
|
int pos = 0;
|
|
while (pos < code.Length)
|
|
{
|
|
if (extraNewLine)
|
|
{
|
|
lw.WriteLine();
|
|
extraNewLine = false;
|
|
}
|
|
if (currentException != null)
|
|
{
|
|
if (currentException.HandlerOffset == pos)
|
|
{
|
|
switch (currentException.Flags)
|
|
{
|
|
case ExceptionHandlingClauseOptions.Clause:
|
|
lw.GoToColumn(level - 2);
|
|
if (currentException.TryOffset + currentException.TryLength == pos)
|
|
{
|
|
lw.WriteLine("} // end .try");
|
|
}
|
|
else
|
|
{
|
|
lw.WriteLine("} // end handler");
|
|
}
|
|
lw.GoToColumn(level - 2);
|
|
lw.Write("catch ");
|
|
if (currentException.CatchType.__IsMissing || !currentException.CatchType.IsGenericType)
|
|
{
|
|
WriteTypeDefOrRef(lw, currentException.CatchType);
|
|
}
|
|
else
|
|
{
|
|
WriteSignatureType(lw, currentException.CatchType);
|
|
}
|
|
lw.WriteLine(" ");
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("{");
|
|
handler = true;
|
|
break;
|
|
case ExceptionHandlingClauseOptions.Finally:
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("} // end .try");
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("finally");
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("{");
|
|
break;
|
|
case ExceptionHandlingClauseOptions.Fault:
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("} // end .try");
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("fault");
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("{");
|
|
break;
|
|
case ExceptionHandlingClauseOptions.Filter:
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("} // end filter");
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("{ // handler");
|
|
handler = true;
|
|
break;
|
|
default:
|
|
throw new IKVM.Reflection.BadImageFormatException();
|
|
}
|
|
}
|
|
else if (currentException.FilterOffset == pos && pos != 0)
|
|
{
|
|
lw.GoToColumn(level - 2);
|
|
if (handler)
|
|
{
|
|
lw.WriteLine("} // end handler");
|
|
}
|
|
else
|
|
{
|
|
lw.WriteLine("} // end .try");
|
|
}
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("filter");
|
|
lw.GoToColumn(level - 2);
|
|
lw.WriteLine("{");
|
|
}
|
|
}
|
|
while (nextException < exceptions.Count
|
|
&& exceptions[nextException].TryOffset == pos)
|
|
{
|
|
activeExceptions.Push(currentException);
|
|
ExceptionHandlingClause prevException = currentException;
|
|
currentException = exceptions[nextException++];
|
|
if (prevException != null && currentException.TryOffset == prevException.TryOffset && currentException.TryLength == prevException.TryLength)
|
|
{
|
|
// another handler for the same block
|
|
continue;
|
|
}
|
|
handler = false;
|
|
lw.GoToColumn(level);
|
|
lw.WriteLine(".try");
|
|
lw.GoToColumn(level);
|
|
lw.WriteLine("{");
|
|
level += 2;
|
|
}
|
|
lw.GoToColumn(level);
|
|
int currPos = pos;
|
|
lw.Write("IL_{0:x4}: ", pos);
|
|
int level1 = lw.Column;
|
|
short opcodeValue = code[pos++];
|
|
if (opcodeValue == 0xFE)
|
|
{
|
|
opcodeValue = (short)(0xFE00 + code[pos++]);
|
|
}
|
|
OpCode opcode = opcodes[opcodeValue + 512];
|
|
lw.Write("{0}", opcode.Name);
|
|
switch (opcode.OperandType)
|
|
{
|
|
case OperandType.InlineNone:
|
|
break;
|
|
case OperandType.InlineBrTarget:
|
|
lw.GoToColumn(level1 + 11);
|
|
lw.Write("IL_{0:x4}", ReadInt32(code, ref pos) + pos);
|
|
break;
|
|
case OperandType.ShortInlineBrTarget:
|
|
lw.GoToColumn(level1 + 11);
|
|
lw.Write("IL_{0:x4}", (sbyte)code[pos++] + pos);
|
|
break;
|
|
case OperandType.InlineMethod:
|
|
{
|
|
lw.GoToColumn(level1 + 11);
|
|
int token = ReadInt32(code, ref pos);
|
|
MethodBase methodOrConstructor = ResolveMethod(token, genericTypeArguments, genericMethodArguments);
|
|
if ((methodOrConstructor.CallingConvention & CallingConventions.Any) == CallingConventions.VarArgs)
|
|
{
|
|
CustomModifiers[] customModifiers;
|
|
Type[] optionalParameterTypes = ResolveOptionalParameterTypes(token, genericTypeArguments, genericMethodArguments, out customModifiers);
|
|
WriteInlineMethod(lw, methodOrConstructor, optionalParameterTypes, customModifiers);
|
|
}
|
|
else
|
|
{
|
|
WriteInlineMethod(lw, methodOrConstructor, Type.EmptyTypes, null);
|
|
}
|
|
}
|
|
break;
|
|
case OperandType.InlineField:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteInlineField(lw, ResolveField(ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments));
|
|
break;
|
|
case OperandType.InlineI:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteInlineI(lw, ReadInt32(code, ref pos));
|
|
break;
|
|
case OperandType.InlineI8:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteInlineI8(lw, ReadInt64(code, ref pos));
|
|
break;
|
|
case OperandType.ShortInlineI:
|
|
lw.GoToColumn(level1 + 11);
|
|
lw.Write("{0}", (sbyte)code[pos++]);
|
|
break;
|
|
case OperandType.InlineR:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteInlineR(lw, ReadDouble(code, ref pos), false);
|
|
break;
|
|
case OperandType.ShortInlineR:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteShortInlineR(lw, ReadSingle(code, ref pos), false);
|
|
break;
|
|
case OperandType.InlineType:
|
|
if (opcode == OpCodes.Constrained)
|
|
{
|
|
// "constrained." is too long to fit in the opcode column
|
|
lw.Write(" ");
|
|
}
|
|
else
|
|
{
|
|
lw.GoToColumn(level1 + 11);
|
|
}
|
|
WriteInlineType(lw, ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments);
|
|
break;
|
|
case OperandType.InlineTok:
|
|
{
|
|
int token = ReadInt32(code, ref pos);
|
|
switch (token >> 24)
|
|
{
|
|
case 0x01:
|
|
case 0x02:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteTypeDefOrRef(lw, ResolveType(token, genericTypeArguments, genericMethodArguments));
|
|
break;
|
|
case 0x1B:
|
|
{
|
|
Type type = ResolveType(token, genericTypeArguments, genericMethodArguments);
|
|
if (type.IsGenericTypeDefinition)
|
|
{
|
|
// HACK because typeof(Foo<>).MakeGenericType(typeof(Foo<>).GetGenericArguments()) == typeof(Foo<>)
|
|
// we need to inflate the builder here
|
|
type = type.MakeGenericType(type.GetGenericArguments());
|
|
}
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteSignatureType(lw, type);
|
|
break;
|
|
}
|
|
case 0x04:
|
|
case 0x06:
|
|
case 0x0A:
|
|
case 0x2B:
|
|
{
|
|
MemberInfo member = ResolveMember(token, genericTypeArguments, genericMethodArguments);
|
|
if (member is FieldInfo)
|
|
{
|
|
lw.GoToColumn(level1 + 11);
|
|
lw.Write("field ");
|
|
WriteInlineField(lw, (FieldInfo)member);
|
|
}
|
|
else
|
|
{
|
|
var mb1 = (MethodBase)member;
|
|
lw.GoToColumn(level1 + 11);
|
|
if (mb1.__IsMissing || !mb1.IsGenericMethod || compat != CompatLevel.V20)
|
|
{
|
|
lw.Write("method ");
|
|
}
|
|
WriteInlineMethod(lw, mb1, Type.EmptyTypes, null);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
throw new NotImplementedException("token type = " + (token >> 24));
|
|
}
|
|
}
|
|
break;
|
|
case OperandType.InlineVar:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteInlineVar(lw, mb, opcode, parameters, ReadInt16(code, ref pos));
|
|
break;
|
|
case OperandType.ShortInlineVar:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteInlineVar(lw, mb, opcode, parameters, code[pos++]);
|
|
break;
|
|
case OperandType.InlineString:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteInlineString(lw, module.ResolveString(ReadInt32(code, ref pos)), level);
|
|
break;
|
|
case OperandType.InlineSwitch:
|
|
{
|
|
lw.GoToColumn(level1 + 11);
|
|
lw.WriteLine("( ");
|
|
int count = ReadInt32(code, ref pos);
|
|
int offset = pos + 4 * count;
|
|
for (int i = 0; i < count - 1; i++)
|
|
{
|
|
lw.GoToColumn(level + 22);
|
|
lw.WriteLine("IL_{0:x4},", offset + ReadInt32(code, ref pos));
|
|
}
|
|
lw.GoToColumn(level + 22);
|
|
lw.Write("IL_{0:x4})", offset + ReadInt32(code, ref pos));
|
|
}
|
|
break;
|
|
case OperandType.InlineSig:
|
|
lw.GoToColumn(level1 + 11);
|
|
WriteStandAloneMethodSig(lw, module.__ResolveStandAloneMethodSig(ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments), false, false);
|
|
break;
|
|
default:
|
|
throw new InvalidOperationException();
|
|
}
|
|
lw.WriteLine();
|
|
|
|
if (opcode == OpCodes.Leave || opcode == OpCodes.Leave_S)
|
|
{
|
|
if (pos < code.Length)
|
|
{
|
|
lw.WriteLine();
|
|
}
|
|
}
|
|
else if (opcode != OpCodes.Switch && opcode != OpCodes.Rethrow && opcode != OpCodes.Endfilter && opcode != OpCodes.Endfinally)
|
|
{
|
|
switch (opcode.FlowControl)
|
|
{
|
|
case FlowControl.Branch:
|
|
case FlowControl.Cond_Branch:
|
|
case FlowControl.Throw:
|
|
case FlowControl.Return:
|
|
extraNewLine = true;
|
|
break;
|
|
}
|
|
}
|
|
if (nextFlatException < exceptions2.Count && exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength == currPos)
|
|
{
|
|
if (extraNewLine && pos < code.Length)
|
|
{
|
|
extraNewLine = false;
|
|
lw.WriteLine();
|
|
}
|
|
lw.GoToColumn(level);
|
|
if (exceptions2[nextFlatException].FilterOffset == 0)
|
|
{
|
|
lw.Write(".try IL_{0:x4} to IL_{1:x4} catch ", exceptions2[nextFlatException].TryOffset, exceptions2[nextFlatException].TryOffset + exceptions2[nextFlatException].TryLength);
|
|
if (exceptions2[nextFlatException].CatchType.__IsMissing || !exceptions2[nextFlatException].CatchType.IsGenericType)
|
|
{
|
|
WriteTypeDefOrRef(lw, exceptions2[nextFlatException].CatchType);
|
|
}
|
|
else
|
|
{
|
|
WriteSignatureType(lw, exceptions2[nextFlatException].CatchType);
|
|
}
|
|
lw.WriteLine(" handler IL_{0:x4} to IL_{1:x4}", exceptions2[nextFlatException].HandlerOffset, exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength);
|
|
}
|
|
else
|
|
{
|
|
lw.WriteLine(".try IL_{0:x4} to IL_{1:x4} filter IL_{2:x4} handler IL_{3:x4} to IL_{4:x4}",
|
|
exceptions2[nextFlatException].TryOffset, exceptions2[nextFlatException].TryOffset + exceptions2[nextFlatException].TryLength,
|
|
exceptions2[nextFlatException].FilterOffset,
|
|
exceptions2[nextFlatException].HandlerOffset, exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength);
|
|
}
|
|
nextFlatException++;
|
|
}
|
|
|
|
while (currentException != null && currentException.HandlerOffset + currentException.HandlerLength == pos)
|
|
{
|
|
ExceptionHandlingClause prevException = currentException;
|
|
currentException = activeExceptions.Pop();
|
|
if (currentException == null || currentException.TryOffset != prevException.TryOffset || currentException.TryLength != prevException.TryLength)
|
|
{
|
|
if (extraNewLine && pos < code.Length)
|
|
{
|
|
extraNewLine = false;
|
|
lw.WriteLine();
|
|
}
|
|
level -= 2;
|
|
lw.GoToColumn(level);
|
|
lw.WriteLine("} // end handler");
|
|
handler = false;
|
|
}
|
|
else
|
|
{
|
|
handler = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WriteInlineVar(LineWriter lw, MethodBase mb, OpCode opcode, ParameterInfo[] parameters, int index)
|
|
{
|
|
if (opcode == OpCodes.Ldarg_S
|
|
|| opcode == OpCodes.Starg_S
|
|
|| opcode == OpCodes.Ldarga_S
|
|
|| opcode == OpCodes.Ldarg
|
|
|| opcode == OpCodes.Starg
|
|
|| opcode == OpCodes.Ldarga)
|
|
{
|
|
ParameterInfo param = mb.IsStatic ? parameters[index] : index == 0 ? null : parameters[index - 1];
|
|
if (param == null)
|
|
{
|
|
// this
|
|
lw.Write("0");
|
|
}
|
|
else if (param.Name == null)
|
|
{
|
|
lw.Write("A_{0}", index);
|
|
}
|
|
else
|
|
{
|
|
lw.Write("{0}", QuoteIdentifier(param.Name));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lw.Write("V_{0}", index);
|
|
}
|
|
}
|
|
|
|
static int FloatToInt32Bits(float v)
|
|
{
|
|
return IKVM.Reflection.Reader.SingleConverter.SingleToInt32Bits(v);
|
|
}
|
|
|
|
string ToString(float value, bool field)
|
|
{
|
|
if (value == 0 && !field)
|
|
{
|
|
return FloatToInt32Bits(value) < 0
|
|
? "-0.0"
|
|
: "0.0";
|
|
}
|
|
else if (compat != CompatLevel.None)
|
|
{
|
|
byte[] buf = new byte[50];
|
|
_gcvt(value, 8, buf);
|
|
string str = Encoding.ASCII.GetString(buf, 0, Array.IndexOf(buf, (byte)0));
|
|
float v2;
|
|
if (Single.TryParse(str, out v2) && FloatToInt32Bits(value) == FloatToInt32Bits(v2))
|
|
{
|
|
return str;
|
|
}
|
|
else
|
|
{
|
|
if (field)
|
|
{
|
|
return String.Format("0x{0:X}", FloatToInt32Bits(value));
|
|
}
|
|
else
|
|
{
|
|
byte[] buf2 = BitConverter.GetBytes(value);
|
|
return String.Format("({0:X2} {1:X2} {2:X2} {3:X2})", buf2[0], buf2[1], buf2[2], buf2[3]);
|
|
}
|
|
}
|
|
}
|
|
else if (Single.IsInfinity(value) || Single.IsNaN(value))
|
|
{
|
|
if (field)
|
|
{
|
|
return String.Format("0x{0:X}", FloatToInt32Bits(value));
|
|
}
|
|
else
|
|
{
|
|
byte[] buf = BitConverter.GetBytes(value);
|
|
return String.Format("({0:X2} {1:X2} {2:X2} {3:X2})", buf[0], buf[1], buf[2], buf[3]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return String.Format("{0:R}", value);
|
|
}
|
|
}
|
|
|
|
void WriteShortInlineR(LineWriter lw, float value, bool field)
|
|
{
|
|
lw.Write(ToString(value, field));
|
|
}
|
|
|
|
[System.Runtime.InteropServices.DllImport("msvcrt.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
|
|
static extern IntPtr _gcvt(double value, int digits, byte[] buffer);
|
|
|
|
string ToString(double value, bool field)
|
|
{
|
|
if (value == 0 && !field)
|
|
{
|
|
return BitConverter.DoubleToInt64Bits(value) < 0
|
|
? "-0.0"
|
|
: "0.0";
|
|
}
|
|
else if (compat != CompatLevel.None)
|
|
{
|
|
byte[] buf = new byte[50];
|
|
_gcvt(value, 17, buf);
|
|
string str = Encoding.ASCII.GetString(buf, 0, Array.IndexOf(buf, (byte)0));
|
|
double v2;
|
|
if (Double.TryParse(str, out v2) && BitConverter.DoubleToInt64Bits(value) == BitConverter.DoubleToInt64Bits(v2))
|
|
{
|
|
return str;
|
|
}
|
|
else
|
|
{
|
|
if (field)
|
|
{
|
|
return String.Format("0x{0:X}", BitConverter.DoubleToInt64Bits(value));
|
|
}
|
|
else
|
|
{
|
|
byte[] buf2 = BitConverter.GetBytes(value);
|
|
return String.Format("({0:X2} {1:X2} {2:X2} {3:X2} {4:X2} {5:X2} {6:X2} {7:X2})", buf2[0], buf2[1], buf2[2], buf2[3], buf2[4], buf2[5], buf2[6], buf2[7]);
|
|
}
|
|
}
|
|
}
|
|
else if (Double.IsInfinity(value) || Double.IsNaN(value))
|
|
{
|
|
if (field)
|
|
{
|
|
return String.Format("0x{0:X}", BitConverter.DoubleToInt64Bits(value));
|
|
}
|
|
else
|
|
{
|
|
byte[] buf = BitConverter.GetBytes(value);
|
|
return String.Format("({0:X2} {1:X2} {2:X2} {3:X2} {4:X2} {5:X2} {6:X2} {7:X2})", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return String.Format("{0:R}", value.ToString("R"));
|
|
}
|
|
}
|
|
|
|
void WriteInlineR(LineWriter lw, double value, bool field)
|
|
{
|
|
lw.Write(ToString(value, field));
|
|
}
|
|
|
|
void WriteInlineString(LineWriter lw, string str, int level)
|
|
{
|
|
int initial = 44 - lw.Column + level;
|
|
int pos = 44;
|
|
StringBuilder sb = new StringBuilder(str.Length + 10);
|
|
int backslashes = 0;
|
|
for (int i = 0; i < str.Length; i++)
|
|
{
|
|
char c = str[i];
|
|
if (i < str.Length - 2 && ((pos == 94 && pos - initial != backslashes) || pos > 94))
|
|
{
|
|
if (pos - initial == backslashes)
|
|
{
|
|
sb.Append('\\', backslashes * 2);
|
|
backslashes = 0;
|
|
}
|
|
pos = initial + backslashes;
|
|
sb.Append("\"\r\n");
|
|
sb.Append(' ', level);
|
|
sb.Append("+ \"");
|
|
}
|
|
if (c == '\\')
|
|
{
|
|
backslashes++;
|
|
}
|
|
else if (backslashes != 0)
|
|
{
|
|
sb.Append('\\', backslashes * 2);
|
|
backslashes = 0;
|
|
}
|
|
if (c < 32)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '\r':
|
|
sb.Append("\\r");
|
|
break;
|
|
case '\n':
|
|
sb.Append("\\n");
|
|
break;
|
|
case '\t':
|
|
sb.Append("\\t");
|
|
break;
|
|
default:
|
|
lw.Write("bytearray (");
|
|
WriteBytes(lw, GetBytes(str), false);
|
|
return;
|
|
}
|
|
}
|
|
else if (c > 126)
|
|
{
|
|
lw.Write("bytearray (");
|
|
WriteBytes(lw, GetBytes(str), false);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
switch (c)
|
|
{
|
|
case '"':
|
|
sb.Append("\\\"");
|
|
break;
|
|
case '?':
|
|
sb.Append("\\?");
|
|
break;
|
|
case '\\':
|
|
break;
|
|
default:
|
|
sb.Append(c);
|
|
break;
|
|
}
|
|
}
|
|
pos++;
|
|
}
|
|
sb.Append('\\', backslashes * 2);
|
|
lw.Write("\"{0}\"", sb);
|
|
}
|
|
|
|
static byte[] GetBytes(string str)
|
|
{
|
|
byte[] buf = new byte[str.Length * 2];
|
|
for (int i = 0; i < str.Length; i++)
|
|
{
|
|
char ch = str[i];
|
|
buf[i * 2 + 0] = (byte)(ch >> 0);
|
|
buf[i * 2 + 1] = (byte)(ch >> 8);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
void WriteInlineI(LineWriter lw, int value)
|
|
{
|
|
if (value >= 128 || value < 128)
|
|
{
|
|
lw.Write("0x{0:x}", value);
|
|
}
|
|
else
|
|
{
|
|
lw.Write("{0}", value);
|
|
}
|
|
}
|
|
|
|
void WriteInlineI8(LineWriter lw, long value)
|
|
{
|
|
if (value >= 128 || value < 128)
|
|
{
|
|
lw.Write("0x{0:x}", value);
|
|
}
|
|
else
|
|
{
|
|
lw.Write("{0}", value);
|
|
}
|
|
}
|
|
|
|
static bool IsArrayOfGenericParameter(Type type)
|
|
{
|
|
if (type != null && type.IsArray)
|
|
{
|
|
while (type.IsArray)
|
|
{
|
|
type = type.GetElementType();
|
|
}
|
|
return !type.__IsMissing && type.IsGenericParameter;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void WriteInlineMethod(LineWriter lw, MethodBase mb, Type[] optionalParameterTypes, CustomModifiers[] customModifiers, MethodInfo methodimpl = null)
|
|
{
|
|
WriteCallingConvention(lw, mb.CallingConvention);
|
|
if (mb is ConstructorInfo)
|
|
{
|
|
WriteSignatureType(lw, ((ConstructorInfo)mb).__ReturnParameter.ParameterType);
|
|
WriteCustomModifiers(lw, ((ConstructorInfo)mb).__ReturnParameter.__GetCustomModifiers());
|
|
lw.Write(" ");
|
|
}
|
|
else
|
|
{
|
|
WriteSignatureType(lw, ((MethodInfo)mb.__GetMethodOnTypeDefinition()).ReturnType, IsArrayOfGenericParameter(mb.DeclaringType) ? TypeLocation.General : TypeLocation.MemberRefNoWrap);
|
|
WriteCustomModifiers(lw, ((MethodInfo)mb).ReturnParameter.__GetCustomModifiers());
|
|
lw.Write(" ");
|
|
}
|
|
bool generic;
|
|
if (mb.DeclaringType == null)
|
|
{
|
|
generic = false;
|
|
lw.Write("{0}", QuoteIdentifier(GetMethodName(mb)));
|
|
}
|
|
else
|
|
{
|
|
if (mb.DeclaringType.__IsMissing || !mb.DeclaringType.IsGenericType)
|
|
{
|
|
generic = false;
|
|
WriteTypeDefOrRef(lw, mb.DeclaringType);
|
|
}
|
|
else
|
|
{
|
|
generic = true;
|
|
WriteSignatureType(lw, mb.DeclaringType, mb.IsGenericMethod ? TypeLocation.DeclaringType : TypeLocation.General);
|
|
}
|
|
lw.Write("::{0}", QuoteIdentifier(GetMethodName(mb)));
|
|
}
|
|
if (mb.IsGenericMethod)
|
|
{
|
|
if (methodimpl != null)
|
|
{
|
|
lw.Write("<[{0}]>", mb.GetGenericArguments().Length);
|
|
}
|
|
else
|
|
{
|
|
lw.Write("<");
|
|
string sep = "";
|
|
foreach (var par in mb.GetGenericArguments())
|
|
{
|
|
lw.Write(sep);
|
|
sep = ",";
|
|
WriteSignatureType(lw, par, generic ? TypeLocation.MemberRefNoWrap : TypeLocation.MethodGenericParameter);
|
|
}
|
|
lw.Write(">");
|
|
}
|
|
}
|
|
if (mb.IsGenericMethodDefinition && methodimpl != null)
|
|
{
|
|
mb = ((MethodInfo)mb).MakeGenericMethod(methodimpl.GetGenericArguments());
|
|
}
|
|
else
|
|
{
|
|
mb = mb.__GetMethodOnTypeDefinition();
|
|
}
|
|
lw.Write("(");
|
|
TypeLocation loc = (methodimpl != null && mb.IsGenericMethod)
|
|
? TypeLocation.GenericMethodImpl
|
|
: IsArrayOfGenericParameter(mb.DeclaringType) ? TypeLocation.General : TypeLocation.MemberRefNoWrap;
|
|
int level = lw.Column;
|
|
if (compat != CompatLevel.None && loc == TypeLocation.GenericMethodImpl)
|
|
{
|
|
// ildasm doesn't take the length of the arity ("<[1]>") into account
|
|
level -= 5 + (int)Math.Log10(mb.GetGenericArguments().Length);
|
|
}
|
|
bool first = true;
|
|
bool noLineWrapCompat = false;
|
|
foreach (var parameter in mb.GetParameters())
|
|
{
|
|
if (!first)
|
|
{
|
|
if (noLineWrapCompat)
|
|
{
|
|
lw.Write(",");
|
|
}
|
|
else
|
|
{
|
|
if (loc == TypeLocation.MemberRefNoWrap)
|
|
{
|
|
loc = TypeLocation.MemberRef;
|
|
}
|
|
lw.WriteLine(",");
|
|
lw.GoToColumn(level);
|
|
}
|
|
}
|
|
first = false;
|
|
lw.ClearWrappedFlag();
|
|
WriteSignatureType(lw, parameter.ParameterType, loc);
|
|
noLineWrapCompat |= lw.Wrapped;
|
|
WriteCustomModifiers(lw, parameter.__GetCustomModifiers());
|
|
}
|
|
if (optionalParameterTypes.Length != 0)
|
|
{
|
|
if (!first)
|
|
{
|
|
lw.WriteLine(",");
|
|
lw.GoToColumn(level);
|
|
}
|
|
first = false;
|
|
lw.Write("...");
|
|
for (int i = 0; i < optionalParameterTypes.Length; i++)
|
|
{
|
|
if (!first)
|
|
{
|
|
lw.WriteLine(",");
|
|
lw.GoToColumn(level);
|
|
}
|
|
first = false;
|
|
WriteSignatureType(lw, optionalParameterTypes[i], TypeLocation.MemberRef);
|
|
WriteCustomModifiers(lw, customModifiers[i]);
|
|
}
|
|
}
|
|
lw.Write(")");
|
|
}
|
|
|
|
void WriteInlineType(LineWriter lw, int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
CustomModifiers mods = new CustomModifiers();
|
|
if (metadataToken >> 24 == 0x1B)
|
|
{
|
|
mods = module.__ResolveTypeSpecCustomModifiers(metadataToken, genericTypeArguments, genericMethodArguments);
|
|
}
|
|
if (!mods.IsEmpty)
|
|
{
|
|
lw.Write("class ");
|
|
}
|
|
Type type = ResolveType(metadataToken, genericTypeArguments, genericMethodArguments);
|
|
if (type.HasElementType)
|
|
{
|
|
WriteSignatureType(lw, type);
|
|
}
|
|
else if (!type.__IsMissing && type.IsGenericType)
|
|
{
|
|
WriteSignatureType(lw, type, TypeLocation.General);
|
|
}
|
|
else
|
|
{
|
|
WriteTypeDefOrRef(lw, type);
|
|
}
|
|
if (!mods.IsEmpty)
|
|
{
|
|
WriteCustomModifiers(lw, mods);
|
|
}
|
|
}
|
|
|
|
void WriteInlineField(LineWriter lw, FieldInfo field)
|
|
{
|
|
WriteSignatureType(lw, field.__GetFieldOnTypeDefinition().FieldType, TypeLocation.MemberRefNoWrap);
|
|
WriteCustomModifiers(lw, field.__GetCustomModifiers());
|
|
lw.Write(" ");
|
|
if (field.DeclaringType == null)
|
|
{
|
|
lw.Write("{0}", QuoteIdentifier(GetFieldName(field)));
|
|
}
|
|
else
|
|
{
|
|
if (field.DeclaringType.__IsMissing || !field.DeclaringType.IsGenericType)
|
|
{
|
|
WriteTypeDefOrRef(lw, field.DeclaringType);
|
|
}
|
|
else
|
|
{
|
|
WriteSignatureType(lw, field.DeclaringType, TypeLocation.General);
|
|
}
|
|
lw.Write("::{0}", QuoteIdentifier(GetFieldName(field)));
|
|
}
|
|
}
|
|
|
|
Type[] ResolveOptionalParameterTypes(int token, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
|
|
{
|
|
return module.__ResolveOptionalParameterTypes(token, genericTypeArguments, genericMethodArguments, out customModifiers);
|
|
}
|
|
|
|
void SortExceptions(IList<ExceptionHandlingClause> all, List<ExceptionHandlingClause> nested, List<ExceptionHandlingClause> flat)
|
|
{
|
|
var exceptions = new List<ExceptionHandlingClause>(all);
|
|
exceptions.Sort(this);
|
|
int first = 0;
|
|
for (int i = 1; i <= exceptions.Count; i++)
|
|
{
|
|
if (i < exceptions.Count
|
|
&& exceptions[first].TryOffset == exceptions[i].TryOffset
|
|
&& exceptions[first].TryLength == exceptions[i].TryLength
|
|
&& (compat != CompatLevel.V20 || exceptions[i].FilterOffset == 0))
|
|
{
|
|
// part of a multiple handler block
|
|
}
|
|
else
|
|
{
|
|
if (compat == CompatLevel.V20)
|
|
{
|
|
for (int j = first; j < i; j++)
|
|
{
|
|
if (exceptions[j].FilterOffset != 0
|
|
|| (i < exceptions.Count
|
|
&& exceptions[j].TryOffset == exceptions[i].TryOffset
|
|
&& exceptions[j].TryLength == exceptions[i].TryLength
|
|
&& exceptions[j].HandlerOffset + exceptions[j].HandlerLength > exceptions[i].FilterOffset))
|
|
{
|
|
flat.Add(exceptions[j]);
|
|
}
|
|
else
|
|
{
|
|
nested.Add(exceptions[j]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int j = first; j < i; j++)
|
|
{
|
|
nested.Add(exceptions[j]);
|
|
}
|
|
int end = exceptions[first].TryOffset + exceptions[first].TryLength;
|
|
for (int j = i - 1; j >= first; j--)
|
|
{
|
|
Debug.Assert(exceptions[j].TryOffset == exceptions[first].TryOffset && exceptions[j].TryLength == exceptions[first].TryLength);
|
|
if (exceptions[j].FilterOffset == end)
|
|
{
|
|
end += exceptions[j].HandlerOffset - exceptions[j].FilterOffset;
|
|
}
|
|
if (exceptions[j].HandlerOffset != end)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
end += exceptions[j].HandlerLength;
|
|
}
|
|
}
|
|
first = i;
|
|
}
|
|
}
|
|
flat.Sort(FlatExceptionComparer);
|
|
}
|
|
|
|
static int FlatExceptionComparer(ExceptionHandlingClause x, ExceptionHandlingClause y)
|
|
{
|
|
return (x.HandlerOffset + x.HandlerLength).CompareTo(y.HandlerOffset + y.HandlerLength);
|
|
}
|
|
|
|
Type ResolveType(int token, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
return module.ResolveType(token, genericTypeArguments, genericMethodArguments);
|
|
}
|
|
|
|
FieldInfo ResolveField(int token, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
return module.ResolveField(token, genericTypeArguments, genericMethodArguments);
|
|
}
|
|
|
|
MethodBase ResolveMethod(int token, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
return module.ResolveMethod(token, genericTypeArguments, genericMethodArguments);
|
|
}
|
|
|
|
MemberInfo ResolveMember(int token, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
return module.ResolveMember(token, genericTypeArguments, genericMethodArguments);
|
|
}
|
|
|
|
short ReadInt16(byte[] code, ref int pos)
|
|
{
|
|
short s = BitConverter.ToInt16(code, pos);
|
|
pos += 2;
|
|
return s;
|
|
}
|
|
|
|
int ReadInt32(byte[] code, ref int pos)
|
|
{
|
|
int i = BitConverter.ToInt32(code, pos);
|
|
pos += 4;
|
|
return i;
|
|
}
|
|
|
|
long ReadInt64(byte[] code, ref int pos)
|
|
{
|
|
long l = BitConverter.ToInt64(code, pos);
|
|
pos += 8;
|
|
return l;
|
|
}
|
|
|
|
float ReadSingle(byte[] code, ref int pos)
|
|
{
|
|
float f = BitConverter.ToSingle(code, pos);
|
|
pos += 4;
|
|
return f;
|
|
}
|
|
|
|
double ReadDouble(byte[] code, ref int pos)
|
|
{
|
|
double d = BitConverter.ToDouble(code, pos);
|
|
pos += 8;
|
|
return d;
|
|
}
|
|
|
|
int IComparer<ExceptionHandlingClause>.Compare(ExceptionHandlingClause x, ExceptionHandlingClause y)
|
|
{
|
|
if (x.TryOffset < y.TryOffset)
|
|
{
|
|
return -1;
|
|
}
|
|
if (x.TryOffset > y.TryOffset)
|
|
{
|
|
return 1;
|
|
}
|
|
if (x.TryLength > y.TryLength)
|
|
{
|
|
return -1;
|
|
}
|
|
if (x.TryLength < y.TryLength)
|
|
{
|
|
return 1;
|
|
}
|
|
if (x.HandlerOffset > y.HandlerOffset)
|
|
{
|
|
return -1;
|
|
}
|
|
if (x.HandlerOffset < y.HandlerOffset)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
}
|