ILGenerator.cs 36 KB

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