PageRenderTime 315ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/System.Compilers/ILReader.cs

http://rendering.codeplex.com
C# | 341 lines | 296 code | 43 blank | 2 comment | 54 complexity | 76092b0bf8dd1de089dec7ebaf8e52d5 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Reflection;
  6. using System.Reflection.Emit;
  7. using System.IO;
  8. namespace System.Compilers
  9. {
  10. class ILReader
  11. {
  12. Assembly assembly;
  13. public ILReader(Assembly assembly)
  14. {
  15. this.assembly = assembly;
  16. }
  17. static Dictionary<int, FieldInfo> fields = new Dictionary<int, FieldInfo>();
  18. FieldInfo ResolveField(int token)
  19. {
  20. if (fields.ContainsKey(token))
  21. return fields[token];
  22. lock (fields)
  23. {
  24. FieldInfo field = assembly.ManifestModule.ResolveField(token);
  25. if (field != null)
  26. {
  27. fields.Add(token, field);
  28. return field;
  29. }
  30. }
  31. return null;
  32. }
  33. MethodBase ResolveMethod(int token)
  34. {
  35. lock (fields)
  36. {
  37. MethodBase method = (MethodBase)assembly.ManifestModule.ResolveMethod(token);
  38. if (method != null)
  39. return method;
  40. }
  41. return null;
  42. }
  43. String ResolveString(int token)
  44. {
  45. lock (fields)
  46. {
  47. String _string = assembly.ManifestModule.ResolveString(token);
  48. if (_string != null)
  49. return _string;
  50. }
  51. return null;
  52. }
  53. Type ResolveType(int token)
  54. {
  55. lock (fields)
  56. {
  57. Type type = assembly.ManifestModule.ResolveType(token);
  58. if (type != null)
  59. return type;
  60. }
  61. return null;
  62. }
  63. static IEnumerable<OpCode> allOpcodes = new Func<IEnumerable<OpCode>>(() =>
  64. {
  65. FieldInfo[] fields = typeof(OpCodes).GetFields();
  66. List<OpCode> opCodes = new List<OpCode>();
  67. foreach (var f in fields)
  68. if (f.FieldType == typeof(OpCode))
  69. opCodes.Add((OpCode)f.GetValue(null));
  70. return opCodes;
  71. })();
  72. static IEnumerable<OpCode> AllOpcodes
  73. {
  74. get
  75. {
  76. return allOpcodes;
  77. }
  78. }
  79. private ILInstruction ReadFrom(BinaryReader binary)
  80. {
  81. int position = (int)binary.BaseStream.Position;
  82. byte opCodeValue = binary.ReadByte();
  83. OpCode currentOpCode = new OpCode();
  84. foreach (OpCode opcode in AllOpcodes)
  85. if (opcode.Value == opCodeValue)
  86. currentOpCode = opcode;
  87. if (currentOpCode.FlowControl == FlowControl.Meta)
  88. {
  89. byte opCodeValue2 = binary.ReadByte();
  90. unchecked
  91. {
  92. short s = (short)((opCodeValue << 8) + (opCodeValue2 << 0));
  93. foreach (OpCode opcode in AllOpcodes)
  94. if (opcode.Value == s)
  95. currentOpCode = opcode;
  96. }
  97. }
  98. object[] args = new object[0];
  99. int token = 0;
  100. switch (currentOpCode.OperandType)
  101. {
  102. case OperandType.InlineBrTarget:
  103. args = new object[] { binary.ReadInt32() };
  104. break;
  105. case OperandType.InlineField:
  106. token = binary.ReadInt32();
  107. args = new object[] { ResolveField(token) };
  108. break;
  109. case OperandType.InlineI:
  110. args = new object[] { binary.ReadInt32() };
  111. break;
  112. case OperandType.InlineI8:
  113. args = new object[] { binary.ReadInt64() };
  114. break;
  115. case OperandType.InlineMethod:
  116. token = binary.ReadInt32();
  117. args = new object[] { ResolveMethod(token) };
  118. break;
  119. case OperandType.InlineNone:
  120. args = new object[] { };
  121. break;
  122. case OperandType.InlineR:
  123. args = new object[] { binary.ReadDouble() };
  124. break;
  125. case OperandType.InlineSig:
  126. args = new object[] { binary.ReadInt32() };
  127. break;
  128. case OperandType.InlineString:
  129. token = binary.ReadInt32();
  130. args = new object[] { ResolveString(token) };
  131. break;
  132. case OperandType.InlineSwitch:
  133. int count = binary.ReadInt32();
  134. int[] _switches = new int[count];
  135. for (int i = 0; i < _switches.Length; i++)
  136. _switches[i] = binary.ReadInt32();
  137. args = new object[count];
  138. for (int i = 0; i < count; i++)
  139. args[i] = _switches[i];
  140. break;
  141. case OperandType.InlineTok:
  142. token = binary.ReadInt32();
  143. args = new object[] { token };
  144. break;
  145. case OperandType.InlineType:
  146. token = binary.ReadInt32();
  147. args = new object[] { ResolveType(token) };
  148. break;
  149. case OperandType.InlineVar:
  150. short id = binary.ReadInt16();
  151. args = new object[] { id };
  152. break;
  153. case OperandType.ShortInlineBrTarget:
  154. sbyte _id = (sbyte)(binary.ReadSByte());
  155. args = new object[] { _id };
  156. break;
  157. case OperandType.ShortInlineI:
  158. _id = binary.ReadSByte();
  159. args = new object[] { _id };
  160. break;
  161. case OperandType.ShortInlineR:
  162. float v = binary.ReadSingle();
  163. args = new object[] { v };
  164. break;
  165. case OperandType.ShortInlineVar:
  166. _id = binary.ReadSByte();
  167. args = new object[] { _id };
  168. break;
  169. }
  170. return new ILInstruction(currentOpCode, position, (int)(binary.BaseStream.Position - position), args);
  171. }
  172. public IEnumerable<ILInstruction> GetIL(MethodInfo method)
  173. {
  174. List<ILInstruction> il = new List<ILInstruction>();
  175. MethodBody body = method.GetMethodBody();
  176. BinaryReader br = new BinaryReader(new MemoryStream(body.GetILAsByteArray()));
  177. while (br.BaseStream.Position < br.BaseStream.Length)
  178. il.Add(ReadFrom(br));
  179. return il;
  180. }
  181. int NextBlockStart(List<ILInstruction> instructions, int start)
  182. {
  183. do
  184. {
  185. start = instructions.FindIndex(start, (inst) => { return inst.OpCode == OpCodes.Ldc_I4_M1; });
  186. if (start == -1)
  187. return -1;
  188. if (instructions[start + 1].OpCode == OpCodes.Stfld && ((FieldInfo)instructions[start + 1].Operand).Name == "<>1__state")
  189. return start + 2;
  190. start++;
  191. } while (true);
  192. }
  193. int NextBlockEnd(List<ILInstruction> instructions, int start)
  194. {
  195. do
  196. {
  197. start = instructions.FindIndex(start, (inst) => { return inst.OpCode == OpCodes.Stfld; });
  198. if (start == -1)
  199. return -1;
  200. if (((FieldInfo)instructions[start].Operand).Name == "<>2__current")
  201. return start - 1;
  202. start++;
  203. } while (true);
  204. }
  205. private IEnumerable<ILInstruction> GetILInvolvedOnLeazyMethod(MethodInfo method)
  206. {
  207. List<ILInstruction> il = new List<ILInstruction>(GetILForLeazyMethod(method));
  208. int start = 0, finish = 0;
  209. do
  210. {
  211. start = NextBlockStart(il, start);
  212. finish = NextBlockEnd(il, start);
  213. if (start == -1 || finish == -1)
  214. yield break;
  215. for (int i = start; i <= finish; i++)
  216. yield return il[i];
  217. yield return new ILInstruction(OpCodes.Ret, il[finish + 1].Address, 1);
  218. } while (true);
  219. }
  220. private IEnumerable<ILInstruction> GetILForLeazyMethod(MethodInfo method)
  221. {
  222. //string innerclassname = method.ReflectedType.FullName + "+<" + method.Name + ">d_0";
  223. Type type = method.ReflectedType.GetNestedType("<" + method.Name + ">d__0", BindingFlags.NonPublic);
  224. List<ILInstruction> fullIL = new List<ILInstruction>(GetIL(type.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)));
  225. return fullIL;
  226. }
  227. }
  228. public class ILInstruction
  229. {
  230. OpCode _operation;
  231. object[] _params;
  232. int position;
  233. int size;
  234. public OpCode OpCode { get { return _operation; } }
  235. public bool HasOperand { get { return _params.Length > 0; } }
  236. public object Operand { get { return HasOperand ? _params[0] : null; } }
  237. public object[] Args { get { return _params; } }
  238. public int Address { get { return position; } }
  239. public ILInstruction Clone()
  240. {
  241. return new ILInstruction(this.OpCode, this.position, this.size, this._params);
  242. }
  243. internal ILInstruction(OpCode op, int address, int size, params object[] args)
  244. {
  245. this._operation = op;
  246. this._params = args;
  247. this.position = address;
  248. this.size = size;
  249. }
  250. public int Size { get { return size; } }
  251. public bool IsBranch
  252. {
  253. get { return OpCode.FlowControl == FlowControl.Branch || OpCode.FlowControl == FlowControl.Cond_Branch; }
  254. }
  255. public bool IsConditionalBranch
  256. {
  257. get { return OpCode.FlowControl == FlowControl.Cond_Branch; }
  258. }
  259. public int BrachILAddress
  260. {
  261. get
  262. {
  263. if (OpCode.OperandType == OperandType.ShortInlineBrTarget)
  264. {
  265. return ((int)((sbyte)Args[0]) + this.Address + this.Size);
  266. }
  267. if (OpCode.OperandType == OperandType.InlineBrTarget)
  268. {
  269. return ((int)((int)Args[0]) + this.Address + this.Size);
  270. }
  271. return -1;
  272. }
  273. }
  274. public override string ToString()
  275. {
  276. string argList = "";
  277. for (int i = 0; i < Args.Length; i++)
  278. {
  279. if (IsBranch)
  280. {
  281. argList += ((sbyte)Args[i]) + ": IL_" + BrachILAddress.ToString("X");
  282. continue;
  283. }
  284. if (OpCode.OperandType == OperandType.InlineSwitch)
  285. {
  286. argList += ((int)Args[i]).ToString("X");
  287. if (i < Args.Length - 1)
  288. argList += ", ";
  289. continue;
  290. }
  291. argList += Args[i];
  292. }
  293. //if (Args.Length > 1)
  294. argList = "(" + argList + ")";
  295. return "IL_" + Address.ToString("X") + ": " + OpCode.Name + " " + argList;
  296. }
  297. }
  298. }