2 Copyright (C) 2008-2012 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.Writer;
31 namespace IKVM.Reflection.Emit
35 // 1-based here, to make sure that an uninitialized Label isn't valid
36 private readonly int index1;
38 internal Label(int index)
40 this.index1 = index + 1;
45 get { return index1 - 1; }
48 public bool Equals(Label other)
50 return other.index1 == index1;
53 public override bool Equals(object obj)
55 return this == obj as Label?;
58 public override int GetHashCode()
63 public static bool operator ==(Label arg1, Label arg2)
65 return arg1.index1 == arg2.index1;
68 public static bool operator !=(Label arg1, Label arg2)
70 return !(arg1 == arg2);
74 public sealed class LocalBuilder
76 private readonly Type localType;
77 private readonly int index;
78 private readonly bool pinned;
80 internal int startOffset;
81 internal int endOffset;
83 internal LocalBuilder(Type localType, int index, bool pinned)
85 this.localType = localType;
90 public void SetLocalSymInfo(string name)
95 public void SetLocalSymInfo(string name, int startOffset, int endOffset)
98 this.startOffset = startOffset;
99 this.endOffset = endOffset;
102 public Type LocalType
104 get { return localType; }
107 public int LocalIndex
109 get { return index; }
114 get { return pinned; }
118 public sealed class ILGenerator
120 private readonly ModuleBuilder moduleBuilder;
121 private readonly ByteBuffer code;
122 private readonly SignatureHelper locals;
123 private int localsCount;
124 private readonly List<int> tokenFixups = new List<int>();
125 private readonly List<int> labels = new List<int>();
126 private readonly List<int> labelStackHeight = new List<int>();
127 private readonly List<LabelFixup> labelFixups = new List<LabelFixup>();
128 private readonly List<SequencePoint> sequencePoints = new List<SequencePoint>();
129 private readonly List<ExceptionBlock> exceptions = new List<ExceptionBlock>();
130 private readonly Stack<ExceptionBlock> exceptionStack = new Stack<ExceptionBlock>();
131 private ushort maxStack;
132 private bool fatHeader;
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; // MarkerType.Finally = finally block, MarkerType.Filter = handler with filter, MarkerType.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 this.locals = SignatureHelper.GetLocalVarSigHelper(moduleBuilder);
217 if (moduleBuilder.symbolWriter != null)
219 scope = new Scope(null);
224 public void __DisableExceptionBlockAssistance()
226 exceptionBlockAssistanceMode = EBAM_DISABLE;
230 public void __CleverExceptionBlockAssistance()
232 exceptionBlockAssistanceMode = EBAM_CLEVER;
236 public int __MaxStackSize
238 get { return maxStack; }
241 maxStack = (ushort)value;
247 // returns -1 if the current position is currently unreachable
248 public int __StackHeight
250 get { return stackHeight; }
256 get { return code.Position; }
259 public void BeginCatchBlock(Type exceptionType)
261 ExceptionBlock block = exceptionStack.Peek();
262 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
264 if (exceptionType == null)
266 Emit(OpCodes.Endfilter);
270 Emit(OpCodes.Leave, block.labelEnd);
275 if (exceptionType == null)
277 if (block.exceptionType != MarkerType.Filter || block.handlerOffset != 0)
279 throw new ArgumentNullException("exceptionType");
281 block.handlerOffset = code.Position;
285 if (block.tryLength == 0)
287 block.tryLength = code.Position - block.tryOffset;
291 block.handlerLength = code.Position - block.handlerOffset;
292 exceptionStack.Pop();
293 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
294 newBlock.labelEnd = block.labelEnd;
295 newBlock.tryOffset = block.tryOffset;
296 newBlock.tryLength = block.tryLength;
298 exceptions.Add(block);
299 exceptionStack.Push(block);
301 block.exceptionType = exceptionType;
302 if (exceptionType == MarkerType.Filter)
304 block.filterOffset = code.Position;
308 block.handlerOffset = code.Position;
313 public Label BeginExceptionBlock()
315 ExceptionBlock block = new ExceptionBlock(exceptions.Count);
316 block.labelEnd = DefineLabel();
317 block.tryOffset = code.Position;
318 exceptionStack.Push(block);
319 exceptions.Add(block);
321 return block.labelEnd;
324 public void BeginExceptFilterBlock()
326 BeginCatchBlock(MarkerType.Filter);
329 public void BeginFaultBlock()
331 BeginFinallyFaultBlock(MarkerType.Fault);
334 public void BeginFinallyBlock()
336 BeginFinallyFaultBlock(MarkerType.Finally);
339 private void BeginFinallyFaultBlock(Type type)
341 ExceptionBlock block = exceptionStack.Peek();
342 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
344 Emit(OpCodes.Leave, block.labelEnd);
346 if (block.handlerOffset == 0)
348 block.tryLength = code.Position - block.tryOffset;
352 block.handlerLength = code.Position - block.handlerOffset;
354 if (exceptionBlockAssistanceMode != EBAM_COMPAT)
356 labelEnd = block.labelEnd;
360 MarkLabel(block.labelEnd);
361 labelEnd = DefineLabel();
362 Emit(OpCodes.Leave, labelEnd);
364 exceptionStack.Pop();
365 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
366 newBlock.labelEnd = labelEnd;
367 newBlock.tryOffset = block.tryOffset;
368 newBlock.tryLength = code.Position - block.tryOffset;
370 exceptions.Add(block);
371 exceptionStack.Push(block);
373 block.handlerOffset = code.Position;
374 block.exceptionType = type;
378 public void EndExceptionBlock()
380 ExceptionBlock block = exceptionStack.Pop();
381 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
383 if (block.filterOffset != 0 || (block.exceptionType != MarkerType.Finally && block.exceptionType != MarkerType.Fault))
385 Emit(OpCodes.Leave, block.labelEnd);
389 Emit(OpCodes.Endfinally);
392 MarkLabel(block.labelEnd);
393 block.handlerLength = code.Position - block.handlerOffset;
396 public void BeginScope()
398 Scope newScope = new Scope(scope);
399 scope.children.Add(newScope);
401 scope.startOffset = code.Position;
404 public void UsingNamespace(string usingNamespace)
406 if (moduleBuilder.symbolWriter != null)
408 moduleBuilder.symbolWriter.UsingNamespace(usingNamespace);
412 public LocalBuilder DeclareLocal(Type localType)
414 return DeclareLocal(localType, false);
417 public LocalBuilder DeclareLocal(Type localType, bool pinned)
419 LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned);
420 locals.AddArgument(localType, pinned);
423 scope.locals.Add(local);
428 public LocalBuilder __DeclareLocal(Type localType, bool pinned, CustomModifiers customModifiers)
430 LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned);
431 locals.__AddArgument(localType, pinned, customModifiers);
434 scope.locals.Add(local);
439 public Label DefineLabel()
441 Label label = new Label(labels.Count);
443 labelStackHeight.Add(-1);
447 public void Emit(OpCode opc)
449 Debug.Assert(opc != OpCodes.Ret || (opc == OpCodes.Ret && stackHeight <= 1));
452 code.Write((byte)(opc.Value >> 8));
454 code.Write((byte)opc.Value);
455 switch (opc.FlowControl)
457 case FlowControl.Branch:
458 case FlowControl.Break:
459 case FlowControl.Return:
460 case FlowControl.Throw:
464 UpdateStack(opc.StackDiff);
469 private void UpdateStack(int stackdiff)
471 if (stackHeight == -1)
473 // we're about to emit code that is either unreachable or reachable only via a backward branch
476 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
477 stackHeight += stackdiff;
478 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
479 maxStack = Math.Max(maxStack, (ushort)stackHeight);
482 public void Emit(OpCode opc, byte arg)
488 public void Emit(OpCode opc, double arg)
494 public void Emit(OpCode opc, FieldInfo field)
497 WriteToken(moduleBuilder.GetFieldToken(field));
500 public void Emit(OpCode opc, short arg)
506 public void Emit(OpCode opc, int arg)
512 public void Emit(OpCode opc, long arg)
518 public void Emit(OpCode opc, Label label)
520 // We need special stackHeight handling for unconditional branches,
521 // because the branch and next flows have differing stack heights.
522 // Note that this assumes that unconditional branches do not push/pop.
523 int flowStackHeight = this.stackHeight;
525 if (opc == OpCodes.Leave || opc == OpCodes.Leave_S)
529 else if (opc.FlowControl != FlowControl.Branch)
531 flowStackHeight = this.stackHeight;
533 // if the label has already been marked, we can emit the branch offset directly
534 if (labels[label.Index] != -1)
536 if (labelStackHeight[label.Index] != flowStackHeight && (labelStackHeight[label.Index] != 0 || flowStackHeight != -1))
538 // the "backward branch constraint" prohibits this, so we don't need to support it
539 throw new NotSupportedException("'Backward branch constraints' violated");
541 if (opc.OperandType == OperandType.ShortInlineBrTarget)
543 WriteByteBranchOffset(labels[label.Index] - (code.Position + 1));
547 code.Write(labels[label.Index] - (code.Position + 4));
552 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == flowStackHeight || (flowStackHeight == -1 && labelStackHeight[label.Index] == 0));
553 labelStackHeight[label.Index] = flowStackHeight;
554 LabelFixup fix = new LabelFixup();
555 fix.label = label.Index;
556 fix.offset = code.Position;
557 labelFixups.Add(fix);
558 if (opc.OperandType == OperandType.ShortInlineBrTarget)
569 private void WriteByteBranchOffset(int offset)
571 if (offset < -128 || offset > 127)
573 throw new NotSupportedException("Branch offset of " + offset + " does not fit in one-byte branch target at position " + code.Position);
575 code.Write((byte)offset);
578 public void Emit(OpCode opc, Label[] labels)
581 LabelFixup fix = new LabelFixup();
583 fix.offset = code.Position;
584 labelFixups.Add(fix);
585 code.Write(labels.Length);
586 foreach (Label label in labels)
588 code.Write(label.Index);
589 if (this.labels[label.Index] != -1)
591 if (labelStackHeight[label.Index] != stackHeight)
593 // the "backward branch constraint" prohibits this, so we don't need to support it
594 throw new NotSupportedException();
599 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == stackHeight);
600 labelStackHeight[label.Index] = stackHeight;
605 public void Emit(OpCode opc, LocalBuilder local)
607 if ((opc == OpCodes.Ldloc || opc == OpCodes.Ldloca || opc == OpCodes.Stloc) && local.LocalIndex < 256)
609 if (opc == OpCodes.Ldloc)
611 switch (local.LocalIndex)
614 Emit(OpCodes.Ldloc_0);
617 Emit(OpCodes.Ldloc_1);
620 Emit(OpCodes.Ldloc_2);
623 Emit(OpCodes.Ldloc_3);
626 Emit(OpCodes.Ldloc_S);
627 code.Write((byte)local.LocalIndex);
631 else if (opc == OpCodes.Ldloca)
633 Emit(OpCodes.Ldloca_S);
634 code.Write((byte)local.LocalIndex);
636 else if (opc == OpCodes.Stloc)
638 switch (local.LocalIndex)
641 Emit(OpCodes.Stloc_0);
644 Emit(OpCodes.Stloc_1);
647 Emit(OpCodes.Stloc_2);
650 Emit(OpCodes.Stloc_3);
653 Emit(OpCodes.Stloc_S);
654 code.Write((byte)local.LocalIndex);
662 switch (opc.OperandType)
664 case OperandType.InlineVar:
665 code.Write((ushort)local.LocalIndex);
667 case OperandType.ShortInlineVar:
668 code.Write((byte)local.LocalIndex);
674 private void WriteToken(FieldToken token)
676 if (token.IsPseudoToken)
678 tokenFixups.Add(code.Position);
680 code.Write(token.Token);
683 private void WriteToken(MethodToken token)
685 if (token.IsPseudoToken)
687 tokenFixups.Add(code.Position);
689 code.Write(token.Token);
692 private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
694 if (opc == OpCodes.Jmp)
698 else if (opc.FlowControl == FlowControl.Call)
701 if ((hasthis && opc != OpCodes.Newobj) || opc == OpCodes.Calli)
707 stackdiff -= parameterCount;
708 if (returnType != moduleBuilder.universe.System_Void)
713 UpdateStack(stackdiff);
717 public void Emit(OpCode opc, MethodInfo method)
719 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount);
721 WriteToken(moduleBuilder.GetMethodTokenForIL(method));
724 public void Emit(OpCode opc, ConstructorInfo constructor)
726 Emit(opc, constructor.GetMethodInfo());
729 public void Emit(OpCode opc, sbyte arg)
735 public void Emit(OpCode opc, float arg)
741 public void Emit(OpCode opc, string str)
744 code.Write(moduleBuilder.GetStringConstant(str).Token);
747 public void Emit(OpCode opc, Type type)
750 if (opc == OpCodes.Ldtoken)
752 code.Write(moduleBuilder.GetTypeToken(type).Token);
756 code.Write(moduleBuilder.GetTypeTokenForMemberRef(type));
760 public void Emit(OpCode opcode, SignatureHelper signature)
763 UpdateStack(opcode, signature.HasThis, signature.ReturnType, signature.ParameterCount);
764 code.Write(moduleBuilder.GetSignatureToken(signature).Token);
767 public void EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes)
769 __EmitCall(opc, method, optionalParameterTypes, null);
772 public void __EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
774 if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
781 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount + optionalParameterTypes.Length);
782 code.Write(moduleBuilder.__GetMethodToken(method, optionalParameterTypes, customModifiers).Token);
786 public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes)
788 EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes);
791 public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
793 __EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes, customModifiers);
796 public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
798 SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
799 sig.AddArguments(parameterTypes, null, null);
803 public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
805 SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
806 sig.AddArguments(parameterTypes, null, null);
808 sig.AddArguments(optionalParameterTypes, null, null);
812 public void __EmitCalli(OpCode opc, __StandAloneMethodSig sig)
817 UpdateStack(opc, false, sig.ReturnType, sig.ParameterCount);
821 CallingConventions callingConvention = sig.CallingConvention;
822 UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, sig.ReturnType, sig.ParameterCount);
824 ByteBuffer bb = new ByteBuffer(16);
825 Signature.WriteStandAloneMethodSig(moduleBuilder, bb, sig);
826 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(bb)));
829 public void EmitWriteLine(string text)
831 Universe u = moduleBuilder.universe;
832 Emit(OpCodes.Ldstr, text);
833 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("WriteLine", new Type[] { u.System_String }));
836 public void EmitWriteLine(FieldInfo field)
838 Universe u = moduleBuilder.universe;
839 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
842 Emit(OpCodes.Ldsfld, field);
846 Emit(OpCodes.Ldarg_0);
847 Emit(OpCodes.Ldfld, field);
849 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { field.FieldType }));
852 public void EmitWriteLine(LocalBuilder local)
854 Universe u = moduleBuilder.universe;
855 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
856 Emit(OpCodes.Ldloc, local);
857 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { local.LocalType }));
860 public void EndScope()
862 scope.endOffset = code.Position;
863 scope = scope.parent;
866 public void MarkLabel(Label loc)
868 Debug.Assert(stackHeight == -1 || labelStackHeight[loc.Index] == -1 || stackHeight == labelStackHeight[loc.Index]);
869 labels[loc.Index] = code.Position;
870 if (labelStackHeight[loc.Index] == -1)
872 if (stackHeight == -1)
874 // We're at a location that can only be reached by a backward branch,
875 // so according to the "backward branch constraint" that must mean the stack is empty,
876 // but note that this may be an unused label followed by another label that is used and
877 // that does have a non-zero stack height, so we don't yet set stackHeight here.
878 labelStackHeight[loc.Index] = 0;
882 labelStackHeight[loc.Index] = stackHeight;
887 Debug.Assert(stackHeight == -1 || stackHeight == labelStackHeight[loc.Index]);
888 stackHeight = labelStackHeight[loc.Index];
892 public void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
894 SequencePoint sp = new SequencePoint();
895 sp.document = document;
896 sp.offset = code.Position;
897 sp.startLine = startLine;
898 sp.startColumn = startColumn;
899 sp.endLine = endLine;
900 sp.endColumn = endColumn;
901 sequencePoints.Add(sp);
904 public void ThrowException(Type excType)
906 Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
910 internal int WriteBody(bool initLocals)
912 if (moduleBuilder.symbolWriter != null)
914 Debug.Assert(scope != null && scope.parent == null);
915 scope.endOffset = code.Position;
920 ByteBuffer bb = moduleBuilder.methodBodies;
922 int localVarSigTok = 0;
925 if (localsCount == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64 && !fatHeader)
927 rva = WriteTinyHeaderAndCode(bb);
931 rva = WriteFatHeaderAndCode(bb, ref localVarSigTok, initLocals);
934 if (moduleBuilder.symbolWriter != null)
936 if (sequencePoints.Count != 0)
938 ISymbolDocumentWriter document = sequencePoints[0].document;
939 int[] offsets = new int[sequencePoints.Count];
940 int[] lines = new int[sequencePoints.Count];
941 int[] columns = new int[sequencePoints.Count];
942 int[] endLines = new int[sequencePoints.Count];
943 int[] endColumns = new int[sequencePoints.Count];
944 for (int i = 0; i < sequencePoints.Count; i++)
946 if (sequencePoints[i].document != document)
948 throw new NotImplementedException();
950 offsets[i] = sequencePoints[i].offset;
951 lines[i] = sequencePoints[i].startLine;
952 columns[i] = sequencePoints[i].startColumn;
953 endLines[i] = sequencePoints[i].endLine;
954 endColumns[i] = sequencePoints[i].endColumn;
956 moduleBuilder.symbolWriter.DefineSequencePoints(document, offsets, lines, columns, endLines, endColumns);
959 WriteScope(scope, localVarSigTok);
964 private void ResolveBranches()
966 foreach (LabelFixup fixup in labelFixups)
969 if (fixup.label == -1)
971 code.Position = fixup.offset;
972 int count = code.GetInt32AtCurrentPosition();
973 int offset = fixup.offset + 4 + 4 * count;
975 for (int i = 0; i < count; i++)
977 int index = code.GetInt32AtCurrentPosition();
978 code.Write(labels[index] - offset);
983 code.Position = fixup.offset;
984 byte size = code.GetByteAtCurrentPosition();
985 int branchOffset = labels[fixup.label] - (code.Position + size);
988 WriteByteBranchOffset(branchOffset);
992 code.Write(branchOffset);
998 private int WriteTinyHeaderAndCode(ByteBuffer bb)
1000 int rva = bb.Position;
1001 const byte CorILMethod_TinyFormat = 0x2;
1002 bb.Write((byte)(CorILMethod_TinyFormat | (code.Length << 2)));
1007 private int WriteFatHeaderAndCode(ByteBuffer bb, ref int localVarSigTok, bool initLocals)
1009 // fat headers require 4-byte alignment
1011 int rva = bb.Position;
1013 if (localsCount != 0)
1015 localVarSigTok = moduleBuilder.GetSignatureToken(locals).Token;
1018 const byte CorILMethod_FatFormat = 0x03;
1019 const byte CorILMethod_MoreSects = 0x08;
1020 const byte CorILMethod_InitLocals = 0x10;
1022 short flagsAndSize = (short)(CorILMethod_FatFormat | (3 << 12));
1025 flagsAndSize |= CorILMethod_InitLocals;
1028 if (exceptions.Count > 0)
1030 flagsAndSize |= CorILMethod_MoreSects;
1033 bb.Write(flagsAndSize);
1035 bb.Write(code.Length);
1036 bb.Write(localVarSigTok);
1040 if (exceptions.Count > 0)
1045 foreach (ExceptionBlock block in exceptions)
1047 if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
1053 exceptions.Sort(exceptions[0]);
1054 if (exceptions.Count * 12 + 4 > 255)
1058 const byte CorILMethod_Sect_EHTable = 0x1;
1059 const byte CorILMethod_Sect_FatFormat = 0x40;
1060 const short COR_ILEXCEPTION_CLAUSE_EXCEPTION = 0x0000;
1061 const short COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001;
1062 const short COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002;
1063 const short COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004;
1067 bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
1068 int dataSize = exceptions.Count * 24 + 4;
1069 bb.Write((byte)dataSize);
1070 bb.Write((short)(dataSize >> 8));
1071 foreach (ExceptionBlock block in exceptions)
1073 if (block.exceptionType == MarkerType.Fault)
1075 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FAULT);
1077 else if (block.exceptionType == MarkerType.Filter)
1079 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FILTER);
1081 else if (block.exceptionType == MarkerType.Finally)
1083 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FINALLY);
1087 bb.Write((int)COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1089 bb.Write(block.tryOffset);
1090 bb.Write(block.tryLength);
1091 bb.Write(block.handlerOffset);
1092 bb.Write(block.handlerLength);
1093 if (block.exceptionType != MarkerType.Fault && block.exceptionType != MarkerType.Filter && block.exceptionType != MarkerType.Finally)
1095 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1099 bb.Write(block.filterOffset);
1105 bb.Write(CorILMethod_Sect_EHTable);
1106 bb.Write((byte)(exceptions.Count * 12 + 4));
1108 foreach (ExceptionBlock block in exceptions)
1110 if (block.exceptionType == MarkerType.Fault)
1112 bb.Write(COR_ILEXCEPTION_CLAUSE_FAULT);
1114 else if (block.exceptionType == MarkerType.Filter)
1116 bb.Write(COR_ILEXCEPTION_CLAUSE_FILTER);
1118 else if (block.exceptionType == MarkerType.Finally)
1120 bb.Write(COR_ILEXCEPTION_CLAUSE_FINALLY);
1124 bb.Write(COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1126 bb.Write((short)block.tryOffset);
1127 bb.Write((byte)block.tryLength);
1128 bb.Write((short)block.handlerOffset);
1129 bb.Write((byte)block.handlerLength);
1130 if (block.exceptionType != MarkerType.Fault && block.exceptionType != MarkerType.Filter && block.exceptionType != MarkerType.Finally)
1132 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1136 bb.Write(block.filterOffset);
1144 private void WriteCode(ByteBuffer bb)
1146 int codeOffset = bb.Position;
1147 foreach (int fixup in this.tokenFixups)
1149 moduleBuilder.tokenFixupOffsets.Add(fixup + codeOffset);
1154 private void WriteScope(Scope scope, int localVarSigTok)
1156 moduleBuilder.symbolWriter.OpenScope(scope.startOffset);
1157 foreach (LocalBuilder local in scope.locals)
1159 if (local.name != null)
1161 int startOffset = local.startOffset;
1162 int endOffset = local.endOffset;
1163 if (startOffset == 0 && endOffset == 0)
1165 startOffset = scope.startOffset;
1166 endOffset = scope.endOffset;
1168 moduleBuilder.symbolWriter.DefineLocalVariable2(local.name, 0, localVarSigTok, SymAddressKind.ILOffset, local.LocalIndex, 0, 0, startOffset, endOffset);
1171 foreach (Scope child in scope.children)
1173 WriteScope(child, localVarSigTok);
1175 moduleBuilder.symbolWriter.CloseScope(scope.endOffset);