10using System.Buffers.Binary;
11using System.Diagnostics;
12using System.Diagnostics.Contracts;
13using System.Diagnostics.SymbolStore;
15using System.Runtime.InteropServices;
19 internal class ILGenerator
23 private const int DefaultSize = 16;
24 private const int DefaultFixupArraySize = 8;
25 private const int DefaultLabelArraySize = 4;
26 private const int DefaultExceptionArraySize = 2;
29 #region Internal Statics
30 internal static T[] EnlargeArray<T>(T[] incoming)
32 return EnlargeArray(incoming, incoming.Length * 2);
35 internal static T[] EnlargeArray<T>(T[] incoming,
int requiredSize)
37 Debug.Assert(incoming !=
null);
39 T[] temp =
new T[requiredSize];
40 Array.Copy(incoming, temp, incoming.Length);
46 #region Internal Data Members
48 private byte[] m_ILStream;
50 private __LabelInfo[]? m_labelList;
51 private int m_labelCount;
53 private __FixupData[]? m_fixupData;
55 private int m_fixupCount;
57 private int[]? m_RelocFixupList;
58 private int m_RelocFixupCount;
60 private int m_exceptionCount;
61 private int m_currExcStackCount;
62 private __ExceptionInfo[]? m_exceptions;
63 private __ExceptionInfo[]? m_currExcStack;
65 internal ScopeTree m_ScopeTree;
66 internal LineNumberInfo m_LineNumberInfo;
68 internal MethodBuilder m_methodBuilder;
69 internal int m_localCount;
70 internal SignatureHelper m_localSignature;
72 private int m_curDepth;
73 private int m_targetDepth;
74 private int m_maxDepth;
78 private long m_depthAdjustment;
80 internal int CurrExcStackCount => m_currExcStackCount;
82 internal __ExceptionInfo[]? CurrExcStack => m_currExcStack;
89 internal ILGenerator(MethodBuilder methodBuilder) : this(methodBuilder, 64)
93 internal ILGenerator(MethodBuilder methodBuilder,
int size)
95 Debug.Assert(methodBuilder !=
null);
96 Debug.Assert(methodBuilder is MethodBuilder);
98 m_ILStream =
new byte[Math.Max(size, DefaultSize)];
101 m_ScopeTree =
new ScopeTree();
102 m_LineNumberInfo =
new LineNumberInfo();
103 m_methodBuilder = methodBuilder;
106 m_localSignature = SignatureHelper.GetLocalVarSigHelper(methodBuilder.ModuleBuilder);
111 #region Internal Members
112 internal virtual void RecordTokenFixup()
114 if (m_RelocFixupList ==
null)
116 m_RelocFixupList =
new int[DefaultFixupArraySize];
118 else if (m_RelocFixupList.Length <= m_RelocFixupCount)
120 m_RelocFixupList = EnlargeArray(m_RelocFixupList);
123 m_RelocFixupList[m_RelocFixupCount++] = m_length;
126 internal void InternalEmit(OpCode opcode)
128 short opcodeValue = opcode.Value;
129 if (opcode.Size != 1)
131 BinaryPrimitives.WriteInt16BigEndian(m_ILStream.AsSpan(m_length), opcodeValue);
136 m_ILStream[m_length++] = (byte)opcodeValue;
139 UpdateStackSize(opcode, opcode.StackChange());
142 [MethodImpl(MethodImplOptions.AggressiveInlining)]
143 internal void UpdateStackSize(OpCode opcode,
int stackchange)
157 m_curDepth += stackchange;
161 m_depthAdjustment -= m_curDepth;
164 else if (m_maxDepth < m_curDepth)
165 m_maxDepth = m_curDepth;
166 Debug.Assert(m_depthAdjustment >= 0);
167 Debug.Assert(m_curDepth >= 0);
170 m_targetDepth = m_curDepth;
173 if (opcode.EndsUncondJmpBlk())
177 private int GetMethodToken(
MethodBase method,
Type[]? optionalParameterTypes,
bool useMethodDef)
180 if (optionalParameterTypes ==
null || optionalParameterTypes.Length == 0)
181 return m_methodBuilder.ModuleBuilder.GetMethodTokenForIL(mi).Token;
183 return m_methodBuilder.ModuleBuilder.__GetMethodToken(mi, optionalParameterTypes,
null).Token;
186 internal SignatureHelper GetMemberRefSignature(
187 CallingConventions call,
189 Type[]? parameterTypes,
190 Type[]? optionalParameterTypes)
192 var sig = SignatureHelper.GetMethodSigHelper(m_methodBuilder.Module, call, returnType);
193 sig.AddArguments(parameterTypes,
null,
null);
194 if (optionalParameterTypes !=
null && optionalParameterTypes.Length != 0)
197 sig.AddArguments(optionalParameterTypes,
null,
null);
203 internal byte[]? BakeByteArray()
208 if (m_currExcStackCount != 0)
210 throw new ArgumentException(
"The IL Generator cannot be used while there are unclosed exceptions.");
217 byte[] newBytes =
new byte[m_length];
220 Array.Copy(m_ILStream, newBytes, m_length);
225 for (
int i = 0; i < m_fixupCount; i++)
227 __FixupData fixupData = m_fixupData![i];
228 int updateAddr = GetLabelPos(fixupData.m_fixupLabel) - (fixupData.m_fixupPos + fixupData.m_fixupInstSize);
232 if (fixupData.m_fixupInstSize == 1)
235 if (updateAddr < sbyte.MinValue || updateAddr > sbyte.MaxValue)
237 throw new NotSupportedException(
string.Format(
"Illegal one-byte branch at position: {0}. Requested branch was: {1}.", fixupData.m_fixupPos, updateAddr));
241 newBytes[fixupData.m_fixupPos] = (byte)updateAddr;
246 BinaryPrimitives.WriteInt32LittleEndian(newBytes.AsSpan(fixupData.m_fixupPos), updateAddr);
252 internal __ExceptionInfo[]? GetExceptions()
254 if (m_currExcStackCount != 0)
256 throw new NotSupportedException(
"The IL Generator cannot be used while there are unclosed exceptions.");
259 if (m_exceptionCount == 0)
264 var temp =
new __ExceptionInfo[m_exceptionCount];
265 Array.Copy(m_exceptions!, temp, m_exceptionCount);
266 SortExceptions(temp);
270 internal void EnsureCapacity(
int size)
273 if (m_length + size >= m_ILStream.Length)
275 IncreaseCapacity(size);
279 private void IncreaseCapacity(
int size)
281 byte[] temp =
new byte[Math.Max(m_ILStream.Length * 2, m_length + size)];
282 Array.Copy(m_ILStream, temp, m_ILStream.Length);
286 [MethodImpl(MethodImplOptions.AggressiveInlining)]
287 internal void PutInteger4(
int value)
289 BinaryPrimitives.WriteInt32LittleEndian(m_ILStream.AsSpan(m_length), value);
293 private int GetLabelPos(Label lbl)
300 if (index < 0 || index >= m_labelCount || m_labelList is
null)
301 throw new ArgumentException(
"Bad label in ILGenerator.");
303 int pos = m_labelList[index].m_pos;
305 throw new ArgumentException(
"Bad label content in ILGenerator.");
310 private void AddFixup(Label lbl,
int pos,
int instSize)
315 if (m_fixupData ==
null)
317 m_fixupData =
new __FixupData[DefaultFixupArraySize];
319 else if (m_fixupData.Length <= m_fixupCount)
321 m_fixupData = EnlargeArray(m_fixupData);
324 m_fixupData[m_fixupCount++] =
new __FixupData
328 m_fixupInstSize = instSize
331 int labelIndex = lbl.Id;
332 if (labelIndex < 0 || labelIndex >= m_labelCount || m_labelList is
null)
333 throw new ArgumentException(
"Bad label in ILGenerator.");
335 int depth = m_labelList[labelIndex].m_depth;
336 int targetDepth = m_targetDepth;
337 Debug.Assert(depth >= -1);
338 Debug.Assert(targetDepth >= -1);
339 if (depth < targetDepth)
344 m_depthAdjustment += targetDepth - depth;
345 m_labelList[labelIndex].m_depth = targetDepth;
349 internal int GetMaxStackSize()
352 Debug.Assert(m_depthAdjustment >= 0);
353 return (
int)Math.Min(ushort.MaxValue, m_maxDepth + m_depthAdjustment);
356 private static void SortExceptions(__ExceptionInfo[] exceptions)
362 for (
int i = 0; i < exceptions.Length; i++)
365 for (
int j = i + 1; j < exceptions.Length; j++)
367 if (exceptions[least].IsInner(exceptions[j]))
372 __ExceptionInfo temp = exceptions[i];
373 exceptions[i] = exceptions[least];
374 exceptions[least] = temp;
378 internal int[]? GetTokenFixups()
380 if (m_RelocFixupCount == 0)
382 Debug.Assert(m_RelocFixupList ==
null);
386 int[] narrowTokens =
new int[m_RelocFixupCount];
387 Array.Copy(m_RelocFixupList!, narrowTokens, m_RelocFixupCount);
392 #region Public Members
395 public void Emit(OpCode opcode)
398 InternalEmit(opcode);
401 public void Emit(OpCode opcode,
byte arg)
404 InternalEmit(opcode);
405 m_ILStream[m_length++] = arg;
408 public void Emit(OpCode opcode,
short arg)
412 InternalEmit(opcode);
413 BinaryPrimitives.WriteInt16LittleEndian(m_ILStream.AsSpan(m_length), arg);
417 public void Emit(OpCode opcode,
int arg)
420 if (opcode.Equals(OpCodes.Ldc_I4))
422 if (arg >= -1 && arg <= 8)
426 -1 => OpCodes.Ldc_I4_M1,
427 0 => OpCodes.Ldc_I4_0,
428 1 => OpCodes.Ldc_I4_1,
429 2 => OpCodes.Ldc_I4_2,
430 3 => OpCodes.Ldc_I4_3,
431 4 => OpCodes.Ldc_I4_4,
432 5 => OpCodes.Ldc_I4_5,
433 6 => OpCodes.Ldc_I4_6,
434 7 => OpCodes.Ldc_I4_7,
435 _ => OpCodes.Ldc_I4_8,
441 if (arg >= -128 && arg <= 127)
443 Emit(OpCodes.Ldc_I4_S, (sbyte)arg);
447 else if (opcode.Equals(OpCodes.Ldarg))
453 0 => OpCodes.Ldarg_0,
454 1 => OpCodes.Ldarg_1,
455 2 => OpCodes.Ldarg_2,
456 _ => OpCodes.Ldarg_3,
461 if ((uint)arg <=
byte.MaxValue)
463 Emit(OpCodes.Ldarg_S, (
byte)arg);
467 if ((uint)arg <= ushort.MaxValue)
469 Emit(OpCodes.Ldarg, (
short)arg);
473 else if (opcode.Equals(OpCodes.Ldarga))
475 if ((uint)arg <=
byte.MaxValue)
477 Emit(OpCodes.Ldarga_S, (
byte)arg);
481 if ((uint)arg <= ushort.MaxValue)
483 Emit(OpCodes.Ldarga, (
short)arg);
487 else if (opcode.Equals(OpCodes.Starg))
489 if ((uint)arg <=
byte.MaxValue)
491 Emit(OpCodes.Starg_S, (
byte)arg);
495 if ((uint)arg <= ushort.MaxValue)
497 Emit(OpCodes.Starg, (
short)arg);
504 InternalEmit(opcode);
508 public void Emit(OpCode opcode,
MethodInfo meth)
511 throw new ArgumentNullException(nameof(meth));
513 if (opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj))
515 EmitCall(opcode, meth,
null);
523 bool useMethodDef = opcode.Equals(OpCodes.Ldtoken) || opcode.Equals(OpCodes.Ldftn) || opcode.Equals(OpCodes.Ldvirtftn);
524 int tk = GetMethodToken(meth,
null, useMethodDef);
527 InternalEmit(opcode);
529 UpdateStackSize(opcode, 0);
535 public void EmitCalli(OpCode opcode, CallingConventions callingConvention,
536 Type? returnType,
Type[]? parameterTypes,
Type[]? optionalParameterTypes)
539 if (optionalParameterTypes !=
null)
541 if ((callingConvention & CallingConventions.VarArgs) == 0)
544 throw new InvalidOperationException(
"Calling convention must be VarArgs.");
548 ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.ModuleBuilder;
549 SignatureHelper sig = GetMemberRefSignature(callingConvention,
552 optionalParameterTypes);
558 if (returnType != modBuilder.Universe.System_Void)
561 if (parameterTypes !=
null)
562 stackchange -= parameterTypes.Length;
564 if (optionalParameterTypes !=
null)
565 stackchange -= optionalParameterTypes.Length;
567 if ((callingConvention & CallingConventions.HasThis) == CallingConventions.HasThis)
571 UpdateStackSize(OpCodes.Calli, stackchange);
574 PutInteger4(modBuilder.GetSignatureToken(sig).Token);
582 ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
584 if (parameterTypes !=
null)
586 cParams = parameterTypes.Length;
589 SignatureHelper sig = SignatureHelper.GetMethodSigHelper(
594 if (parameterTypes !=
null)
596 for (
int i = 0; i < cParams; i++)
598 sig.AddArgument(parameterTypes[i]);
603 if (returnType != modBuilder.Universe.System_Void)
607 if (parameterTypes !=
null)
608 stackchange -= cParams;
612 UpdateStackSize(OpCodes.Calli, stackchange);
617 PutInteger4(modBuilder.GetSignatureToken(sig).Token);
620 public void EmitCall(OpCode opcode,
MethodInfo methodInfo,
Type[]? optionalParameterTypes)
622 if (methodInfo is
null)
623 throw new ArgumentNullException(nameof(methodInfo));
625 if (!(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj)))
626 throw new ArgumentException(
"The specified opcode cannot be passed to EmitCall.", nameof(opcode));
629 int tk = GetMethodToken(methodInfo, optionalParameterTypes,
false);
632 InternalEmit(opcode);
635 if (methodInfo.ReturnType != m_methodBuilder.ModuleBuilder.Universe.System_Void)
638 Type[] parameters = methodInfo.GetParameterTypes();
639 if (parameters !=
null)
640 stackchange -= parameters.Length;
644 if (!methodInfo.IsStatic && !opcode.Equals(OpCodes.Newobj))
647 if (optionalParameterTypes !=
null)
648 stackchange -= optionalParameterTypes.Length;
649 UpdateStackSize(opcode, stackchange);
655 public void Emit(OpCode opcode, SignatureHelper signature)
657 if (signature is
null)
658 throw new ArgumentNullException(nameof(signature));
661 ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
662 int sig = modBuilder.GetSignatureToken(signature).Token;
667 InternalEmit(opcode);
674 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
676 Debug.Assert(opcode.Equals(OpCodes.Calli),
677 "Unexpected opcode encountered for StackBehaviour VarPop.");
679 stackchange -= signature.ArgumentCount;
682 UpdateStackSize(opcode, stackchange);
686 PutInteger4(tempVal);
692 throw new ArgumentNullException(nameof(con));
697 int tk = GetMethodToken(con,
null,
true);
700 InternalEmit(opcode);
704 if (opcode.StackBehaviourPush == StackBehaviour.Varpush)
707 Debug.Assert(opcode.Equals(OpCodes.Call) ||
708 opcode.Equals(OpCodes.Callvirt),
709 "Unexpected opcode encountered for StackBehaviour of VarPush.");
712 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
715 Debug.Assert(opcode.Equals(OpCodes.Call) ||
716 opcode.Equals(OpCodes.Callvirt) ||
717 opcode.Equals(OpCodes.Newobj),
718 "Unexpected opcode encountered for StackBehaviour of VarPop.");
720 Type[] parameters = con.GetParameterTypes();
721 if (parameters !=
null)
722 stackchange -= parameters.Length;
724 UpdateStackSize(opcode, stackchange);
730 public void Emit(OpCode opcode,
Type cls)
736 ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
737 bool getGenericDefinition = (opcode == OpCodes.Ldtoken && cls !=
null && cls.IsGenericTypeDefinition);
738 int tempVal = getGenericDefinition ? modBuilder.GetTypeToken(cls).Token : modBuilder.GetTypeTokenForMemberRef(cls);
741 InternalEmit(opcode);
743 PutInteger4(tempVal);
746 public void Emit(OpCode opcode,
long arg)
749 InternalEmit(opcode);
750 BinaryPrimitives.WriteInt64LittleEndian(m_ILStream.AsSpan(m_length), arg);
754 public void Emit(OpCode opcode,
float arg)
757 InternalEmit(opcode);
758 BinaryPrimitives.WriteInt32LittleEndian(m_ILStream.AsSpan(m_length), SingleToInt32Bits(arg));
767 [MethodImpl(MethodImplOptions.AggressiveInlining)]
768 static unsafe
int SingleToInt32Bits(
float value)
771 return *((
int*)&value);
773 return BitConverter.SingleToInt32Bits(value);
777 public void Emit(OpCode opcode,
double arg)
780 InternalEmit(opcode);
781 BinaryPrimitives.WriteInt64LittleEndian(m_ILStream.AsSpan(m_length), BitConverter.DoubleToInt64Bits(arg));
785 public void Emit(OpCode opcode, Label label)
799 InternalEmit(opcode);
800 if (OpCodes.TakesSingleByteArgument(opcode))
802 AddFixup(label, m_length++, 1);
806 AddFixup(label, m_length, 4);
811 public void Emit(OpCode opcode, Label[] labels)
814 throw new ArgumentNullException(nameof(labels));
822 int count = labels.Length;
824 EnsureCapacity(count * 4 + 7);
825 InternalEmit(opcode);
827 for (remaining = count * 4, i = 0; remaining > 0; remaining -= 4, i++)
829 AddFixup(labels[i], m_length, remaining);
834 public void Emit(OpCode opcode,
FieldInfo field)
836 ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
837 int tempVal = modBuilder.GetFieldToken(field).Token;
839 InternalEmit(opcode);
841 PutInteger4(tempVal);
844 public void Emit(OpCode opcode,
string str)
850 ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
851 int tempVal = modBuilder.GetStringConstant(str).Token;
853 InternalEmit(opcode);
854 PutInteger4(tempVal);
857 public void Emit(OpCode opcode, LocalBuilder local)
860 throw new ArgumentNullException(nameof(local));
863 int tempVal = local.LocalIndex;
864 if (local.Method != m_methodBuilder)
866 throw new ArgumentException(
"Local passed in does not belong to this ILGenerator.", nameof(local));
869 if (opcode.Equals(OpCodes.Ldloc))
874 opcode = OpCodes.Ldloc_0;
877 opcode = OpCodes.Ldloc_1;
880 opcode = OpCodes.Ldloc_2;
883 opcode = OpCodes.Ldloc_3;
887 opcode = OpCodes.Ldloc_S;
891 else if (opcode.Equals(OpCodes.Stloc))
896 opcode = OpCodes.Stloc_0;
899 opcode = OpCodes.Stloc_1;
902 opcode = OpCodes.Stloc_2;
905 opcode = OpCodes.Stloc_3;
909 opcode = OpCodes.Stloc_S;
913 else if (opcode.Equals(OpCodes.Ldloca))
916 opcode = OpCodes.Ldloca_S;
920 InternalEmit(opcode);
922 if (opcode.OperandType == OperandType.InlineNone)
925 if (!OpCodes.TakesSingleByteArgument(opcode))
927 BinaryPrimitives.WriteInt16LittleEndian(m_ILStream.AsSpan(m_length), (
short)tempVal);
933 if (tempVal >
byte.MaxValue)
935 throw new InvalidOperationException(
"Opcodes using a short-form index cannot address a local position over 255.");
937 m_ILStream[m_length++] = (byte)tempVal;
944 public virtual void ThrowException(
Type excType)
947 throw new ArgumentNullException(nameof(excType));
953 var con = excType.GetConstructor(
Type.EmptyTypes);
955 throw new ArgumentException(nameof(excType));
957 Emit(OpCodes.Newobj, con);
961 public Label BeginExceptionBlock()
976 m_exceptions ??=
new __ExceptionInfo[DefaultExceptionArraySize];
977 m_currExcStack ??=
new __ExceptionInfo[DefaultExceptionArraySize];
979 if (m_exceptionCount >= m_exceptions.Length)
981 m_exceptions = EnlargeArray(m_exceptions);
984 if (m_currExcStackCount >= m_currExcStack.Length)
986 m_currExcStack = EnlargeArray(m_currExcStack);
989 Label endLabel = DefineLabel(0);
990 __ExceptionInfo exceptionInfo =
new __ExceptionInfo(m_length, endLabel);
993 m_exceptions[m_exceptionCount++] = exceptionInfo;
996 m_currExcStack[m_currExcStackCount++] = exceptionInfo;
1004 public void EndExceptionBlock()
1006 if (m_currExcStackCount == 0)
1008 throw new NotSupportedException(
"Not currently in an exception block.");
1012 __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1];
1013 m_currExcStack[--m_currExcStackCount] =
null!;
1015 Label endLabel = current.GetEndLabel();
1016 int state = current.GetCurrentState();
1018 if (state == __ExceptionInfo.State_Filter ||
1019 state == __ExceptionInfo.State_Try)
1021 throw new InvalidOperationException(
"Incorrect code generation for exception block.");
1024 if (state == __ExceptionInfo.State_Catch)
1026 Emit(OpCodes.Leave, endLabel);
1028 else if (state == __ExceptionInfo.State_Finally || state == __ExceptionInfo.State_Fault)
1030 Emit(OpCodes.Endfinally);
1036 Label label = m_labelList![endLabel.GetLabelValue()].m_pos != -1
1037 ? current.m_finallyEndLabel
1042 current.Done(m_length);
1045 public void BeginExceptFilterBlock()
1049 if (m_currExcStackCount == 0)
1050 throw new NotSupportedException(
"Not currently in an exception block.");
1052 __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1];
1054 Emit(OpCodes.Leave, current.GetEndLabel());
1056 current.MarkFilterAddr(m_length);
1062 public void BeginCatchBlock(
Type? exceptionType)
1064 Debug.Assert(ModuleBuilder.IsPseudoToken(m_methodBuilder.ModuleBuilder.GetTypeTokenForMemberRef(exceptionType)) ==
false);
1068 if (m_currExcStackCount == 0)
1070 throw new NotSupportedException(
"Not currently in an exception block.");
1072 __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1];
1074 if (current.GetCurrentState() == __ExceptionInfo.State_Filter)
1076 if (exceptionType !=
null)
1078 throw new ArgumentException(
"Should not specify exception type for catch clause for filter block.");
1081 Emit(OpCodes.Endfilter);
1086 if (exceptionType is
null)
1087 throw new ArgumentNullException(nameof(exceptionType));
1089 Emit(OpCodes.Leave, current.GetEndLabel());
1092 current.MarkCatchAddr(m_length, exceptionType);
1098 public void BeginFaultBlock()
1100 if (m_currExcStackCount == 0)
1102 throw new NotSupportedException(
"Not currently in an exception block.");
1104 __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1];
1107 Emit(OpCodes.Leave, current.GetEndLabel());
1109 current.MarkFaultAddr(m_length);
1115 public void BeginFinallyBlock()
1117 if (m_currExcStackCount == 0)
1119 throw new NotSupportedException(
"Not currently in an exception block.");
1121 __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1];
1122 int state = current.GetCurrentState();
1123 Label endLabel = current.GetEndLabel();
1124 int catchEndAddr = 0;
1125 if (state != __ExceptionInfo.State_Try)
1128 Emit(OpCodes.Leave, endLabel);
1129 catchEndAddr = m_length;
1132 MarkLabel(endLabel);
1134 Label finallyEndLabel = DefineLabel(0);
1135 current.SetFinallyEndLabel(finallyEndLabel);
1138 Emit(OpCodes.Leave, finallyEndLabel);
1139 if (catchEndAddr == 0)
1140 catchEndAddr = m_length;
1141 current.MarkFinallyAddr(m_length, catchEndAddr);
1150 public Label DefineLabel()
1153 return DefineLabel(-1);
1156 private Label DefineLabel(
int depth)
1161 Debug.Assert(depth >= -1);
1164 m_labelList ??=
new __LabelInfo[DefaultLabelArraySize];
1166 if (m_labelCount >= m_labelList.Length)
1168 m_labelList = EnlargeArray(m_labelList);
1170 m_labelList[m_labelCount].m_pos = -1;
1171 m_labelList[m_labelCount].m_depth = depth;
1172 return new Label(m_labelCount++);
1175 public void MarkLabel(Label loc)
1180 int labelIndex = loc.Id;
1183 if (m_labelList is
null || labelIndex < 0 || labelIndex >= m_labelList.Length)
1185 throw new ArgumentException(
"Invalid Label.");
1188 if (m_labelList[labelIndex].m_pos != -1)
1190 throw new ArgumentException(
"Label defined multiple times.");
1193 m_labelList[labelIndex].m_pos = m_length;
1195 int depth = m_labelList[labelIndex].m_depth;
1206 m_labelList[labelIndex].m_depth = m_curDepth;
1208 else if (depth < m_curDepth)
1212 m_depthAdjustment += m_curDepth - depth;
1213 m_labelList[labelIndex].m_depth = m_curDepth;
1215 else if (depth > m_curDepth)
1227 public LocalBuilder DeclareLocal(
Type localType)
1229 return DeclareLocal(localType,
false);
1232 public LocalBuilder DeclareLocal(
Type localType,
bool pinned)
1237 if (m_methodBuilder is not MethodBuilder methodBuilder)
1238 throw new NotSupportedException();
1240 if (methodBuilder.IsTypeCreated())
1243 throw new InvalidOperationException(
"Unable to change after type has been created.");
1246 if (localType is
null)
1247 throw new ArgumentNullException(nameof(localType));
1249 if (methodBuilder.IsBaked)
1251 throw new InvalidOperationException(
"Type definition of the method is complete.");
1255 m_localSignature.AddArgument(localType, pinned);
1257 return new LocalBuilder(m_methodBuilder, localType, m_localCount++, pinned);
1260 public void UsingNamespace(
string usingNamespace)
1265 if (
string.IsNullOrEmpty(usingNamespace))
1266 throw new ArgumentException(nameof(usingNamespace));
1268 if (m_methodBuilder is not MethodBuilder methodBuilder)
1269 throw new NotSupportedException();
1271 int index = ((ILGenerator)methodBuilder.GetILGenerator()).m_ScopeTree.GetCurrentActiveScopeIndex();
1274 methodBuilder.m_localSymInfo ??=
new();
1275 methodBuilder.m_localSymInfo!.AddUsingNamespace(usingNamespace);
1279 m_ScopeTree.AddUsingNamespaceToCurrentScope(usingNamespace);
1283 public void BeginScope()
1285 m_ScopeTree.AddScopeInfo(ScopeAction.Open, m_length);
1288 public void EndScope()
1290 m_ScopeTree.AddScopeInfo(ScopeAction.Close, m_length);
1293 public virtual void MarkSequencePoint(
1294 ISymbolDocumentWriter document,
1300 if (startLine == 0 || startLine < 0 || endLine == 0 || endLine < 0)
1302 throw new ArgumentOutOfRangeException(
"startLine");
1304 Contract.EndContractBlock();
1305 m_LineNumberInfo.AddLineNumberInfo(document, m_length, startLine, startColumn, endLine, endColumn);
1308 public int ILOffset => m_length;
1310 public void Emit(OpCode opcode, sbyte arg) => Emit(opcode, (
byte)arg);
1317 internal struct __LabelInfo
1320 internal int m_depth;
1323 internal struct __FixupData
1325 internal Label m_fixupLabel;
1326 internal int m_fixupPos;
1328 internal int m_fixupInstSize;
1331 internal sealed class __ExceptionInfo
1333 internal const int None = 0x0000;
1334 internal const int Filter = 0x0001;
1335 internal const int Finally = 0x0002;
1336 internal const int Fault = 0x0004;
1337 internal const int PreserveStack = 0x0004;
1339 internal const int State_Try = 0;
1340 internal const int State_Filter = 1;
1341 internal const int State_Catch = 2;
1342 internal const int State_Finally = 3;
1343 internal const int State_Fault = 4;
1344 internal const int State_Done = 5;
1346 internal int m_startAddr;
1347 internal int[] m_filterAddr;
1348 internal int[] m_catchAddr;
1349 internal int[] m_catchEndAddr;
1350 internal int[] m_type;
1351 internal Type[] m_catchClass;
1352 internal Label m_endLabel;
1353 internal Label m_finallyEndLabel;
1354 internal int m_endAddr;
1355 internal int m_endFinally;
1356 internal int m_currentCatch;
1358 private int m_currentState;
1360 internal __ExceptionInfo(
int startAddr, Label endLabel)
1362 m_startAddr = startAddr;
1364 m_filterAddr =
new int[4];
1365 m_catchAddr =
new int[4];
1366 m_catchEndAddr =
new int[4];
1367 m_catchClass =
new Type[4];
1369 m_endLabel = endLabel;
1370 m_type =
new int[4];
1372 m_currentState = State_Try;
1375 private void MarkHelper(
1376 int catchorfilterAddr,
1381 int currentCatch = m_currentCatch;
1382 if (currentCatch >= m_catchAddr.Length)
1384 m_filterAddr = ILGenerator.EnlargeArray(m_filterAddr);
1385 m_catchAddr = ILGenerator.EnlargeArray(m_catchAddr);
1386 m_catchEndAddr = ILGenerator.EnlargeArray(m_catchEndAddr);
1387 m_catchClass = ILGenerator.EnlargeArray(m_catchClass);
1388 m_type = ILGenerator.EnlargeArray(m_type);
1392 m_type[currentCatch] = type;
1393 m_filterAddr[currentCatch] = catchorfilterAddr;
1394 m_catchAddr[currentCatch] = -1;
1395 if (currentCatch > 0)
1397 Debug.Assert(m_catchEndAddr[currentCatch - 1] == -1,
"m_catchEndAddr[m_currentCatch-1] == -1");
1398 m_catchEndAddr[currentCatch - 1] = catchorfilterAddr;
1404 m_catchClass[currentCatch] = catchClass!;
1405 if (m_type[currentCatch] != Filter)
1407 m_type[currentCatch] = type;
1409 m_catchAddr[currentCatch] = catchorfilterAddr;
1410 if (currentCatch > 0)
1412 if (m_type[currentCatch] != Filter)
1414 Debug.Assert(m_catchEndAddr[currentCatch - 1] == -1,
"m_catchEndAddr[m_currentCatch-1] == -1");
1415 m_catchEndAddr[currentCatch - 1] = catchEndAddr;
1418 m_catchEndAddr[currentCatch] = -1;
1422 if (m_endAddr == -1)
1424 m_endAddr = catchorfilterAddr;
1428 internal void MarkFilterAddr(
int filterAddr)
1430 m_currentState = State_Filter;
1431 MarkHelper(filterAddr, filterAddr,
null, Filter);
1434 internal void MarkFaultAddr(
int faultAddr)
1436 m_currentState = State_Fault;
1437 MarkHelper(faultAddr, faultAddr,
null, Fault);
1440 internal void MarkCatchAddr(
int catchAddr,
Type? catchException)
1442 m_currentState = State_Catch;
1443 MarkHelper(catchAddr, catchAddr, catchException, None);
1446 internal void MarkFinallyAddr(
int finallyAddr,
int endCatchAddr)
1448 if (m_endFinally != -1)
1450 throw new ArgumentException(
"Exception blocks may have at most one finally clause.");
1453 m_currentState = State_Finally;
1454 m_endFinally = finallyAddr;
1455 MarkHelper(finallyAddr, endCatchAddr,
null, Finally);
1458 internal void Done(
int endAddr)
1460 Debug.Assert(m_currentCatch > 0,
"m_currentCatch > 0");
1461 Debug.Assert(m_catchAddr[m_currentCatch - 1] > 0,
"m_catchAddr[m_currentCatch-1] > 0");
1462 Debug.Assert(m_catchEndAddr[m_currentCatch - 1] == -1,
"m_catchEndAddr[m_currentCatch-1] == -1");
1463 m_catchEndAddr[m_currentCatch - 1] = endAddr;
1464 m_currentState = State_Done;
1467 internal int GetStartAddress()
1472 internal int GetEndAddress()
1477 internal int GetFinallyEndAddress()
1479 return m_endFinally;
1482 internal Label GetEndLabel()
1487 internal int[] GetFilterAddresses()
1489 return m_filterAddr;
1492 internal int[] GetCatchAddresses()
1497 internal int[] GetCatchEndAddresses()
1499 return m_catchEndAddr;
1502 internal Type[] GetCatchClass()
1504 return m_catchClass;
1507 internal int GetNumberOfCatches()
1509 return m_currentCatch;
1512 internal int[] GetExceptionTypes()
1517 internal void SetFinallyEndLabel(Label lbl)
1519 m_finallyEndLabel = lbl;
1522 internal Label GetFinallyEndLabel()
1524 return m_finallyEndLabel;
1535 internal bool IsInner(__ExceptionInfo exc)
1537 Debug.Assert(exc !=
null);
1538 Debug.Assert(m_currentCatch > 0,
"m_currentCatch > 0");
1539 Debug.Assert(exc.m_currentCatch > 0,
"exc.m_currentCatch > 0");
1541 int exclast = exc.m_currentCatch - 1;
1542 int last = m_currentCatch - 1;
1544 if (exc.m_catchEndAddr[exclast] < m_catchEndAddr[last])
1547 if (exc.m_catchEndAddr[exclast] != m_catchEndAddr[last])
1549 Debug.Assert(exc.GetEndAddress() != GetEndAddress(),
1550 "exc.GetEndAddress() != GetEndAddress()");
1552 return exc.GetEndAddress() > GetEndAddress();
1560 internal int GetCurrentState()
1562 return m_currentState;
1572 internal enum ScopeAction : sbyte
1578 internal sealed class ScopeTree
1580 internal ScopeTree()
1583 m_iOpenScopeCount = 0;
1592 internal int GetCurrentActiveScopeIndex()
1599 int i = m_iCount - 1;
1601 for (
int cClose = 0; cClose > 0 || m_ScopeActions[i] == ScopeAction.Close; i--)
1603 cClose += (sbyte)m_ScopeActions[i];
1609 internal void AddLocalSymInfoToCurrentScope(
1616 int i = GetCurrentActiveScopeIndex();
1617 m_localSymInfos[i] ??=
new LocalSymInfo();
1618 m_localSymInfos[i]!.AddLocalSymInfo(strName, signature, slot, startOffset, endOffset);
1621 internal void AddUsingNamespaceToCurrentScope(
string strNamespace)
1623 int i = GetCurrentActiveScopeIndex();
1624 m_localSymInfos[i] ??=
new LocalSymInfo();
1625 m_localSymInfos[i]!.AddUsingNamespace(strNamespace);
1628 internal void AddScopeInfo(ScopeAction sa,
int iOffset)
1630 if (sa == ScopeAction.Close && m_iOpenScopeCount <= 0)
1632 throw new ArgumentException(
"Non-matching symbol scope.");
1638 m_ScopeActions[m_iCount] = sa;
1639 m_iOffsets[m_iCount] = iOffset;
1640 m_localSymInfos[m_iCount] =
null;
1641 checked { m_iCount++; }
1643 m_iOpenScopeCount += -(sbyte)sa;
1649 internal void EnsureCapacity()
1654 m_iOffsets =
new int[InitialSize];
1655 m_ScopeActions =
new ScopeAction[InitialSize];
1656 m_localSymInfos =
new LocalSymInfo[InitialSize];
1658 else if (m_iCount == m_iOffsets.Length)
1662 int newSize = checked(m_iCount * 2);
1663 int[] temp =
new int[newSize];
1664 Array.Copy(m_iOffsets, temp, m_iCount);
1667 ScopeAction[] tempSA =
new ScopeAction[newSize];
1668 Array.Copy(m_ScopeActions, tempSA, m_iCount);
1669 m_ScopeActions = tempSA;
1671 LocalSymInfo[] tempLSI =
new LocalSymInfo[newSize];
1672 Array.Copy(m_localSymInfos, tempLSI, m_iCount);
1673 m_localSymInfos = tempLSI;
1676 internal void EmitScopeTree(ISymbolWriter symWriter)
1679 for (i = 0; i < m_iCount; i++)
1681 if (m_ScopeActions !=
null && m_ScopeActions[i] == ScopeAction.Open)
1683 symWriter.OpenScope(m_iOffsets[i]);
1687 symWriter.CloseScope(m_iOffsets[i]);
1689 if (m_localSymInfos !=
null && m_localSymInfos[i] !=
null)
1691 m_localSymInfos[i]!.EmitLocalSymInfo(symWriter);
1696 internal int[] m_iOffsets =
null!;
1697 internal ScopeAction[] m_ScopeActions =
null!;
1698 internal int m_iCount;
1699 internal int m_iOpenScopeCount;
1700 internal const int InitialSize = 16;
1701 internal LocalSymInfo?[] m_localSymInfos =
null!;
1710 internal sealed class LineNumberInfo
1712 internal LineNumberInfo()
1715 m_DocumentCount = 0;
1719 internal void AddLineNumberInfo(
1720 ISymbolDocumentWriter document,
1730 i = FindDocument(document);
1732 Contract.Assert(i < m_DocumentCount,
"Bad document look up!");
1733 m_Documents[i].AddLineNumberInfo(document, iOffset, iStartLine, iStartColumn, iEndLine, iEndColumn);
1738 private int FindDocument(ISymbolDocumentWriter document)
1744 if (m_iLastFound < m_DocumentCount && m_Documents[m_iLastFound].m_document == document)
1745 return m_iLastFound;
1747 for (i = 0; i < m_DocumentCount; i++)
1749 if (m_Documents[i].m_document == document)
1752 return m_iLastFound;
1758 m_iLastFound = m_DocumentCount;
1759 m_Documents[m_iLastFound] =
new REDocument(document);
1760 checked { m_DocumentCount++; }
1761 return m_iLastFound;
1769 private void EnsureCapacity()
1771 if (m_DocumentCount == 0)
1774 m_Documents =
new REDocument[InitialSize];
1776 else if (m_DocumentCount == m_Documents.Length)
1779 REDocument[] temp =
new REDocument[m_DocumentCount * 2];
1780 Array.Copy(m_Documents, temp, m_DocumentCount);
1785 internal void EmitLineNumberInfo(ISymbolWriter symWriter)
1787 for (
int i = 0; i < m_DocumentCount; i++)
1788 m_Documents[i].EmitLineNumberInfo(symWriter);
1791 private int m_DocumentCount;
1792 private REDocument[] m_Documents;
1793 private const int InitialSize = 16;
1794 private int m_iLastFound;
1803 internal sealed class REDocument
1805 internal REDocument(ISymbolDocumentWriter document)
1808 m_iLineNumberCount = 0;
1809 m_document = document;
1812 internal void AddLineNumberInfo(
1813 ISymbolDocumentWriter document,
1820 Contract.Assert(document == m_document,
"Bad document look up!");
1825 m_iOffsets[m_iLineNumberCount] = iOffset;
1826 m_iLines[m_iLineNumberCount] = iStartLine;
1827 m_iColumns[m_iLineNumberCount] = iStartColumn;
1828 m_iEndLines[m_iLineNumberCount] = iEndLine;
1829 m_iEndColumns[m_iLineNumberCount] = iEndColumn;
1830 checked { m_iLineNumberCount++; }
1838 private void EnsureCapacity()
1840 if (m_iLineNumberCount == 0)
1843 m_iOffsets =
new int[InitialSize];
1844 m_iLines =
new int[InitialSize];
1845 m_iColumns =
new int[InitialSize];
1846 m_iEndLines =
new int[InitialSize];
1847 m_iEndColumns =
new int[InitialSize];
1849 else if (m_iLineNumberCount == m_iOffsets.Length)
1853 int newSize = checked(m_iLineNumberCount * 2);
1854 int[] temp =
new int[newSize];
1855 Array.Copy(m_iOffsets, temp, m_iLineNumberCount);
1858 temp =
new int[newSize];
1859 Array.Copy(m_iLines, temp, m_iLineNumberCount);
1862 temp =
new int[newSize];
1863 Array.Copy(m_iColumns, temp, m_iLineNumberCount);
1866 temp =
new int[newSize];
1867 Array.Copy(m_iEndLines, temp, m_iLineNumberCount);
1870 temp =
new int[newSize];
1871 Array.Copy(m_iEndColumns, temp, m_iLineNumberCount);
1872 m_iEndColumns = temp;
1876 internal void EmitLineNumberInfo(ISymbolWriter symWriter)
1881 int[] iEndLinesTemp;
1882 int[] iEndColumnsTemp;
1884 if (m_iLineNumberCount == 0)
1887 iOffsetsTemp =
new int[m_iLineNumberCount];
1888 Array.Copy(m_iOffsets, iOffsetsTemp, m_iLineNumberCount);
1890 iLinesTemp =
new int[m_iLineNumberCount];
1891 Array.Copy(m_iLines, iLinesTemp, m_iLineNumberCount);
1893 iColumnsTemp =
new int[m_iLineNumberCount];
1894 Array.Copy(m_iColumns, iColumnsTemp, m_iLineNumberCount);
1896 iEndLinesTemp =
new int[m_iLineNumberCount];
1897 Array.Copy(m_iEndLines, iEndLinesTemp, m_iLineNumberCount);
1899 iEndColumnsTemp =
new int[m_iLineNumberCount];
1900 Array.Copy(m_iEndColumns, iEndColumnsTemp, m_iLineNumberCount);
1902 symWriter.DefineSequencePoints(m_document, iOffsetsTemp, iLinesTemp, iColumnsTemp, iEndLinesTemp, iEndColumnsTemp);
1905 private int[] m_iOffsets;
1906 private int[] m_iLines;
1907 private int[] m_iColumns;
1908 private int[] m_iEndLines;
1909 private int[] m_iEndColumns;
1910 internal ISymbolDocumentWriter m_document;
1911 private int m_iLineNumberCount;
1912 private const int InitialSize = 16;
IKVM.Reflection.Type Type
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.FieldInfo FieldInfo
IKVM.Reflection.MethodInfo MethodInfo
IKVM.Reflection.MethodBase MethodBase
System.Runtime.InteropServices.CallingConvention CallingConvention