ILGenerator.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131
  1. //
  2. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining
  5. // a copy of this software and associated documentation files (the
  6. // "Software"), to deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge, publish,
  8. // distribute, sublicense, and/or sell copies of the Software, and to
  9. // permit persons to whom the Software is furnished to do so, subject to
  10. // the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. //
  23. //
  24. // System.Reflection.Emit/ILGenerator.cs
  25. //
  26. // Author:
  27. // Paolo Molaro ([email protected])
  28. //
  29. // (C) 2001 Ximian, Inc. http://www.ximian.com
  30. //
  31. using System;
  32. using System.Collections;
  33. using System.Diagnostics.SymbolStore;
  34. using System.Runtime.InteropServices;
  35. namespace System.Reflection.Emit {
  36. internal struct ILExceptionBlock {
  37. public const int CATCH = 0;
  38. public const int FILTER = 1;
  39. public const int FINALLY = 2;
  40. public const int FAULT = 4;
  41. public const int FILTER_START = -1;
  42. internal Type extype;
  43. internal int type;
  44. internal int start;
  45. internal int len;
  46. internal int filter_offset;
  47. internal void Debug () {
  48. #if NO
  49. System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString()+" len="+len.ToString());
  50. if (extype != null)
  51. System.Console.WriteLine (" extype="+extype.ToString());
  52. else
  53. System.Console.WriteLine (String.Empty);
  54. #endif
  55. }
  56. }
  57. internal struct ILExceptionInfo {
  58. #pragma warning disable 169
  59. #pragma warning disable 414
  60. ILExceptionBlock[] handlers;
  61. internal int start;
  62. int len;
  63. internal Label end;
  64. #pragma warning restore 169
  65. #pragma warning restore 414
  66. internal int NumHandlers ()
  67. {
  68. return handlers.Length;
  69. }
  70. internal void AddCatch (Type extype, int offset)
  71. {
  72. int i;
  73. End (offset);
  74. add_block (offset);
  75. i = handlers.Length - 1;
  76. handlers [i].type = ILExceptionBlock.CATCH;
  77. handlers [i].start = offset;
  78. handlers [i].extype = extype;
  79. }
  80. internal void AddFinally (int offset)
  81. {
  82. int i;
  83. End (offset);
  84. add_block (offset);
  85. i = handlers.Length - 1;
  86. handlers [i].type = ILExceptionBlock.FINALLY;
  87. handlers [i].start = offset;
  88. handlers [i].extype = null;
  89. }
  90. internal void AddFault (int offset)
  91. {
  92. int i;
  93. End (offset);
  94. add_block (offset);
  95. i = handlers.Length - 1;
  96. handlers [i].type = ILExceptionBlock.FAULT;
  97. handlers [i].start = offset;
  98. handlers [i].extype = null;
  99. }
  100. internal void AddFilter (int offset)
  101. {
  102. int i;
  103. End (offset);
  104. add_block (offset);
  105. i = handlers.Length - 1;
  106. handlers [i].type = ILExceptionBlock.FILTER_START;
  107. handlers [i].extype = null;
  108. handlers [i].filter_offset = offset;
  109. }
  110. internal void End (int offset)
  111. {
  112. if (handlers == null)
  113. return;
  114. int i = handlers.Length - 1;
  115. if (i >= 0)
  116. handlers [i].len = offset - handlers [i].start;
  117. }
  118. internal int LastClauseType ()
  119. {
  120. if (handlers != null)
  121. return handlers [handlers.Length-1].type;
  122. else
  123. return ILExceptionBlock.CATCH;
  124. }
  125. internal void PatchFilterClause (int start)
  126. {
  127. if (handlers != null && handlers.Length > 0) {
  128. handlers [handlers.Length - 1].start = start;
  129. handlers [handlers.Length - 1].type = ILExceptionBlock.FILTER;
  130. }
  131. }
  132. internal void Debug (int b)
  133. {
  134. #if NO
  135. System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
  136. for (int i = 0; i < handlers.Length; ++i)
  137. handlers [i].Debug ();
  138. #endif
  139. }
  140. void add_block (int offset)
  141. {
  142. if (handlers != null) {
  143. int i = handlers.Length;
  144. ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
  145. System.Array.Copy (handlers, new_b, i);
  146. handlers = new_b;
  147. handlers [i].len = offset - handlers [i].start;
  148. } else {
  149. handlers = new ILExceptionBlock [1];
  150. len = offset - start;
  151. }
  152. }
  153. }
  154. internal struct ILTokenInfo {
  155. public MemberInfo member;
  156. public int code_pos;
  157. }
  158. internal interface TokenGenerator {
  159. int GetToken (string str);
  160. int GetToken (MemberInfo member, bool create_open_instance);
  161. int GetToken (MethodInfo method, Type[] opt_param_types);
  162. int GetToken (SignatureHelper helper);
  163. }
  164. [ComVisible (true)]
  165. [ComDefaultInterface (typeof (_ILGenerator))]
  166. [ClassInterface (ClassInterfaceType.None)]
  167. public class ILGenerator: _ILGenerator {
  168. private struct LabelFixup {
  169. public int offset; // The number of bytes between pos and the
  170. // offset of the jump
  171. public int pos; // Where offset of the label is placed
  172. public int label_idx; // The label to jump to
  173. };
  174. struct LabelData {
  175. public LabelData (int addr, int maxStack)
  176. {
  177. this.addr = addr;
  178. this.maxStack = maxStack;
  179. }
  180. public int addr;
  181. public int maxStack;
  182. }
  183. static readonly Type void_type = typeof (void);
  184. #region Sync with reflection.h
  185. private byte[] code;
  186. private int code_len;
  187. private int max_stack;
  188. private int cur_stack;
  189. private LocalBuilder[] locals;
  190. private ILExceptionInfo[] ex_handlers;
  191. private int num_token_fixups;
  192. private ILTokenInfo[] token_fixups;
  193. #endregion
  194. private LabelData [] labels;
  195. private int num_labels;
  196. private LabelFixup[] fixups;
  197. private int num_fixups;
  198. internal Module module;
  199. private int cur_block;
  200. private Stack open_blocks;
  201. private TokenGenerator token_gen;
  202. const int defaultFixupSize = 4;
  203. const int defaultLabelsSize = 4;
  204. const int defaultExceptionStackSize = 2;
  205. ArrayList sequencePointLists;
  206. SequencePointList currentSequence;
  207. internal ILGenerator (Module m, TokenGenerator token_gen, int size)
  208. {
  209. if (size < 0)
  210. size = 128;
  211. code = new byte [size];
  212. token_fixups = new ILTokenInfo [8];
  213. module = m;
  214. this.token_gen = token_gen;
  215. }
  216. private void add_token_fixup (MemberInfo mi)
  217. {
  218. if (num_token_fixups == token_fixups.Length) {
  219. ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
  220. token_fixups.CopyTo (ntf, 0);
  221. token_fixups = ntf;
  222. }
  223. token_fixups [num_token_fixups].member = mi;
  224. token_fixups [num_token_fixups++].code_pos = code_len;
  225. }
  226. private void make_room (int nbytes)
  227. {
  228. if (code_len + nbytes < code.Length)
  229. return;
  230. byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
  231. System.Array.Copy (code, 0, new_code, 0, code.Length);
  232. code = new_code;
  233. }
  234. private void emit_int (int val)
  235. {
  236. code [code_len++] = (byte) (val & 0xFF);
  237. code [code_len++] = (byte) ((val >> 8) & 0xFF);
  238. code [code_len++] = (byte) ((val >> 16) & 0xFF);
  239. code [code_len++] = (byte) ((val >> 24) & 0xFF);
  240. }
  241. /* change to pass by ref to avoid copy */
  242. private void ll_emit (OpCode opcode)
  243. {
  244. /*
  245. * there is already enough room allocated in code.
  246. */
  247. // access op1 and op2 directly since the Value property is useless
  248. if (opcode.Size == 2)
  249. code [code_len++] = opcode.op1;
  250. code [code_len++] = opcode.op2;
  251. /*
  252. * We should probably keep track of stack needs here.
  253. * Or we may want to run the verifier on the code before saving it
  254. * (this may be needed anyway when the ILGenerator is not used...).
  255. */
  256. switch (opcode.StackBehaviourPush) {
  257. case StackBehaviour.Push1:
  258. case StackBehaviour.Pushi:
  259. case StackBehaviour.Pushi8:
  260. case StackBehaviour.Pushr4:
  261. case StackBehaviour.Pushr8:
  262. case StackBehaviour.Pushref:
  263. case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
  264. cur_stack ++;
  265. break;
  266. case StackBehaviour.Push1_push1:
  267. cur_stack += 2;
  268. break;
  269. }
  270. if (max_stack < cur_stack)
  271. max_stack = cur_stack;
  272. /*
  273. * Note that we adjust for the pop behaviour _after_ setting max_stack.
  274. */
  275. switch (opcode.StackBehaviourPop) {
  276. case StackBehaviour.Varpop:
  277. break; /* we are conservative and assume it doesn't decrease the stack needs */
  278. case StackBehaviour.Pop1:
  279. case StackBehaviour.Popi:
  280. case StackBehaviour.Popref:
  281. cur_stack --;
  282. break;
  283. case StackBehaviour.Pop1_pop1:
  284. case StackBehaviour.Popi_pop1:
  285. case StackBehaviour.Popi_popi:
  286. case StackBehaviour.Popi_popi8:
  287. case StackBehaviour.Popi_popr4:
  288. case StackBehaviour.Popi_popr8:
  289. case StackBehaviour.Popref_pop1:
  290. case StackBehaviour.Popref_popi:
  291. cur_stack -= 2;
  292. break;
  293. case StackBehaviour.Popi_popi_popi:
  294. case StackBehaviour.Popref_popi_popi:
  295. case StackBehaviour.Popref_popi_popi8:
  296. case StackBehaviour.Popref_popi_popr4:
  297. case StackBehaviour.Popref_popi_popr8:
  298. case StackBehaviour.Popref_popi_popref:
  299. cur_stack -= 3;
  300. break;
  301. }
  302. }
  303. private static int target_len (OpCode opcode)
  304. {
  305. if (opcode.OperandType == OperandType.InlineBrTarget)
  306. return 4;
  307. return 1;
  308. }
  309. private void InternalEndClause ()
  310. {
  311. switch (ex_handlers [cur_block].LastClauseType ()) {
  312. case ILExceptionBlock.CATCH:
  313. case ILExceptionBlock.FILTER:
  314. case ILExceptionBlock.FILTER_START:
  315. // how could we optimize code size here?
  316. Emit (OpCodes.Leave, ex_handlers [cur_block].end);
  317. break;
  318. case ILExceptionBlock.FAULT:
  319. case ILExceptionBlock.FINALLY:
  320. Emit (OpCodes.Endfinally);
  321. break;
  322. }
  323. }
  324. public virtual void BeginCatchBlock (Type exceptionType)
  325. {
  326. if (open_blocks == null)
  327. open_blocks = new Stack (defaultExceptionStackSize);
  328. if (open_blocks.Count <= 0)
  329. throw new NotSupportedException ("Not in an exception block");
  330. if (exceptionType != null && exceptionType.IsUserType)
  331. throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
  332. if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
  333. if (exceptionType != null)
  334. throw new ArgumentException ("Do not supply an exception type for filter clause");
  335. Emit (OpCodes.Endfilter);
  336. ex_handlers [cur_block].PatchFilterClause (code_len);
  337. } else {
  338. InternalEndClause ();
  339. ex_handlers [cur_block].AddCatch (exceptionType, code_len);
  340. }
  341. cur_stack = 1; // the exception object is on the stack by default
  342. if (max_stack < cur_stack)
  343. max_stack = cur_stack;
  344. //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
  345. }
  346. public virtual void BeginExceptFilterBlock ()
  347. {
  348. if (open_blocks == null)
  349. open_blocks = new Stack (defaultExceptionStackSize);
  350. if (open_blocks.Count <= 0)
  351. throw new NotSupportedException ("Not in an exception block");
  352. InternalEndClause ();
  353. ex_handlers [cur_block].AddFilter (code_len);
  354. }
  355. public virtual Label BeginExceptionBlock ()
  356. {
  357. //System.Console.WriteLine ("Begin Block");
  358. if (open_blocks == null)
  359. open_blocks = new Stack (defaultExceptionStackSize);
  360. if (ex_handlers != null) {
  361. cur_block = ex_handlers.Length;
  362. ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
  363. System.Array.Copy (ex_handlers, new_ex, cur_block);
  364. ex_handlers = new_ex;
  365. } else {
  366. ex_handlers = new ILExceptionInfo [1];
  367. cur_block = 0;
  368. }
  369. open_blocks.Push (cur_block);
  370. ex_handlers [cur_block].start = code_len;
  371. return ex_handlers [cur_block].end = DefineLabel ();
  372. }
  373. public virtual void BeginFaultBlock()
  374. {
  375. if (open_blocks == null)
  376. open_blocks = new Stack (defaultExceptionStackSize);
  377. if (open_blocks.Count <= 0)
  378. throw new NotSupportedException ("Not in an exception block");
  379. if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
  380. Emit (OpCodes.Leave, ex_handlers [cur_block].end);
  381. ex_handlers [cur_block].PatchFilterClause (code_len);
  382. }
  383. InternalEndClause ();
  384. //System.Console.WriteLine ("Begin fault Block");
  385. ex_handlers [cur_block].AddFault (code_len);
  386. }
  387. public virtual void BeginFinallyBlock()
  388. {
  389. if (open_blocks == null)
  390. open_blocks = new Stack (defaultExceptionStackSize);
  391. if (open_blocks.Count <= 0)
  392. throw new NotSupportedException ("Not in an exception block");
  393. InternalEndClause ();
  394. if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
  395. Emit (OpCodes.Leave, ex_handlers [cur_block].end);
  396. ex_handlers [cur_block].PatchFilterClause (code_len);
  397. }
  398. //System.Console.WriteLine ("Begin finally Block");
  399. ex_handlers [cur_block].AddFinally (code_len);
  400. }
  401. public virtual void BeginScope ()
  402. { }
  403. public virtual LocalBuilder DeclareLocal (Type localType)
  404. {
  405. return DeclareLocal (localType, false);
  406. }
  407. public virtual LocalBuilder DeclareLocal (Type localType, bool pinned)
  408. {
  409. if (localType == null)
  410. throw new ArgumentNullException ("localType");
  411. if (localType.IsUserType)
  412. throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
  413. LocalBuilder res = new LocalBuilder (localType, this);
  414. res.is_pinned = pinned;
  415. if (locals != null) {
  416. LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
  417. System.Array.Copy (locals, new_l, locals.Length);
  418. new_l [locals.Length] = res;
  419. locals = new_l;
  420. } else {
  421. locals = new LocalBuilder [1];
  422. locals [0] = res;
  423. }
  424. res.position = (ushort)(locals.Length - 1);
  425. return res;
  426. }
  427. public virtual Label DefineLabel ()
  428. {
  429. if (labels == null)
  430. labels = new LabelData [defaultLabelsSize];
  431. else if (num_labels >= labels.Length) {
  432. LabelData [] t = new LabelData [labels.Length * 2];
  433. Array.Copy (labels, t, labels.Length);
  434. labels = t;
  435. }
  436. labels [num_labels] = new LabelData (-1, 0);
  437. return new Label (num_labels++);
  438. }
  439. public virtual void Emit (OpCode opcode)
  440. {
  441. make_room (2);
  442. ll_emit (opcode);
  443. }
  444. public virtual void Emit (OpCode opcode, Byte arg)
  445. {
  446. make_room (3);
  447. ll_emit (opcode);
  448. code [code_len++] = arg;
  449. }
  450. [ComVisible (true)]
  451. public virtual void Emit (OpCode opcode, ConstructorInfo con)
  452. {
  453. int token = token_gen.GetToken (con, true);
  454. make_room (6);
  455. ll_emit (opcode);
  456. if (con.DeclaringType.Module == module)
  457. add_token_fixup (con);
  458. emit_int (token);
  459. if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
  460. cur_stack -= con.GetParameterCount ();
  461. }
  462. public virtual void Emit (OpCode opcode, double arg)
  463. {
  464. byte[] s = System.BitConverter.GetBytes (arg);
  465. make_room (10);
  466. ll_emit (opcode);
  467. if (BitConverter.IsLittleEndian){
  468. System.Array.Copy (s, 0, code, code_len, 8);
  469. code_len += 8;
  470. } else {
  471. code [code_len++] = s [7];
  472. code [code_len++] = s [6];
  473. code [code_len++] = s [5];
  474. code [code_len++] = s [4];
  475. code [code_len++] = s [3];
  476. code [code_len++] = s [2];
  477. code [code_len++] = s [1];
  478. code [code_len++] = s [0];
  479. }
  480. }
  481. public virtual void Emit (OpCode opcode, FieldInfo field)
  482. {
  483. int token = token_gen.GetToken (field, true);
  484. make_room (6);
  485. ll_emit (opcode);
  486. if (field.DeclaringType.Module == module)
  487. add_token_fixup (field);
  488. emit_int (token);
  489. }
  490. public virtual void Emit (OpCode opcode, Int16 arg)
  491. {
  492. make_room (4);
  493. ll_emit (opcode);
  494. code [code_len++] = (byte) (arg & 0xFF);
  495. code [code_len++] = (byte) ((arg >> 8) & 0xFF);
  496. }
  497. public virtual void Emit (OpCode opcode, int arg)
  498. {
  499. make_room (6);
  500. ll_emit (opcode);
  501. emit_int (arg);
  502. }
  503. public virtual void Emit (OpCode opcode, long arg)
  504. {
  505. make_room (10);
  506. ll_emit (opcode);
  507. code [code_len++] = (byte) (arg & 0xFF);
  508. code [code_len++] = (byte) ((arg >> 8) & 0xFF);
  509. code [code_len++] = (byte) ((arg >> 16) & 0xFF);
  510. code [code_len++] = (byte) ((arg >> 24) & 0xFF);
  511. code [code_len++] = (byte) ((arg >> 32) & 0xFF);
  512. code [code_len++] = (byte) ((arg >> 40) & 0xFF);
  513. code [code_len++] = (byte) ((arg >> 48) & 0xFF);
  514. code [code_len++] = (byte) ((arg >> 56) & 0xFF);
  515. }
  516. public virtual void Emit (OpCode opcode, Label label)
  517. {
  518. int tlen = target_len (opcode);
  519. make_room (6);
  520. ll_emit (opcode);
  521. if (cur_stack > labels [label.label].maxStack)
  522. labels [label.label].maxStack = cur_stack;
  523. if (fixups == null)
  524. fixups = new LabelFixup [defaultFixupSize];
  525. else if (num_fixups >= fixups.Length) {
  526. LabelFixup[] newf = new LabelFixup [fixups.Length * 2];
  527. System.Array.Copy (fixups, newf, fixups.Length);
  528. fixups = newf;
  529. }
  530. fixups [num_fixups].offset = tlen;
  531. fixups [num_fixups].pos = code_len;
  532. fixups [num_fixups].label_idx = label.label;
  533. num_fixups++;
  534. code_len += tlen;
  535. }
  536. public virtual void Emit (OpCode opcode, Label[] labels)
  537. {
  538. if (labels == null)
  539. throw new ArgumentNullException ("labels");
  540. /* opcode needs to be switch. */
  541. int count = labels.Length;
  542. make_room (6 + count * 4);
  543. ll_emit (opcode);
  544. for (int i = 0; i < count; ++i)
  545. if (cur_stack > this.labels [labels [i].label].maxStack)
  546. this.labels [labels [i].label].maxStack = cur_stack;
  547. emit_int (count);
  548. if (fixups == null)
  549. fixups = new LabelFixup [defaultFixupSize + count];
  550. else if (num_fixups + count >= fixups.Length) {
  551. LabelFixup[] newf = new LabelFixup [count + fixups.Length * 2];
  552. System.Array.Copy (fixups, newf, fixups.Length);
  553. fixups = newf;
  554. }
  555. // ECMA 335, Partition III, p94 (7-10)
  556. //
  557. // The switch instruction implements a jump table. The format of
  558. // the instruction is an unsigned int32 representing the number of targets N,
  559. // followed by N int32 values specifying jump targets: these targets are
  560. // represented as offsets (positive or negative) from the beginning of the
  561. // instruction following this switch instruction.
  562. //
  563. // We must make sure it gets an offset from the *end* of the last label
  564. // (eg, the beginning of the instruction following this).
  565. //
  566. // remaining is the number of bytes from the current instruction to the
  567. // instruction that will be emitted.
  568. for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
  569. fixups [num_fixups].offset = remaining;
  570. fixups [num_fixups].pos = code_len;
  571. fixups [num_fixups].label_idx = labels [i].label;
  572. num_fixups++;
  573. code_len += 4;
  574. }
  575. }
  576. public virtual void Emit (OpCode opcode, LocalBuilder local)
  577. {
  578. if (local == null)
  579. throw new ArgumentNullException ("local");
  580. if (local.ilgen != this)
  581. throw new ArgumentException ("Trying to emit a local from a different ILGenerator.");
  582. uint pos = local.position;
  583. bool load_addr = false;
  584. bool is_store = false;
  585. bool is_load = false;
  586. make_room (6);
  587. /* inline the code from ll_emit () to optimize il code size */
  588. if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
  589. cur_stack --;
  590. is_store = true;
  591. } else if (opcode.StackBehaviourPush == StackBehaviour.Push1 || opcode.StackBehaviourPush == StackBehaviour.Pushi) {
  592. cur_stack++;
  593. is_load = true;
  594. if (cur_stack > max_stack)
  595. max_stack = cur_stack;
  596. load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
  597. }
  598. if (load_addr) {
  599. if (pos < 256) {
  600. code [code_len++] = (byte)0x12;
  601. code [code_len++] = (byte)pos;
  602. } else {
  603. code [code_len++] = (byte)0xfe;
  604. code [code_len++] = (byte)0x0d;
  605. code [code_len++] = (byte)(pos & 0xff);
  606. code [code_len++] = (byte)((pos >> 8) & 0xff);
  607. }
  608. } else {
  609. if (is_store) {
  610. if (pos < 4) {
  611. code [code_len++] = (byte)(0x0a + pos);
  612. } else if (pos < 256) {
  613. code [code_len++] = (byte)0x13;
  614. code [code_len++] = (byte)pos;
  615. } else {
  616. code [code_len++] = (byte)0xfe;
  617. code [code_len++] = (byte)0x0e;
  618. code [code_len++] = (byte)(pos & 0xff);
  619. code [code_len++] = (byte)((pos >> 8) & 0xff);
  620. }
  621. } else if (is_load) {
  622. if (pos < 4) {
  623. code [code_len++] = (byte)(0x06 + pos);
  624. } else if (pos < 256) {
  625. code [code_len++] = (byte)0x11;
  626. code [code_len++] = (byte)pos;
  627. } else {
  628. code [code_len++] = (byte)0xfe;
  629. code [code_len++] = (byte)0x0c;
  630. code [code_len++] = (byte)(pos & 0xff);
  631. code [code_len++] = (byte)((pos >> 8) & 0xff);
  632. }
  633. } else {
  634. ll_emit (opcode);
  635. }
  636. }
  637. }
  638. public virtual void Emit (OpCode opcode, MethodInfo meth)
  639. {
  640. if (meth == null)
  641. throw new ArgumentNullException ("meth");
  642. // For compatibility with MS
  643. if ((meth is DynamicMethod) && ((opcode == OpCodes.Ldftn) || (opcode == OpCodes.Ldvirtftn) || (opcode == OpCodes.Ldtoken)))
  644. throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
  645. int token = token_gen.GetToken (meth, true);
  646. make_room (6);
  647. ll_emit (opcode);
  648. Type declaringType = meth.DeclaringType;
  649. // Might be a DynamicMethod with no declaring type
  650. if (declaringType != null) {
  651. if (declaringType.Module == module)
  652. add_token_fixup (meth);
  653. }
  654. emit_int (token);
  655. if (meth.ReturnType != void_type)
  656. cur_stack ++;
  657. if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
  658. cur_stack -= meth.GetParameterCount ();
  659. }
  660. private void Emit (OpCode opcode, MethodInfo method, int token)
  661. {
  662. make_room (6);
  663. ll_emit (opcode);
  664. // Might be a DynamicMethod with no declaring type
  665. Type declaringType = method.DeclaringType;
  666. if (declaringType != null) {
  667. if (declaringType.Module == module)
  668. add_token_fixup (method);
  669. }
  670. emit_int (token);
  671. if (method.ReturnType != void_type)
  672. cur_stack ++;
  673. if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
  674. cur_stack -= method.GetParameterCount ();
  675. }
  676. [CLSCompliant(false)]
  677. public void Emit (OpCode opcode, sbyte arg)
  678. {
  679. make_room (3);
  680. ll_emit (opcode);
  681. code [code_len++] = (byte)arg;
  682. }
  683. public virtual void Emit (OpCode opcode, SignatureHelper signature)
  684. {
  685. int token = token_gen.GetToken (signature);
  686. make_room (6);
  687. ll_emit (opcode);
  688. emit_int (token);
  689. }
  690. public virtual void Emit (OpCode opcode, float arg)
  691. {
  692. byte[] s = System.BitConverter.GetBytes (arg);
  693. make_room (6);
  694. ll_emit (opcode);
  695. if (BitConverter.IsLittleEndian){
  696. System.Array.Copy (s, 0, code, code_len, 4);
  697. code_len += 4;
  698. } else {
  699. code [code_len++] = s [3];
  700. code [code_len++] = s [2];
  701. code [code_len++] = s [1];
  702. code [code_len++] = s [0];
  703. }
  704. }
  705. public virtual void Emit (OpCode opcode, string str)
  706. {
  707. int token = token_gen.GetToken (str);
  708. make_room (6);
  709. ll_emit (opcode);
  710. emit_int (token);
  711. }
  712. public virtual void Emit (OpCode opcode, Type cls)
  713. {
  714. if (cls != null && cls.IsByRef)
  715. throw new ArgumentException ("Cannot get TypeToken for a ByRef type.");
  716. make_room (6);
  717. ll_emit (opcode);
  718. emit_int (token_gen.GetToken (cls, opcode != OpCodes.Ldtoken));
  719. }
  720. [MonoLimitation ("vararg methods are not supported")]
  721. public virtual void EmitCall (OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
  722. {
  723. if (methodInfo == null)
  724. throw new ArgumentNullException ("methodInfo");
  725. short value = opcode.Value;
  726. if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
  727. throw new NotSupportedException ("Only Call and CallVirt are allowed");
  728. if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0)
  729. optionalParameterTypes = null;
  730. if (optionalParameterTypes != null){
  731. if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0){
  732. throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
  733. }
  734. int token = token_gen.GetToken (methodInfo, optionalParameterTypes);
  735. Emit (opcode, methodInfo, token);
  736. return;
  737. }
  738. Emit (opcode, methodInfo);
  739. }
  740. public virtual void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
  741. {
  742. SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module, 0, unmanagedCallConv, returnType, parameterTypes);
  743. Emit (opcode, helper);
  744. }
  745. public virtual void EmitCalli (OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
  746. {
  747. if (optionalParameterTypes != null)
  748. throw new NotImplementedException ();
  749. SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module, callingConvention, 0, returnType, parameterTypes);
  750. Emit (opcode, helper);
  751. }
  752. public virtual void EmitWriteLine (FieldInfo fld)
  753. {
  754. if (fld == null)
  755. throw new ArgumentNullException ("fld");
  756. // The MS implementation does not check for valuetypes here but it
  757. // should. Also, it should check that if the field is not static,
  758. // then it is a member of this type.
  759. if (fld.IsStatic)
  760. Emit (OpCodes.Ldsfld, fld);
  761. else {
  762. Emit (OpCodes.Ldarg_0);
  763. Emit (OpCodes.Ldfld, fld);
  764. }
  765. Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { fld.FieldType }));
  766. }
  767. public virtual void EmitWriteLine (LocalBuilder localBuilder)
  768. {
  769. if (localBuilder == null)
  770. throw new ArgumentNullException ("localBuilder");
  771. if (localBuilder.LocalType is TypeBuilder)
  772. throw new ArgumentException ("Output streams do not support TypeBuilders.");
  773. // The MS implementation does not check for valuetypes here but it
  774. // should.
  775. Emit (OpCodes.Ldloc, localBuilder);
  776. Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { localBuilder.LocalType }));
  777. }
  778. public virtual void EmitWriteLine (string value)
  779. {
  780. Emit (OpCodes.Ldstr, value);
  781. Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { typeof(string)}));
  782. }
  783. public virtual void EndExceptionBlock ()
  784. {
  785. if (open_blocks == null)
  786. open_blocks = new Stack (defaultExceptionStackSize);
  787. if (open_blocks.Count <= 0)
  788. throw new NotSupportedException ("Not in an exception block");
  789. if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START)
  790. throw new InvalidOperationException ("Incorrect code generation for exception block.");
  791. InternalEndClause ();
  792. MarkLabel (ex_handlers [cur_block].end);
  793. ex_handlers [cur_block].End (code_len);
  794. ex_handlers [cur_block].Debug (cur_block);
  795. //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
  796. open_blocks.Pop ();
  797. if (open_blocks.Count > 0)
  798. cur_block = (int)open_blocks.Peek ();
  799. //Console.WriteLine ("curblock restored to {0}", cur_block);
  800. //throw new NotImplementedException ();
  801. }
  802. public virtual void EndScope ()
  803. { }
  804. public virtual void MarkLabel (Label loc)
  805. {
  806. if (loc.label < 0 || loc.label >= num_labels)
  807. throw new System.ArgumentException ("The label is not valid");
  808. if (labels [loc.label].addr >= 0)
  809. throw new System.ArgumentException ("The label was already defined");
  810. labels [loc.label].addr = code_len;
  811. if (labels [loc.label].maxStack > cur_stack)
  812. cur_stack = labels [loc.label].maxStack;
  813. }
  814. public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
  815. int startColumn, int endLine, int endColumn)
  816. {
  817. if (currentSequence == null || currentSequence.Document != document) {
  818. if (sequencePointLists == null)
  819. sequencePointLists = new ArrayList ();
  820. currentSequence = new SequencePointList (document);
  821. sequencePointLists.Add (currentSequence);
  822. }
  823. currentSequence.AddSequencePoint (code_len, startLine, startColumn, endLine, endColumn);
  824. }
  825. internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
  826. {
  827. if (sequencePointLists != null) {
  828. SequencePointList first = (SequencePointList) sequencePointLists [0];
  829. SequencePointList last = (SequencePointList) sequencePointLists [sequencePointLists.Count - 1];
  830. symbolWriter.SetMethodSourceRange (first.Document, first.StartLine, first.StartColumn, last.Document, last.EndLine, last.EndColumn);
  831. foreach (SequencePointList list in sequencePointLists)
  832. symbolWriter.DefineSequencePoints (list.Document, list.GetOffsets(), list.GetLines(), list.GetColumns(), list.GetEndLines(), list.GetEndColumns());
  833. if (locals != null) {
  834. foreach (LocalBuilder local in locals) {
  835. if (local.Name != null && local.Name.Length > 0) {
  836. SignatureHelper sighelper = SignatureHelper.GetLocalVarSigHelper (module);
  837. sighelper.AddArgument (local.LocalType);
  838. byte[] signature = sighelper.GetSignature ();
  839. symbolWriter.DefineLocalVariable (local.Name, FieldAttributes.Public, signature, SymAddressKind.ILOffset, local.position, 0, 0, local.StartOffset, local.EndOffset);
  840. }
  841. }
  842. }
  843. sequencePointLists = null;
  844. }
  845. }
  846. internal bool HasDebugInfo
  847. {
  848. get { return sequencePointLists != null; }
  849. }
  850. public virtual void ThrowException (Type excType)
  851. {
  852. if (excType == null)
  853. throw new ArgumentNullException ("excType");
  854. if (! ((excType == typeof (Exception)) ||
  855. excType.IsSubclassOf (typeof (Exception))))
  856. throw new ArgumentException ("Type should be an exception type", "excType");
  857. ConstructorInfo ctor = excType.GetConstructor (Type.EmptyTypes);
  858. if (ctor == null)
  859. throw new ArgumentException ("Type should have a default constructor", "excType");
  860. Emit (OpCodes.Newobj, ctor);
  861. Emit (OpCodes.Throw);
  862. }
  863. [MonoTODO("Not implemented")]
  864. public virtual void UsingNamespace (String usingNamespace)
  865. {
  866. throw new NotImplementedException ();
  867. }
  868. internal void label_fixup ()
  869. {
  870. for (int i = 0; i < num_fixups; ++i) {
  871. if (labels [fixups [i].label_idx].addr < 0)
  872. throw new ArgumentException ("Label not marked");
  873. // Diff is the offset from the end of the jump instruction to the address of the label
  874. int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
  875. if (fixups [i].offset == 1) {
  876. code [fixups [i].pos] = (byte)((sbyte) diff);
  877. } else {
  878. int old_cl = code_len;
  879. code_len = fixups [i].pos;
  880. emit_int (diff);
  881. code_len = old_cl;
  882. }
  883. }
  884. }
  885. // Still used by symbolwriter
  886. [Obsolete ("Use ILOffset", true)]
  887. internal static int Mono_GetCurrentOffset (ILGenerator ig)
  888. {
  889. return ig.code_len;
  890. }
  891. #if NET_4_0
  892. public
  893. #else
  894. internal
  895. #endif
  896. virtual int ILOffset {
  897. get { return code_len; }
  898. }
  899. void _ILGenerator.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
  900. {
  901. throw new NotImplementedException ();
  902. }
  903. void _ILGenerator.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
  904. {
  905. throw new NotImplementedException ();
  906. }
  907. void _ILGenerator.GetTypeInfoCount (out uint pcTInfo)
  908. {
  909. throw new NotImplementedException ();
  910. }
  911. void _ILGenerator.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
  912. {
  913. throw new NotImplementedException ();
  914. }
  915. }
  916. internal class SequencePointList
  917. {
  918. ISymbolDocumentWriter doc;
  919. SequencePoint[] points;
  920. int count;
  921. const int arrayGrow = 10;
  922. public SequencePointList (ISymbolDocumentWriter doc)
  923. {
  924. this.doc = doc;
  925. }
  926. public ISymbolDocumentWriter Document {
  927. get { return doc; }
  928. }
  929. public int[] GetOffsets()
  930. {
  931. int[] data = new int [count];
  932. for (int n=0; n<count; n++) data [n] = points[n].Offset;
  933. return data;
  934. }
  935. public int[] GetLines()
  936. {
  937. int[] data = new int [count];
  938. for (int n=0; n<count; n++) data [n] = points[n].Line;
  939. return data;
  940. }
  941. public int[] GetColumns()
  942. {
  943. int[] data = new int [count];
  944. for (int n=0; n<count; n++) data [n] = points[n].Col;
  945. return data;
  946. }
  947. public int[] GetEndLines()
  948. {
  949. int[] data = new int [count];
  950. for (int n=0; n<count; n++) data [n] = points[n].EndLine;
  951. return data;
  952. }
  953. public int[] GetEndColumns()
  954. {
  955. int[] data = new int [count];
  956. for (int n=0; n<count; n++) data [n] = points[n].EndCol;
  957. return data;
  958. }
  959. public int StartLine {
  960. get { return points[0].Line; }
  961. }
  962. public int EndLine {
  963. get { return points[count - 1].Line; }
  964. }
  965. public int StartColumn {
  966. get { return points[0].Col; }
  967. }
  968. public int EndColumn {
  969. get { return points[count - 1].Col; }
  970. }
  971. public void AddSequencePoint (int offset, int line, int col, int endLine, int endCol)
  972. {
  973. SequencePoint s = new SequencePoint ();
  974. s.Offset = offset;
  975. s.Line = line;
  976. s.Col = col;
  977. s.EndLine = endLine;
  978. s.EndCol = endCol;
  979. if (points == null) {
  980. points = new SequencePoint [arrayGrow];
  981. } else if (count >= points.Length) {
  982. SequencePoint[] temp = new SequencePoint [count + arrayGrow];
  983. Array.Copy (points, temp, points.Length);
  984. points = temp;
  985. }
  986. points [count] = s;
  987. count++;
  988. }
  989. }
  990. struct SequencePoint {
  991. public int Offset;
  992. public int Line;
  993. public int Col;
  994. public int EndLine;
  995. public int EndCol;
  996. }
  997. }