1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 8 using Internal.IL; 9 using Internal.TypeSystem; 10 11 using Debug = System.Diagnostics.Debug; 12 13 namespace Internal.IL.Stubs 14 { 15 public class ILCodeStream 16 { 17 private struct LabelAndOffset 18 { 19 public readonly ILCodeLabel Label; 20 public readonly int Offset; LabelAndOffsetInternal.IL.Stubs.ILCodeStream.LabelAndOffset21 public LabelAndOffset(ILCodeLabel label, int offset) 22 { 23 Label = label; 24 Offset = offset; 25 } 26 } 27 28 internal byte[] _instructions; 29 internal int _length; 30 internal int _startOffsetForLinking; 31 internal ArrayBuilder<ILSequencePoint> _sequencePoints; 32 33 private ArrayBuilder<LabelAndOffset> _offsetsNeedingPatching; 34 35 private ILEmitter _emitter; 36 ILCodeStream(ILEmitter emitter)37 internal ILCodeStream(ILEmitter emitter) 38 { 39 _instructions = Array.Empty<byte>(); 40 _startOffsetForLinking = -1; 41 _emitter = emitter; 42 } 43 EmitByte(byte b)44 private void EmitByte(byte b) 45 { 46 if (_instructions.Length == _length) 47 Array.Resize<byte>(ref _instructions, 2 * _instructions.Length + 10); 48 _instructions[_length++] = b; 49 } 50 EmitUInt16(ushort value)51 private void EmitUInt16(ushort value) 52 { 53 EmitByte((byte)value); 54 EmitByte((byte)(value >> 8)); 55 } 56 EmitUInt32(int value)57 private void EmitUInt32(int value) 58 { 59 EmitByte((byte)value); 60 EmitByte((byte)(value >> 8)); 61 EmitByte((byte)(value >> 16)); 62 EmitByte((byte)(value >> 24)); 63 } 64 Emit(ILOpcode opcode)65 public void Emit(ILOpcode opcode) 66 { 67 if ((int)opcode > 0x100) 68 EmitByte((byte)ILOpcode.prefix1); 69 EmitByte((byte)opcode); 70 } 71 Emit(ILOpcode opcode, ILToken token)72 public void Emit(ILOpcode opcode, ILToken token) 73 { 74 Emit(opcode); 75 EmitUInt32((int)token); 76 } 77 EmitLdc(int value)78 public void EmitLdc(int value) 79 { 80 if (-1 <= value && value <= 8) 81 { 82 Emit((ILOpcode)(ILOpcode.ldc_i4_0 + value)); 83 } 84 else if (value == (sbyte)value) 85 { 86 Emit(ILOpcode.ldc_i4_s); 87 EmitByte((byte)value); 88 } 89 else 90 { 91 Emit(ILOpcode.ldc_i4); 92 EmitUInt32(value); 93 } 94 } 95 EmitLdArg(int index)96 public void EmitLdArg(int index) 97 { 98 if (index < 4) 99 { 100 Emit((ILOpcode)(ILOpcode.ldarg_0 + index)); 101 } 102 else 103 { 104 Emit(ILOpcode.ldarg); 105 EmitUInt16((ushort)index); 106 } 107 } 108 EmitLdArga(int index)109 public void EmitLdArga(int index) 110 { 111 if (index < 0x100) 112 { 113 Emit(ILOpcode.ldarga_s); 114 EmitByte((byte)index); 115 } 116 else 117 { 118 Emit(ILOpcode.ldarga); 119 EmitUInt16((ushort)index); 120 } 121 } 122 EmitLdLoc(ILLocalVariable variable)123 public void EmitLdLoc(ILLocalVariable variable) 124 { 125 int index = (int)variable; 126 127 if (index < 4) 128 { 129 Emit((ILOpcode)(ILOpcode.ldloc_0 + index)); 130 } 131 else if (index < 0x100) 132 { 133 Emit(ILOpcode.ldloc_s); 134 EmitByte((byte)index); 135 } 136 else 137 { 138 Emit(ILOpcode.ldloc); 139 EmitUInt16((ushort)index); 140 } 141 } 142 EmitLdLoca(ILLocalVariable variable)143 public void EmitLdLoca(ILLocalVariable variable) 144 { 145 int index = (int)variable; 146 147 if (index < 0x100) 148 { 149 Emit(ILOpcode.ldloca_s); 150 EmitByte((byte)index); 151 } 152 else 153 { 154 Emit(ILOpcode.ldloca); 155 EmitUInt16((ushort)index); 156 } 157 } 158 EmitStLoc(ILLocalVariable variable)159 public void EmitStLoc(ILLocalVariable variable) 160 { 161 int index = (int)variable; 162 163 if (index < 4) 164 { 165 Emit((ILOpcode)(ILOpcode.stloc_0 + index)); 166 } 167 else if (index < 0x100) 168 { 169 Emit(ILOpcode.stloc_s); 170 EmitByte((byte)index); 171 } 172 else 173 { 174 Emit(ILOpcode.stloc); 175 EmitUInt16((ushort)index); 176 } 177 } 178 Emit(ILOpcode opcode, ILCodeLabel label)179 public void Emit(ILOpcode opcode, ILCodeLabel label) 180 { 181 Debug.Assert(opcode == ILOpcode.br || opcode == ILOpcode.brfalse || 182 opcode == ILOpcode.brtrue || opcode == ILOpcode.beq || 183 opcode == ILOpcode.bge || opcode == ILOpcode.bgt || 184 opcode == ILOpcode.ble || opcode == ILOpcode.blt || 185 opcode == ILOpcode.bne_un || opcode == ILOpcode.bge_un || 186 opcode == ILOpcode.bgt_un || opcode == ILOpcode.ble_un || 187 opcode == ILOpcode.blt_un || opcode == ILOpcode.leave); 188 189 Emit(opcode); 190 _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length)); 191 EmitUInt32(4); 192 } 193 EmitSwitch(ILCodeLabel[] labels)194 public void EmitSwitch(ILCodeLabel[] labels) 195 { 196 Emit(ILOpcode.switch_); 197 EmitUInt32(labels.Length); 198 199 int remainingBytes = labels.Length * 4; 200 foreach (var label in labels) 201 { 202 _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length)); 203 EmitUInt32(remainingBytes); 204 remainingBytes -= 4; 205 } 206 } 207 EmitUnaligned()208 public void EmitUnaligned() 209 { 210 Emit(ILOpcode.unaligned); 211 EmitByte(1); 212 } 213 EmitLdInd(TypeDesc type)214 public void EmitLdInd(TypeDesc type) 215 { 216 switch (type.UnderlyingType.Category) 217 { 218 case TypeFlags.Byte: 219 case TypeFlags.SByte: 220 case TypeFlags.Boolean: 221 Emit(ILOpcode.ldind_i1); 222 break; 223 case TypeFlags.Char: 224 case TypeFlags.UInt16: 225 case TypeFlags.Int16: 226 Emit(ILOpcode.ldind_i2); 227 break; 228 case TypeFlags.UInt32: 229 case TypeFlags.Int32: 230 Emit(ILOpcode.ldind_i4); 231 break; 232 case TypeFlags.UInt64: 233 case TypeFlags.Int64: 234 Emit(ILOpcode.ldind_i8); 235 break; 236 case TypeFlags.Single: 237 Emit(ILOpcode.ldind_r4); 238 break; 239 case TypeFlags.Double: 240 Emit(ILOpcode.ldind_r8); 241 break; 242 case TypeFlags.IntPtr: 243 case TypeFlags.UIntPtr: 244 case TypeFlags.Pointer: 245 case TypeFlags.FunctionPointer: 246 Emit(ILOpcode.ldind_i); 247 break; 248 case TypeFlags.Array: 249 case TypeFlags.SzArray: 250 case TypeFlags.Class: 251 case TypeFlags.Interface: 252 Emit(ILOpcode.ldind_ref); 253 break; 254 case TypeFlags.ValueType: 255 case TypeFlags.Nullable: 256 Emit(ILOpcode.ldobj, _emitter.NewToken(type)); 257 break; 258 default: 259 Debug.Fail("Unexpected TypeDesc category"); 260 break; 261 } 262 } EmitStInd(TypeDesc type)263 public void EmitStInd(TypeDesc type) 264 { 265 switch (type.UnderlyingType.Category) 266 { 267 case TypeFlags.Byte: 268 case TypeFlags.SByte: 269 case TypeFlags.Boolean: 270 Emit(ILOpcode.stind_i1); 271 break; 272 case TypeFlags.Char: 273 case TypeFlags.UInt16: 274 case TypeFlags.Int16: 275 Emit(ILOpcode.stind_i2); 276 break; 277 case TypeFlags.UInt32: 278 case TypeFlags.Int32: 279 Emit(ILOpcode.stind_i4); 280 break; 281 case TypeFlags.UInt64: 282 case TypeFlags.Int64: 283 Emit(ILOpcode.stind_i8); 284 break; 285 case TypeFlags.Single: 286 Emit(ILOpcode.stind_r4); 287 break; 288 case TypeFlags.Double: 289 Emit(ILOpcode.stind_r8); 290 break; 291 case TypeFlags.IntPtr: 292 case TypeFlags.UIntPtr: 293 case TypeFlags.Pointer: 294 case TypeFlags.FunctionPointer: 295 Emit(ILOpcode.stind_i); 296 break; 297 case TypeFlags.Array: 298 case TypeFlags.SzArray: 299 case TypeFlags.Class: 300 case TypeFlags.Interface: 301 Emit(ILOpcode.stind_ref); 302 break; 303 case TypeFlags.ValueType: 304 case TypeFlags.Nullable: 305 Emit(ILOpcode.stobj, _emitter.NewToken(type)); 306 break; 307 default: 308 Debug.Fail("Unexpected TypeDesc category"); 309 break; 310 } 311 } 312 EmitStElem(TypeDesc type)313 public void EmitStElem(TypeDesc type) 314 { 315 switch (type.UnderlyingType.Category) 316 { 317 case TypeFlags.Byte: 318 case TypeFlags.SByte: 319 case TypeFlags.Boolean: 320 Emit(ILOpcode.stelem_i1); 321 break; 322 case TypeFlags.Char: 323 case TypeFlags.UInt16: 324 case TypeFlags.Int16: 325 Emit(ILOpcode.stelem_i2); 326 break; 327 case TypeFlags.UInt32: 328 case TypeFlags.Int32: 329 Emit(ILOpcode.stelem_i4); 330 break; 331 case TypeFlags.UInt64: 332 case TypeFlags.Int64: 333 Emit(ILOpcode.stelem_i8); 334 break; 335 case TypeFlags.Single: 336 Emit(ILOpcode.stelem_r4); 337 break; 338 case TypeFlags.Double: 339 Emit(ILOpcode.stelem_r8); 340 break; 341 case TypeFlags.IntPtr: 342 case TypeFlags.UIntPtr: 343 case TypeFlags.Pointer: 344 case TypeFlags.FunctionPointer: 345 Emit(ILOpcode.stelem_i); 346 break; 347 case TypeFlags.Array: 348 case TypeFlags.SzArray: 349 case TypeFlags.Class: 350 case TypeFlags.Interface: 351 Emit(ILOpcode.stelem_ref); 352 break; 353 case TypeFlags.ValueType: 354 case TypeFlags.Nullable: 355 Emit(ILOpcode.stelem, _emitter.NewToken(type)); 356 break; 357 default: 358 Debug.Fail("Unexpected TypeDesc category"); 359 break; 360 } 361 } 362 EmitLdElem(TypeDesc type)363 public void EmitLdElem(TypeDesc type) 364 { 365 switch (type.UnderlyingType.Category) 366 { 367 case TypeFlags.Byte: 368 case TypeFlags.SByte: 369 case TypeFlags.Boolean: 370 Emit(ILOpcode.ldelem_i1); 371 break; 372 case TypeFlags.Char: 373 case TypeFlags.UInt16: 374 case TypeFlags.Int16: 375 Emit(ILOpcode.ldelem_i2); 376 break; 377 case TypeFlags.UInt32: 378 case TypeFlags.Int32: 379 Emit(ILOpcode.ldelem_i4); 380 break; 381 case TypeFlags.UInt64: 382 case TypeFlags.Int64: 383 Emit(ILOpcode.ldelem_i8); 384 break; 385 case TypeFlags.Single: 386 Emit(ILOpcode.ldelem_r4); 387 break; 388 case TypeFlags.Double: 389 Emit(ILOpcode.ldelem_r8); 390 break; 391 case TypeFlags.IntPtr: 392 case TypeFlags.UIntPtr: 393 case TypeFlags.Pointer: 394 case TypeFlags.FunctionPointer: 395 Emit(ILOpcode.ldelem_i); 396 break; 397 case TypeFlags.Array: 398 case TypeFlags.SzArray: 399 case TypeFlags.Class: 400 case TypeFlags.Interface: 401 Emit(ILOpcode.ldelem_ref); 402 break; 403 case TypeFlags.ValueType: 404 case TypeFlags.Nullable: 405 Emit(ILOpcode.ldelem, _emitter.NewToken(type)); 406 break; 407 default: 408 Debug.Fail("Unexpected TypeDesc category"); 409 break; 410 } 411 } 412 EmitLabel(ILCodeLabel label)413 public void EmitLabel(ILCodeLabel label) 414 { 415 label.Place(this, _length); 416 } 417 PatchLabels()418 internal void PatchLabels() 419 { 420 for (int i = 0; i < _offsetsNeedingPatching.Count; i++) 421 { 422 LabelAndOffset patch = _offsetsNeedingPatching[i]; 423 424 Debug.Assert(patch.Label.IsPlaced); 425 Debug.Assert(_startOffsetForLinking > -1); 426 427 int offset = patch.Offset; 428 429 int delta = _instructions[offset + 3] << 24 | 430 _instructions[offset + 2] << 16 | 431 _instructions[offset + 1] << 8 | 432 _instructions[offset]; 433 434 int value = patch.Label.AbsoluteOffset - _startOffsetForLinking - patch.Offset - delta; 435 436 _instructions[offset] = (byte)value; 437 _instructions[offset + 1] = (byte)(value >> 8); 438 _instructions[offset + 2] = (byte)(value >> 16); 439 _instructions[offset + 3] = (byte)(value >> 24); 440 } 441 } 442 DefineSequencePoint(string document, int lineNumber)443 public void DefineSequencePoint(string document, int lineNumber) 444 { 445 // Last sequence point defined for this offset wins. 446 if (_sequencePoints.Count > 0 && _sequencePoints[_sequencePoints.Count - 1].Offset == _length) 447 { 448 _sequencePoints[_sequencePoints.Count - 1] = new ILSequencePoint(_length, document, lineNumber); 449 } 450 else 451 { 452 _sequencePoints.Add(new ILSequencePoint(_length, document, lineNumber)); 453 } 454 } 455 } 456 457 /// <summary> 458 /// Represent a token. Use one of the overloads of <see cref="ILEmitter.NewToken"/> 459 /// to create a new token. 460 /// </summary> 461 public enum ILToken { } 462 463 /// <summary> 464 /// Represents a local variable. Use <see cref="ILEmitter.NewLocal"/> to create a new local variable. 465 /// </summary> 466 public enum ILLocalVariable { } 467 468 public class ILStubMethodIL : MethodIL 469 { 470 private readonly byte[] _ilBytes; 471 private readonly LocalVariableDefinition[] _locals; 472 private readonly Object[] _tokens; 473 private readonly MethodDesc _method; 474 private readonly MethodDebugInformation _debugInformation; 475 476 private const int MaxStackNotSet = -1; 477 private int _maxStack; 478 ILStubMethodIL(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, MethodDebugInformation debugInfo = null)479 public ILStubMethodIL(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, MethodDebugInformation debugInfo = null) 480 { 481 _ilBytes = ilBytes; 482 _locals = locals; 483 _tokens = tokens; 484 _method = owningMethod; 485 _maxStack = MaxStackNotSet; 486 487 if (debugInfo == null) 488 debugInfo = MethodDebugInformation.None; 489 _debugInformation = debugInfo; 490 } 491 ILStubMethodIL(ILStubMethodIL methodIL)492 public ILStubMethodIL(ILStubMethodIL methodIL) 493 { 494 _ilBytes = methodIL._ilBytes; 495 _locals = methodIL._locals; 496 _tokens = methodIL._tokens; 497 _method = methodIL._method; 498 _debugInformation = methodIL._debugInformation; 499 _maxStack = methodIL._maxStack; 500 } 501 502 public override MethodDesc OwningMethod 503 { 504 get 505 { 506 return _method; 507 } 508 } 509 GetILBytes()510 public override byte[] GetILBytes() 511 { 512 return _ilBytes; 513 } 514 GetDebugInfo()515 public override MethodDebugInformation GetDebugInfo() 516 { 517 return _debugInformation; 518 } 519 520 public override int MaxStack 521 { 522 get 523 { 524 if (_maxStack == MaxStackNotSet) 525 _maxStack = this.ComputeMaxStack(); 526 return _maxStack; 527 } 528 } 529 GetExceptionRegions()530 public override ILExceptionRegion[] GetExceptionRegions() 531 { 532 return Array.Empty<ILExceptionRegion>(); 533 } 534 public override bool IsInitLocals 535 { 536 get 537 { 538 return true; 539 } 540 } 541 GetLocals()542 public override LocalVariableDefinition[] GetLocals() 543 { 544 return _locals; 545 } GetObject(int token)546 public override Object GetObject(int token) 547 { 548 return _tokens[(token & 0xFFFFFF) - 1]; 549 } 550 } 551 552 // Workaround for places that emit IL that doesn't conform to the ECMA-335 CIL stack requirements. 553 // https://github.com/dotnet/corert/issues/5152 554 // This class and all references to it should be deleted when the issue is fixed. 555 // Do not add new references to this. 556 public class ILStubMethodILWithNonConformingStack : ILStubMethodIL 557 { ILStubMethodILWithNonConformingStack(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, MethodDebugInformation debugInfo)558 public ILStubMethodILWithNonConformingStack(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, MethodDebugInformation debugInfo) 559 : base(owningMethod, ilBytes, locals, tokens, debugInfo) 560 { 561 } 562 ILStubMethodILWithNonConformingStack(ILStubMethodIL methodIL)563 public ILStubMethodILWithNonConformingStack(ILStubMethodIL methodIL) 564 : base(methodIL) 565 { 566 } 567 568 public override int MaxStack => GetILBytes().Length; 569 } 570 571 public class ILCodeLabel 572 { 573 private ILCodeStream _codeStream; 574 private int _offsetWithinCodeStream; 575 576 internal bool IsPlaced 577 { 578 get 579 { 580 return _codeStream != null; 581 } 582 } 583 584 internal int AbsoluteOffset 585 { 586 get 587 { 588 Debug.Assert(IsPlaced); 589 Debug.Assert(_codeStream._startOffsetForLinking >= 0); 590 return _codeStream._startOffsetForLinking + _offsetWithinCodeStream; 591 } 592 } 593 ILCodeLabel()594 internal ILCodeLabel() 595 { 596 } 597 Place(ILCodeStream codeStream, int offsetWithinCodeStream)598 internal void Place(ILCodeStream codeStream, int offsetWithinCodeStream) 599 { 600 Debug.Assert(!IsPlaced); 601 _codeStream = codeStream; 602 _offsetWithinCodeStream = offsetWithinCodeStream; 603 } 604 } 605 606 public class ILEmitter 607 { 608 private ArrayBuilder<ILCodeStream> _codeStreams; 609 private ArrayBuilder<LocalVariableDefinition> _locals; 610 private ArrayBuilder<Object> _tokens; 611 ILEmitter()612 public ILEmitter() 613 { 614 } 615 NewCodeStream()616 public ILCodeStream NewCodeStream() 617 { 618 ILCodeStream stream = new ILCodeStream(this); 619 _codeStreams.Add(stream); 620 return stream; 621 } 622 NewToken(Object value, int tokenType)623 private ILToken NewToken(Object value, int tokenType) 624 { 625 Debug.Assert(value != null); 626 _tokens.Add(value); 627 return (ILToken)(_tokens.Count | tokenType); 628 } 629 NewToken(TypeDesc value)630 public ILToken NewToken(TypeDesc value) 631 { 632 return NewToken(value, 0x01000000); 633 } 634 NewToken(MethodDesc value)635 public ILToken NewToken(MethodDesc value) 636 { 637 return NewToken(value, 0x0a000000); 638 } 639 NewToken(FieldDesc value)640 public ILToken NewToken(FieldDesc value) 641 { 642 return NewToken(value, 0x0a000000); 643 } 644 NewToken(string value)645 public ILToken NewToken(string value) 646 { 647 return NewToken(value, 0x70000000); 648 } 649 NewToken(MethodSignature value)650 public ILToken NewToken(MethodSignature value) 651 { 652 return NewToken(value, 0x11000000); 653 } 654 NewLocal(TypeDesc localType, bool isPinned = false)655 public ILLocalVariable NewLocal(TypeDesc localType, bool isPinned = false) 656 { 657 int index = _locals.Count; 658 _locals.Add(new LocalVariableDefinition(localType, isPinned)); 659 return (ILLocalVariable)index; 660 } 661 NewCodeLabel()662 public ILCodeLabel NewCodeLabel() 663 { 664 var newLabel = new ILCodeLabel(); 665 return newLabel; 666 } 667 Link(MethodDesc owningMethod, bool nonConformingStackWorkaround = false)668 public MethodIL Link(MethodDesc owningMethod, bool nonConformingStackWorkaround = false) 669 { 670 int totalLength = 0; 671 int numSequencePoints = 0; 672 673 for (int i = 0; i < _codeStreams.Count; i++) 674 { 675 ILCodeStream ilCodeStream = _codeStreams[i]; 676 ilCodeStream._startOffsetForLinking = totalLength; 677 totalLength += ilCodeStream._length; 678 numSequencePoints += ilCodeStream._sequencePoints.Count; 679 } 680 681 byte[] ilInstructions = new byte[totalLength]; 682 int copiedLength = 0; 683 for (int i = 0; i < _codeStreams.Count; i++) 684 { 685 ILCodeStream ilCodeStream = _codeStreams[i]; 686 ilCodeStream.PatchLabels(); 687 Array.Copy(ilCodeStream._instructions, 0, ilInstructions, copiedLength, ilCodeStream._length); 688 copiedLength += ilCodeStream._length; 689 } 690 691 MethodDebugInformation debugInfo = null; 692 if (numSequencePoints > 0) 693 { 694 ILSequencePoint[] sequencePoints = new ILSequencePoint[numSequencePoints]; 695 int copiedSequencePointLength = 0; 696 for (int codeStreamIndex = 0; codeStreamIndex < _codeStreams.Count; codeStreamIndex++) 697 { 698 ILCodeStream ilCodeStream = _codeStreams[codeStreamIndex]; 699 700 for (int sequencePointIndex = 0; sequencePointIndex < ilCodeStream._sequencePoints.Count; sequencePointIndex++) 701 { 702 ILSequencePoint sequencePoint = ilCodeStream._sequencePoints[sequencePointIndex]; 703 sequencePoints[copiedSequencePointLength] = new ILSequencePoint( 704 ilCodeStream._startOffsetForLinking + sequencePoint.Offset, 705 sequencePoint.Document, 706 sequencePoint.LineNumber); 707 copiedSequencePointLength++; 708 } 709 } 710 711 debugInfo = new EmittedMethodDebugInformation(sequencePoints); 712 } 713 714 ILStubMethodIL result; 715 if (nonConformingStackWorkaround) 716 { 717 // nonConformingStackWorkaround is a workaround for https://github.com/dotnet/corert/issues/5152 718 result = new ILStubMethodILWithNonConformingStack(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), debugInfo); 719 } 720 else 721 { 722 result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), debugInfo); 723 result.CheckStackBalance(); 724 } 725 return result; 726 } 727 728 private class EmittedMethodDebugInformation : MethodDebugInformation 729 { 730 private readonly ILSequencePoint[] _sequencePoints; 731 EmittedMethodDebugInformation(ILSequencePoint[] sequencePoints)732 public EmittedMethodDebugInformation(ILSequencePoint[] sequencePoints) 733 { 734 _sequencePoints = sequencePoints; 735 } 736 GetSequencePoints()737 public override IEnumerable<ILSequencePoint> GetSequencePoints() 738 { 739 return _sequencePoints; 740 } 741 } 742 } 743 744 public abstract partial class ILStubMethod : MethodDesc 745 { EmitIL()746 public abstract MethodIL EmitIL(); 747 HasCustomAttribute(string attributeNamespace, string attributeName)748 public override bool HasCustomAttribute(string attributeNamespace, string attributeName) 749 { 750 return false; 751 } 752 } 753 } 754