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); } }
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 WriteVTableFixups(LineWriter lw) { int ptrsize = GetPointerSize(); VTableFixups[] fixups = GetVTableFixups(); if (fixups.Length != 0) { for (int i = 0; i < fixups.Length; i++) { lw.Write(".vtfixup [{0}] {1}{2} at D_{3:X8} //", fixups[i].Count, (fixups[i].Type & COR_VTABLE_32BIT) != 0 ? "int32" : "int64", (fixups[i].Type & COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) != 0 ? " retainappdomain" : (fixups[i].Type & COR_VTABLE_FROM_UNMANAGED) != 0 ? " fromunmanaged" : "", fixups[i].RVA); foreach (var method in GetVTableMethods(fixups[i])) { if (ptrsize == 4) { lw.Write(" {0:X8}", method.MetadataToken); } else { lw.Write(" {0:X16}", method.MetadataToken); } } lw.WriteLine(); } } }
void WriteInlineI8(LineWriter lw, long value) { if (value >= 128 || value < 128) { lw.Write("0x{0:x}", value); } else { lw.Write("{0}", value); } }
void WriteInlineType(LineWriter lw, Type type) { if (type.HasElementType) { WriteSignatureType(lw, type); } else if (!type.__IsMissing && type.IsGenericType) { WriteSignatureType(lw, type, TypeLocation.General); } else { WriteTypeDefOrRef(lw, type); } }
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))); } }
void WriteVTableFixupComment(LineWriter lw) { int ptrsize = GetPointerSize(); VTableFixups[] fixups = GetVTableFixups(); if (fixups.Length != 0) { lw.WriteLine("// VTableFixup Directory:"); for (int i = 0; i < fixups.Length; i++) { lw.WriteLine("// IMAGE_COR_VTABLEFIXUP[{0}]:", i); lw.WriteLine("// RVA: 0x{0:x8}", fixups[i].RVA); lw.WriteLine("// Count: 0x{0:x4}", fixups[i].Count); lw.WriteLine("// Type: 0x{0:x4}", fixups[i].Type); var methods = GetVTableMethods(fixups[i]); for (int j = 0; j < methods.Length; j++) { var method = methods[j]; List <KeyValuePair <int, int> > list; if (!vtentryMap.TryGetValue(method, out list)) { list = new List <KeyValuePair <int, int> >(); vtentryMap.Add(method, list); } list.Add(new KeyValuePair <int, int>(i + 1, j + 1)); if (ptrsize == 4) { lw.WriteLine("// [0x{0:x4}] (0x{1:x8})", j, method.MetadataToken); } else { lw.WriteLine("// [0x{0:x4}] (0x {1:x})", j, method.MetadataToken); } } } lw.WriteLine(); } lw.WriteLine(); }
void WriteVTableFixupComment(LineWriter lw) { int ptrsize = GetPointerSize(); VTableFixups[] fixups = GetVTableFixups(); if (fixups.Length != 0) { lw.WriteLine("// VTableFixup Directory:"); for (int i = 0; i < fixups.Length; i++) { lw.WriteLine("// IMAGE_COR_VTABLEFIXUP[{0}]:", i); lw.WriteLine("// RVA: 0x{0:x8}", fixups[i].RVA); lw.WriteLine("// Count: 0x{0:x4}", fixups[i].Count); lw.WriteLine("// Type: 0x{0:x4}", fixups[i].Type); var methods = GetVTableMethods(fixups[i]); for (int j = 0; j < methods.Length; j++) { var method = methods[j]; List<KeyValuePair<int,int>> list; if (!vtentryMap.TryGetValue(method, out list)) { list = new List<KeyValuePair<int, int>>(); vtentryMap.Add(method, list); } list.Add(new KeyValuePair<int,int>(i + 1, j + 1)); if (ptrsize == 4) { lw.WriteLine("// [0x{0:x4}] (0x{1:x8})", j, method.MetadataToken); } else { lw.WriteLine("// [0x{0:x4}] (0x {1:x})", j, method.MetadataToken); } } } lw.WriteLine(); } lw.WriteLine(); }
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 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); }
void WriteInlineR(LineWriter lw, double value, bool field) { lw.Write(ToString(value, field)); }
void WriteShortInlineR(LineWriter lw, float value, bool field) { lw.Write(ToString(value, field)); }
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; } } } }