2 Copyright (C) 2008-2010 Jeroen Frijters
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
25 using System.Runtime.InteropServices;
26 using System.Collections.Generic;
27 using System.Diagnostics.SymbolStore;
28 using System.Diagnostics;
29 using IKVM.Reflection.Metadata;
30 using IKVM.Reflection.Writer;
32 namespace IKVM.Reflection.Emit
36 // 1-based here, to make sure that an uninitialized Label isn't valid
37 private readonly int index1;
39 internal Label(int index)
41 this.index1 = index + 1;
46 get { return index1 - 1; }
49 public bool Equals(Label other)
51 return other.index1 == index1;
54 public override bool Equals(object obj)
56 return this == obj as Label?;
59 public override int GetHashCode()
64 public static bool operator ==(Label arg1, Label arg2)
66 return arg1.index1 == arg2.index1;
69 public static bool operator !=(Label arg1, Label arg2)
71 return !(arg1 == arg2);
75 public sealed class LocalBuilder
77 private readonly Type localType;
78 private readonly int index;
79 private readonly bool pinned;
81 internal int startOffset;
82 internal int endOffset;
84 internal LocalBuilder(Type localType, int index, bool pinned)
86 this.localType = localType;
91 public void SetLocalSymInfo(string name)
96 public void SetLocalSymInfo(string name, int startOffset, int endOffset)
99 this.startOffset = startOffset;
100 this.endOffset = endOffset;
103 public Type LocalType
105 get { return localType; }
108 public int LocalIndex
110 get { return index; }
115 get { return pinned; }
119 public sealed class ILGenerator
121 private static readonly Type FAULT = new BakedType(null); // the type we use here doesn't matter, as long as it can never be used as a real exception type
122 private readonly ModuleBuilder moduleBuilder;
123 private readonly ByteBuffer code;
124 private readonly List<LocalBuilder> locals = new List<LocalBuilder>();
125 private readonly List<int> tokenFixups = new List<int>();
126 private readonly List<int> labels = new List<int>();
127 private readonly List<int> labelStackHeight = new List<int>();
128 private readonly List<LabelFixup> labelFixups = new List<LabelFixup>();
129 private readonly List<SequencePoint> sequencePoints = new List<SequencePoint>();
130 private readonly List<ExceptionBlock> exceptions = new List<ExceptionBlock>();
131 private readonly Stack<ExceptionBlock> exceptionStack = new Stack<ExceptionBlock>();
132 private ushort maxStack;
133 private int stackHeight;
135 private byte exceptionBlockAssistanceMode = EBAM_COMPAT;
136 private const byte EBAM_COMPAT = 0;
137 private const byte EBAM_DISABLE = 1;
138 private const byte EBAM_CLEVER = 2;
140 private struct LabelFixup
146 private sealed class ExceptionBlock : IComparer<ExceptionBlock>
148 internal readonly int ordinal;
149 internal Label labelEnd;
150 internal int tryOffset;
151 internal int tryLength;
152 internal int handlerOffset;
153 internal int handlerLength;
154 internal Type exceptionType; // null = finally block or handler with filter, FAULT = fault block
155 internal int filterOffset;
157 internal ExceptionBlock(int ordinal)
159 this.ordinal = ordinal;
162 int IComparer<ExceptionBlock>.Compare(ExceptionBlock x, ExceptionBlock y)
164 // Mono's sort insists on doing unnecessary comparisons
169 else if (x.tryOffset == y.tryOffset && x.tryLength == y.tryLength)
171 return x.ordinal < y.ordinal ? -1 : 1;
173 else if (x.tryOffset >= y.tryOffset && x.handlerOffset + x.handlerLength <= y.handlerOffset + y.handlerLength)
177 else if (y.tryOffset >= x.tryOffset && y.handlerOffset + y.handlerLength <= x.handlerOffset + x.handlerLength)
183 return x.ordinal < y.ordinal ? -1 : 1;
188 private struct SequencePoint
190 internal ISymbolDocumentWriter document;
192 internal int startLine;
193 internal int startColumn;
194 internal int endLine;
195 internal int endColumn;
198 private sealed class Scope
200 internal readonly Scope parent;
201 internal readonly List<Scope> children = new List<Scope>();
202 internal readonly List<LocalBuilder> locals = new List<LocalBuilder>();
203 internal int startOffset;
204 internal int endOffset;
206 internal Scope(Scope parent)
208 this.parent = parent;
212 internal ILGenerator(ModuleBuilder moduleBuilder, int initialCapacity)
214 this.code = new ByteBuffer(initialCapacity);
215 this.moduleBuilder = moduleBuilder;
216 if (moduleBuilder.symbolWriter != null)
218 scope = new Scope(null);
222 private bool IsLabelReachable(Label label)
224 return labelStackHeight[label.Index] != -1;
228 public void __DisableExceptionBlockAssistance()
230 exceptionBlockAssistanceMode = EBAM_DISABLE;
234 public void __CleverExceptionBlockAssistance()
236 exceptionBlockAssistanceMode = EBAM_CLEVER;
242 get { return code.Position; }
245 public void BeginCatchBlock(Type exceptionType)
247 ExceptionBlock block = exceptionStack.Peek();
248 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
250 if (exceptionType == null)
252 Emit(OpCodes.Endfilter);
256 Emit(OpCodes.Leave, block.labelEnd);
261 if (block.tryLength == 0)
263 block.tryLength = code.Position - block.tryOffset;
265 else if (exceptionType != null)
267 block.handlerLength = code.Position - block.handlerOffset;
268 exceptionStack.Pop();
269 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
270 newBlock.labelEnd = block.labelEnd;
271 newBlock.tryOffset = block.tryOffset;
272 newBlock.tryLength = block.tryLength;
274 exceptions.Add(block);
275 exceptionStack.Push(block);
277 block.handlerOffset = code.Position;
278 block.exceptionType = exceptionType;
281 public Label BeginExceptionBlock()
283 ExceptionBlock block = new ExceptionBlock(exceptions.Count);
284 block.labelEnd = DefineLabel();
285 block.tryOffset = code.Position;
286 exceptionStack.Push(block);
287 exceptions.Add(block);
289 return block.labelEnd;
292 public void BeginExceptFilterBlock()
294 ExceptionBlock block = BeginFinallyFilterFaultBlock();
295 block.filterOffset = code.Position;
299 public void BeginFaultBlock()
301 ExceptionBlock block = BeginFinallyFilterFaultBlock();
302 block.handlerOffset = code.Position;
303 block.exceptionType = FAULT;
306 public void BeginFinallyBlock()
308 ExceptionBlock block = BeginFinallyFilterFaultBlock();
309 block.handlerOffset = code.Position;
312 private ExceptionBlock BeginFinallyFilterFaultBlock()
314 ExceptionBlock block = exceptionStack.Peek();
315 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
317 Emit(OpCodes.Leave, block.labelEnd);
319 if (block.handlerOffset == 0)
321 block.tryLength = code.Position - block.tryOffset;
325 block.handlerLength = code.Position - block.handlerOffset;
327 if (exceptionBlockAssistanceMode != EBAM_COMPAT)
329 labelEnd = block.labelEnd;
333 MarkLabel(block.labelEnd);
334 labelEnd = DefineLabel();
335 Emit(OpCodes.Leave, labelEnd);
337 exceptionStack.Pop();
338 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
339 newBlock.labelEnd = labelEnd;
340 newBlock.tryOffset = block.tryOffset;
341 newBlock.tryLength = code.Position - block.tryOffset;
343 exceptions.Add(block);
344 exceptionStack.Push(block);
350 public void EndExceptionBlock()
352 ExceptionBlock block = exceptionStack.Pop();
353 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
355 if (block.filterOffset != 0 || (block.exceptionType != null && block.exceptionType != FAULT))
357 Emit(OpCodes.Leave, block.labelEnd);
361 Emit(OpCodes.Endfinally);
364 MarkLabel(block.labelEnd);
365 block.handlerLength = code.Position - block.handlerOffset;
368 public void BeginScope()
370 Scope newScope = new Scope(scope);
371 scope.children.Add(newScope);
373 scope.startOffset = code.Position;
376 public void UsingNamespace(string usingNamespace)
378 if (moduleBuilder.symbolWriter != null)
380 moduleBuilder.symbolWriter.UsingNamespace(usingNamespace);
384 public LocalBuilder DeclareLocal(Type localType)
386 return DeclareLocal(localType, false);
389 public LocalBuilder DeclareLocal(Type localType, bool pinned)
391 LocalBuilder local = new LocalBuilder(localType, locals.Count, pinned);
395 scope.locals.Add(local);
400 public Label DefineLabel()
402 Label label = new Label(labels.Count);
404 labelStackHeight.Add(-1);
408 public void Emit(OpCode opc)
410 Debug.Assert(opc != OpCodes.Ret || (opc == OpCodes.Ret && stackHeight <= 1));
413 code.Write((byte)(opc.Value >> 8));
415 code.Write((byte)opc.Value);
416 switch (opc.FlowControl)
418 case FlowControl.Branch:
419 case FlowControl.Break:
420 case FlowControl.Return:
421 case FlowControl.Throw:
425 UpdateStack(opc.StackDiff);
430 private void UpdateStack(int stackdiff)
432 if (stackHeight == -1)
434 // we're about to emit code that is either unreachable or reachable only via a backward branch
437 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
438 stackHeight += stackdiff;
439 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
440 maxStack = Math.Max(maxStack, (ushort)stackHeight);
443 public void Emit(OpCode opc, byte arg)
449 public void Emit(OpCode opc, double arg)
455 public void Emit(OpCode opc, FieldInfo field)
458 WriteToken(moduleBuilder.GetFieldToken(field));
461 public void Emit(OpCode opc, short arg)
467 public void Emit(OpCode opc, int arg)
473 public void Emit(OpCode opc, long arg)
479 public void Emit(OpCode opc, Label label)
481 // We need special stackHeight handling for unconditional branches,
482 // because the branch and next flows have differing stack heights.
483 // Note that this assumes that unconditional branches do not push/pop.
484 int flowStackHeight = this.stackHeight;
486 if (opc == OpCodes.Leave || opc == OpCodes.Leave_S)
490 else if (opc.FlowControl != FlowControl.Branch)
492 flowStackHeight = this.stackHeight;
494 // if the label has already been marked, we can emit the branch offset directly
495 if (labels[label.Index] != -1)
497 if (labelStackHeight[label.Index] != flowStackHeight && (labelStackHeight[label.Index] != 0 || flowStackHeight != -1))
499 // the "backward branch constraint" prohibits this, so we don't need to support it
500 throw new NotSupportedException("'Backward branch constraints' violated");
502 if (opc.OperandType == OperandType.ShortInlineBrTarget)
504 WriteByteBranchOffset(labels[label.Index] - (code.Position + 1));
508 code.Write(labels[label.Index] - (code.Position + 4));
513 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == flowStackHeight || (flowStackHeight == -1 && labelStackHeight[label.Index] == 0));
514 labelStackHeight[label.Index] = flowStackHeight;
515 LabelFixup fix = new LabelFixup();
516 fix.label = label.Index;
517 fix.offset = code.Position;
518 labelFixups.Add(fix);
519 if (opc.OperandType == OperandType.ShortInlineBrTarget)
530 private void WriteByteBranchOffset(int offset)
532 if (offset < -128 || offset > 127)
534 throw new NotSupportedException("Branch offset of " + offset + " does not fit in one-byte branch target at position " + code.Position);
536 code.Write((byte)offset);
539 public void Emit(OpCode opc, Label[] labels)
542 LabelFixup fix = new LabelFixup();
544 fix.offset = code.Position;
545 labelFixups.Add(fix);
546 code.Write(labels.Length);
547 foreach (Label label in labels)
549 code.Write(label.Index);
550 if (this.labels[label.Index] != -1)
552 if (labelStackHeight[label.Index] != stackHeight)
554 // the "backward branch constraint" prohibits this, so we don't need to support it
555 throw new NotSupportedException();
560 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == stackHeight);
561 labelStackHeight[label.Index] = stackHeight;
566 public void Emit(OpCode opc, LocalBuilder local)
568 if ((opc == OpCodes.Ldloc || opc == OpCodes.Ldloca || opc == OpCodes.Stloc) && local.LocalIndex < 256)
570 if (opc == OpCodes.Ldloc)
572 switch (local.LocalIndex)
575 Emit(OpCodes.Ldloc_0);
578 Emit(OpCodes.Ldloc_1);
581 Emit(OpCodes.Ldloc_2);
584 Emit(OpCodes.Ldloc_3);
587 Emit(OpCodes.Ldloc_S);
588 code.Write((byte)local.LocalIndex);
592 else if (opc == OpCodes.Ldloca)
594 Emit(OpCodes.Ldloca_S);
595 code.Write((byte)local.LocalIndex);
597 else if (opc == OpCodes.Stloc)
599 switch (local.LocalIndex)
602 Emit(OpCodes.Stloc_0);
605 Emit(OpCodes.Stloc_1);
608 Emit(OpCodes.Stloc_2);
611 Emit(OpCodes.Stloc_3);
614 Emit(OpCodes.Stloc_S);
615 code.Write((byte)local.LocalIndex);
623 switch (opc.OperandType)
625 case OperandType.InlineVar:
626 code.Write((ushort)local.LocalIndex);
628 case OperandType.ShortInlineVar:
629 code.Write((byte)local.LocalIndex);
635 private void WriteToken(FieldToken token)
637 if (token.IsPseudoToken)
639 tokenFixups.Add(code.Position);
641 code.Write(token.Token);
644 private void WriteToken(MethodToken token)
646 if (token.IsPseudoToken)
648 tokenFixups.Add(code.Position);
650 code.Write(token.Token);
653 private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
655 if (opc == OpCodes.Jmp)
659 else if (opc.FlowControl == FlowControl.Call)
662 if ((hasthis && opc != OpCodes.Newobj) || opc == OpCodes.Calli)
668 stackdiff -= parameterCount;
669 if (returnType != moduleBuilder.universe.System_Void)
674 UpdateStack(stackdiff);
678 public void Emit(OpCode opc, MethodInfo method)
680 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount);
682 WriteToken(moduleBuilder.GetMethodTokenForIL(method));
685 public void Emit(OpCode opc, ConstructorInfo constructor)
687 Emit(opc, constructor.GetMethodInfo());
690 public void Emit(OpCode opc, sbyte arg)
696 public void Emit(OpCode opc, float arg)
702 public void Emit(OpCode opc, string str)
705 code.Write(0x70000000 | moduleBuilder.UserStrings.Add(str));
708 public void Emit(OpCode opc, Type type)
711 if (opc == OpCodes.Ldtoken)
713 code.Write(moduleBuilder.GetTypeToken(type).Token);
717 code.Write(moduleBuilder.GetTypeTokenForMemberRef(type));
721 public void Emit(OpCode opcode, SignatureHelper signature)
724 UpdateStack(opcode, signature.HasThis, signature.ReturnType, signature.ParameterCount);
725 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(signature.GetSignature(moduleBuilder))));
728 public void EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes)
730 if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
737 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount + optionalParameterTypes.Length);
738 ByteBuffer sig = new ByteBuffer(16);
739 method.MethodSignature.WriteMethodRefSig(moduleBuilder, sig, optionalParameterTypes);
740 MemberRefTable.Record record = new MemberRefTable.Record();
741 if (method.Module == moduleBuilder)
743 record.Class = method.MetadataToken;
747 record.Class = moduleBuilder.GetTypeTokenForMemberRef(method.DeclaringType ?? method.Module.GetModuleType());
749 record.Name = moduleBuilder.Strings.Add(method.Name);
750 record.Signature = moduleBuilder.Blobs.Add(sig);
751 code.Write(0x0A000000 | moduleBuilder.MemberRef.FindOrAddRecord(record));
755 public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes)
757 EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes);
760 public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
762 returnType = returnType ?? moduleBuilder.universe.System_Void;
764 UpdateStack(opc, false, returnType, parameterTypes.Length);
765 ByteBuffer sig = new ByteBuffer(16);
766 Signature.WriteStandAloneMethodSig(moduleBuilder, sig, callingConvention, returnType, parameterTypes);
767 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(sig)));
770 public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
772 returnType = returnType ?? moduleBuilder.universe.System_Void;
773 optionalParameterTypes = optionalParameterTypes ?? Type.EmptyTypes;
775 UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, returnType, parameterTypes.Length + optionalParameterTypes.Length);
776 ByteBuffer sig = new ByteBuffer(16);
777 Signature.WriteStandAloneMethodSig(moduleBuilder, sig, callingConvention, returnType, parameterTypes, optionalParameterTypes);
778 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(sig)));
781 public void EmitWriteLine(string text)
783 Universe u = moduleBuilder.universe;
784 Emit(OpCodes.Ldstr, text);
785 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("WriteLine", new Type[] { u.System_String }));
788 public void EmitWriteLine(FieldInfo field)
790 Universe u = moduleBuilder.universe;
791 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
794 Emit(OpCodes.Ldsfld, field);
798 Emit(OpCodes.Ldarg_0);
799 Emit(OpCodes.Ldfld, field);
801 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { field.FieldType }));
804 public void EmitWriteLine(LocalBuilder local)
806 Universe u = moduleBuilder.universe;
807 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
808 Emit(OpCodes.Ldloc, local);
809 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { local.LocalType }));
812 public void EndScope()
814 scope.endOffset = code.Position;
815 scope = scope.parent;
818 public void MarkLabel(Label loc)
820 Debug.Assert(stackHeight == -1 || labelStackHeight[loc.Index] == -1 || stackHeight == labelStackHeight[loc.Index]);
821 labels[loc.Index] = code.Position;
822 if (labelStackHeight[loc.Index] == -1)
824 if (stackHeight == -1)
826 // We're at a location that can only be reached by a backward branch,
827 // so according to the "backward branch constraint" that must mean the stack is empty,
828 // but note that this may be an unused label followed by another label that is used and
829 // that does have a non-zero stack height, so we don't yet set stackHeight here.
830 labelStackHeight[loc.Index] = 0;
834 labelStackHeight[loc.Index] = stackHeight;
839 Debug.Assert(stackHeight == -1 || stackHeight == labelStackHeight[loc.Index]);
840 stackHeight = labelStackHeight[loc.Index];
844 public void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
846 SequencePoint sp = new SequencePoint();
847 sp.document = document;
848 sp.offset = code.Position;
849 sp.startLine = startLine;
850 sp.startColumn = startColumn;
851 sp.endLine = endLine;
852 sp.endColumn = endColumn;
853 sequencePoints.Add(sp);
856 public void ThrowException(Type excType)
858 Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
862 internal int WriteBody(bool initLocals)
864 if (moduleBuilder.symbolWriter != null)
866 Debug.Assert(scope != null && scope.parent == null);
867 scope.endOffset = code.Position;
872 ByteBuffer bb = moduleBuilder.methodBodies;
874 int localVarSigTok = 0;
877 if (locals.Count == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64)
879 rva = WriteTinyHeaderAndCode(bb);
883 rva = WriteFatHeaderAndCode(bb, ref localVarSigTok, initLocals);
886 if (moduleBuilder.symbolWriter != null)
888 if (sequencePoints.Count != 0)
890 ISymbolDocumentWriter document = sequencePoints[0].document;
891 int[] offsets = new int[sequencePoints.Count];
892 int[] lines = new int[sequencePoints.Count];
893 int[] columns = new int[sequencePoints.Count];
894 int[] endLines = new int[sequencePoints.Count];
895 int[] endColumns = new int[sequencePoints.Count];
896 for (int i = 0; i < sequencePoints.Count; i++)
898 if (sequencePoints[i].document != document)
900 throw new NotImplementedException();
902 offsets[i] = sequencePoints[i].offset;
903 lines[i] = sequencePoints[i].startLine;
904 columns[i] = sequencePoints[i].startColumn;
905 endLines[i] = sequencePoints[i].endLine;
906 endColumns[i] = sequencePoints[i].endColumn;
908 moduleBuilder.symbolWriter.DefineSequencePoints(document, offsets, lines, columns, endLines, endColumns);
911 WriteScope(scope, localVarSigTok);
916 private void ResolveBranches()
918 foreach (LabelFixup fixup in labelFixups)
921 if (fixup.label == -1)
923 code.Position = fixup.offset;
924 int count = code.GetInt32AtCurrentPosition();
925 int offset = fixup.offset + 4 + 4 * count;
927 for (int i = 0; i < count; i++)
929 int index = code.GetInt32AtCurrentPosition();
930 code.Write(labels[index] - offset);
935 code.Position = fixup.offset;
936 byte size = code.GetByteAtCurrentPosition();
937 int branchOffset = labels[fixup.label] - (code.Position + size);
940 WriteByteBranchOffset(branchOffset);
944 code.Write(branchOffset);
950 private int WriteTinyHeaderAndCode(ByteBuffer bb)
952 int rva = bb.Position;
953 const byte CorILMethod_TinyFormat = 0x2;
954 bb.Write((byte)(CorILMethod_TinyFormat | (code.Length << 2)));
959 private int WriteFatHeaderAndCode(ByteBuffer bb, ref int localVarSigTok, bool initLocals)
961 // fat headers require 4-byte alignment
963 int rva = bb.Position;
965 if (locals.Count != 0)
967 ByteBuffer localVarSig = new ByteBuffer(locals.Count + 2);
968 Signature.WriteLocalVarSig(moduleBuilder, localVarSig, locals);
969 localVarSigTok = 0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(localVarSig));
972 const byte CorILMethod_FatFormat = 0x03;
973 const byte CorILMethod_MoreSects = 0x08;
974 const byte CorILMethod_InitLocals = 0x10;
976 short flagsAndSize = (short)(CorILMethod_FatFormat | (3 << 12));
979 flagsAndSize |= CorILMethod_InitLocals;
982 if (exceptions.Count > 0)
984 flagsAndSize |= CorILMethod_MoreSects;
987 bb.Write(flagsAndSize);
989 bb.Write(code.Length);
990 bb.Write(localVarSigTok);
994 if (exceptions.Count > 0)
999 foreach (ExceptionBlock block in exceptions)
1001 if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
1007 exceptions.Sort(exceptions[0]);
1008 if (exceptions.Count * 12 + 4 > 255)
1012 const byte CorILMethod_Sect_EHTable = 0x1;
1013 const byte CorILMethod_Sect_FatFormat = 0x40;
1014 const short COR_ILEXCEPTION_CLAUSE_EXCEPTION = 0x0000;
1015 const short COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001;
1016 const short COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002;
1017 const short COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004;
1021 bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
1022 int dataSize = exceptions.Count * 24 + 4;
1023 bb.Write((byte)dataSize);
1024 bb.Write((short)(dataSize >> 8));
1025 foreach (ExceptionBlock block in exceptions)
1027 if (block.exceptionType == FAULT)
1029 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FAULT);
1031 else if (block.filterOffset != 0)
1033 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FILTER);
1035 else if (block.exceptionType != null)
1037 bb.Write((int)COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1041 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FINALLY);
1043 bb.Write(block.tryOffset);
1044 bb.Write(block.tryLength);
1045 bb.Write(block.handlerOffset);
1046 bb.Write(block.handlerLength);
1047 if (block.exceptionType != null && block.exceptionType != FAULT)
1049 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1053 bb.Write(block.filterOffset);
1059 bb.Write(CorILMethod_Sect_EHTable);
1060 bb.Write((byte)(exceptions.Count * 12 + 4));
1062 foreach (ExceptionBlock block in exceptions)
1064 if (block.exceptionType == FAULT)
1066 bb.Write(COR_ILEXCEPTION_CLAUSE_FAULT);
1068 else if (block.filterOffset != 0)
1070 bb.Write(COR_ILEXCEPTION_CLAUSE_FILTER);
1072 else if (block.exceptionType != null)
1074 bb.Write(COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1078 bb.Write(COR_ILEXCEPTION_CLAUSE_FINALLY);
1080 bb.Write((short)block.tryOffset);
1081 bb.Write((byte)block.tryLength);
1082 bb.Write((short)block.handlerOffset);
1083 bb.Write((byte)block.handlerLength);
1084 if (block.exceptionType != null && block.exceptionType != FAULT)
1086 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1090 bb.Write(block.filterOffset);
1098 private void WriteCode(ByteBuffer bb)
1100 int codeOffset = bb.Position;
1101 foreach (int fixup in this.tokenFixups)
1103 moduleBuilder.tokenFixupOffsets.Add(fixup + codeOffset);
1108 private void WriteScope(Scope scope, int localVarSigTok)
1110 moduleBuilder.symbolWriter.OpenScope(scope.startOffset);
1111 foreach (LocalBuilder local in scope.locals)
1113 if (local.name != null)
1115 int startOffset = local.startOffset;
1116 int endOffset = local.endOffset;
1117 if (startOffset == 0 && endOffset == 0)
1119 startOffset = scope.startOffset;
1120 endOffset = scope.endOffset;
1122 moduleBuilder.symbolWriter.DefineLocalVariable2(local.name, 0, localVarSigTok, SymAddressKind.ILOffset, local.LocalIndex, 0, 0, startOffset, endOffset);
1125 foreach (Scope child in scope.children)
1127 WriteScope(child, localVarSigTok);
1129 moduleBuilder.symbolWriter.CloseScope(scope.endOffset);