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