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