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.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 readonly ModuleBuilder moduleBuilder;
122 private readonly ByteBuffer code;
123 private readonly SignatureHelper locals;
124 private int localsCount;
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 bool fatHeader;
134 private int stackHeight;
136 private byte exceptionBlockAssistanceMode = EBAM_COMPAT;
137 private const byte EBAM_COMPAT = 0;
138 private const byte EBAM_DISABLE = 1;
139 private const byte EBAM_CLEVER = 2;
141 private struct LabelFixup
147 private sealed class ExceptionBlock : IComparer<ExceptionBlock>
149 internal readonly int ordinal;
150 internal Label labelEnd;
151 internal int tryOffset;
152 internal int tryLength;
153 internal int handlerOffset;
154 internal int handlerLength;
155 internal Type exceptionType; // MarkerType.Finally = finally block, MarkerType.Filter = handler with filter, MarkerType.Fault = fault block
156 internal int filterOffset;
158 internal ExceptionBlock(int ordinal)
160 this.ordinal = ordinal;
163 int IComparer<ExceptionBlock>.Compare(ExceptionBlock x, ExceptionBlock y)
165 // Mono's sort insists on doing unnecessary comparisons
170 else if (x.tryOffset == y.tryOffset && x.tryLength == y.tryLength)
172 return x.ordinal < y.ordinal ? -1 : 1;
174 else if (x.tryOffset >= y.tryOffset && x.handlerOffset + x.handlerLength <= y.handlerOffset + y.handlerLength)
178 else if (y.tryOffset >= x.tryOffset && y.handlerOffset + y.handlerLength <= x.handlerOffset + x.handlerLength)
184 return x.ordinal < y.ordinal ? -1 : 1;
189 private struct SequencePoint
191 internal ISymbolDocumentWriter document;
193 internal int startLine;
194 internal int startColumn;
195 internal int endLine;
196 internal int endColumn;
199 private sealed class Scope
201 internal readonly Scope parent;
202 internal readonly List<Scope> children = new List<Scope>();
203 internal readonly List<LocalBuilder> locals = new List<LocalBuilder>();
204 internal int startOffset;
205 internal int endOffset;
207 internal Scope(Scope parent)
209 this.parent = parent;
213 internal ILGenerator(ModuleBuilder moduleBuilder, int initialCapacity)
215 this.code = new ByteBuffer(initialCapacity);
216 this.moduleBuilder = moduleBuilder;
217 this.locals = SignatureHelper.GetLocalVarSigHelper(moduleBuilder);
218 if (moduleBuilder.symbolWriter != null)
220 scope = new Scope(null);
225 public void __DisableExceptionBlockAssistance()
227 exceptionBlockAssistanceMode = EBAM_DISABLE;
231 public void __CleverExceptionBlockAssistance()
233 exceptionBlockAssistanceMode = EBAM_CLEVER;
237 public int __MaxStackSize
239 get { return maxStack; }
242 maxStack = (ushort)value;
248 // returns -1 if the current position is currently unreachable
249 public int __StackHeight
251 get { return stackHeight; }
257 get { return code.Position; }
260 public void BeginCatchBlock(Type exceptionType)
262 ExceptionBlock block = exceptionStack.Peek();
263 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
265 if (exceptionType == null)
267 Emit(OpCodes.Endfilter);
271 Emit(OpCodes.Leave, block.labelEnd);
276 if (exceptionType == null)
278 if (block.exceptionType != MarkerType.Filter || block.handlerOffset != 0)
280 throw new ArgumentNullException("exceptionType");
282 block.handlerOffset = code.Position;
286 if (block.tryLength == 0)
288 block.tryLength = code.Position - block.tryOffset;
292 block.handlerLength = code.Position - block.handlerOffset;
293 exceptionStack.Pop();
294 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
295 newBlock.labelEnd = block.labelEnd;
296 newBlock.tryOffset = block.tryOffset;
297 newBlock.tryLength = block.tryLength;
299 exceptions.Add(block);
300 exceptionStack.Push(block);
302 block.exceptionType = exceptionType;
303 if (exceptionType == MarkerType.Filter)
305 block.filterOffset = code.Position;
309 block.handlerOffset = code.Position;
314 public Label BeginExceptionBlock()
316 ExceptionBlock block = new ExceptionBlock(exceptions.Count);
317 block.labelEnd = DefineLabel();
318 block.tryOffset = code.Position;
319 exceptionStack.Push(block);
320 exceptions.Add(block);
322 return block.labelEnd;
325 public void BeginExceptFilterBlock()
327 BeginCatchBlock(MarkerType.Filter);
330 public void BeginFaultBlock()
332 BeginFinallyFaultBlock(MarkerType.Fault);
335 public void BeginFinallyBlock()
337 BeginFinallyFaultBlock(MarkerType.Finally);
340 private void BeginFinallyFaultBlock(Type type)
342 ExceptionBlock block = exceptionStack.Peek();
343 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
345 Emit(OpCodes.Leave, block.labelEnd);
347 if (block.handlerOffset == 0)
349 block.tryLength = code.Position - block.tryOffset;
353 block.handlerLength = code.Position - block.handlerOffset;
355 if (exceptionBlockAssistanceMode != EBAM_COMPAT)
357 labelEnd = block.labelEnd;
361 MarkLabel(block.labelEnd);
362 labelEnd = DefineLabel();
363 Emit(OpCodes.Leave, labelEnd);
365 exceptionStack.Pop();
366 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
367 newBlock.labelEnd = labelEnd;
368 newBlock.tryOffset = block.tryOffset;
369 newBlock.tryLength = code.Position - block.tryOffset;
371 exceptions.Add(block);
372 exceptionStack.Push(block);
374 block.handlerOffset = code.Position;
375 block.exceptionType = type;
379 public void EndExceptionBlock()
381 ExceptionBlock block = exceptionStack.Pop();
382 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
384 if (block.filterOffset != 0 || (block.exceptionType != MarkerType.Finally && block.exceptionType != MarkerType.Fault))
386 Emit(OpCodes.Leave, block.labelEnd);
390 Emit(OpCodes.Endfinally);
393 MarkLabel(block.labelEnd);
394 block.handlerLength = code.Position - block.handlerOffset;
397 public void BeginScope()
399 Scope newScope = new Scope(scope);
400 scope.children.Add(newScope);
402 scope.startOffset = code.Position;
405 public void UsingNamespace(string usingNamespace)
407 if (moduleBuilder.symbolWriter != null)
409 moduleBuilder.symbolWriter.UsingNamespace(usingNamespace);
413 public LocalBuilder DeclareLocal(Type localType)
415 return DeclareLocal(localType, false);
418 public LocalBuilder DeclareLocal(Type localType, bool pinned)
420 LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned);
421 locals.AddArgument(localType, pinned);
424 scope.locals.Add(local);
429 public LocalBuilder __DeclareLocal(Type localType, bool pinned, CustomModifiers customModifiers)
431 LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned);
432 locals.__AddArgument(localType, pinned, customModifiers);
435 scope.locals.Add(local);
440 public Label DefineLabel()
442 Label label = new Label(labels.Count);
444 labelStackHeight.Add(-1);
448 public void Emit(OpCode opc)
450 Debug.Assert(opc != OpCodes.Ret || (opc == OpCodes.Ret && stackHeight <= 1));
453 code.Write((byte)(opc.Value >> 8));
455 code.Write((byte)opc.Value);
456 switch (opc.FlowControl)
458 case FlowControl.Branch:
459 case FlowControl.Break:
460 case FlowControl.Return:
461 case FlowControl.Throw:
465 UpdateStack(opc.StackDiff);
470 private void UpdateStack(int stackdiff)
472 if (stackHeight == -1)
474 // we're about to emit code that is either unreachable or reachable only via a backward branch
477 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
478 stackHeight += stackdiff;
479 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
480 maxStack = Math.Max(maxStack, (ushort)stackHeight);
483 public void Emit(OpCode opc, byte arg)
489 public void Emit(OpCode opc, double arg)
495 public void Emit(OpCode opc, FieldInfo field)
498 WriteToken(moduleBuilder.GetFieldToken(field));
501 public void Emit(OpCode opc, short arg)
507 public void Emit(OpCode opc, int arg)
513 public void Emit(OpCode opc, long arg)
519 public void Emit(OpCode opc, Label label)
521 // We need special stackHeight handling for unconditional branches,
522 // because the branch and next flows have differing stack heights.
523 // Note that this assumes that unconditional branches do not push/pop.
524 int flowStackHeight = this.stackHeight;
526 if (opc == OpCodes.Leave || opc == OpCodes.Leave_S)
530 else if (opc.FlowControl != FlowControl.Branch)
532 flowStackHeight = this.stackHeight;
534 // if the label has already been marked, we can emit the branch offset directly
535 if (labels[label.Index] != -1)
537 if (labelStackHeight[label.Index] != flowStackHeight && (labelStackHeight[label.Index] != 0 || flowStackHeight != -1))
539 // the "backward branch constraint" prohibits this, so we don't need to support it
540 throw new NotSupportedException("'Backward branch constraints' violated");
542 if (opc.OperandType == OperandType.ShortInlineBrTarget)
544 WriteByteBranchOffset(labels[label.Index] - (code.Position + 1));
548 code.Write(labels[label.Index] - (code.Position + 4));
553 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == flowStackHeight || (flowStackHeight == -1 && labelStackHeight[label.Index] == 0));
554 labelStackHeight[label.Index] = flowStackHeight;
555 LabelFixup fix = new LabelFixup();
556 fix.label = label.Index;
557 fix.offset = code.Position;
558 labelFixups.Add(fix);
559 if (opc.OperandType == OperandType.ShortInlineBrTarget)
570 private void WriteByteBranchOffset(int offset)
572 if (offset < -128 || offset > 127)
574 throw new NotSupportedException("Branch offset of " + offset + " does not fit in one-byte branch target at position " + code.Position);
576 code.Write((byte)offset);
579 public void Emit(OpCode opc, Label[] labels)
582 LabelFixup fix = new LabelFixup();
584 fix.offset = code.Position;
585 labelFixups.Add(fix);
586 code.Write(labels.Length);
587 foreach (Label label in labels)
589 code.Write(label.Index);
590 if (this.labels[label.Index] != -1)
592 if (labelStackHeight[label.Index] != stackHeight)
594 // the "backward branch constraint" prohibits this, so we don't need to support it
595 throw new NotSupportedException();
600 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == stackHeight);
601 labelStackHeight[label.Index] = stackHeight;
606 public void Emit(OpCode opc, LocalBuilder local)
608 if ((opc == OpCodes.Ldloc || opc == OpCodes.Ldloca || opc == OpCodes.Stloc) && local.LocalIndex < 256)
610 if (opc == OpCodes.Ldloc)
612 switch (local.LocalIndex)
615 Emit(OpCodes.Ldloc_0);
618 Emit(OpCodes.Ldloc_1);
621 Emit(OpCodes.Ldloc_2);
624 Emit(OpCodes.Ldloc_3);
627 Emit(OpCodes.Ldloc_S);
628 code.Write((byte)local.LocalIndex);
632 else if (opc == OpCodes.Ldloca)
634 Emit(OpCodes.Ldloca_S);
635 code.Write((byte)local.LocalIndex);
637 else if (opc == OpCodes.Stloc)
639 switch (local.LocalIndex)
642 Emit(OpCodes.Stloc_0);
645 Emit(OpCodes.Stloc_1);
648 Emit(OpCodes.Stloc_2);
651 Emit(OpCodes.Stloc_3);
654 Emit(OpCodes.Stloc_S);
655 code.Write((byte)local.LocalIndex);
663 switch (opc.OperandType)
665 case OperandType.InlineVar:
666 code.Write((ushort)local.LocalIndex);
668 case OperandType.ShortInlineVar:
669 code.Write((byte)local.LocalIndex);
675 private void WriteToken(FieldToken token)
677 if (token.IsPseudoToken)
679 tokenFixups.Add(code.Position);
681 code.Write(token.Token);
684 private void WriteToken(MethodToken token)
686 if (token.IsPseudoToken)
688 tokenFixups.Add(code.Position);
690 code.Write(token.Token);
693 private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
695 if (opc == OpCodes.Jmp)
699 else if (opc.FlowControl == FlowControl.Call)
702 if ((hasthis && opc != OpCodes.Newobj) || opc == OpCodes.Calli)
708 stackdiff -= parameterCount;
709 if (returnType != moduleBuilder.universe.System_Void)
714 UpdateStack(stackdiff);
718 public void Emit(OpCode opc, MethodInfo method)
720 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount);
722 WriteToken(moduleBuilder.GetMethodTokenForIL(method));
725 public void Emit(OpCode opc, ConstructorInfo constructor)
727 Emit(opc, constructor.GetMethodInfo());
730 public void Emit(OpCode opc, sbyte arg)
736 public void Emit(OpCode opc, float arg)
742 public void Emit(OpCode opc, string str)
745 code.Write(moduleBuilder.GetStringConstant(str).Token);
748 public void Emit(OpCode opc, Type type)
751 if (opc == OpCodes.Ldtoken)
753 code.Write(moduleBuilder.GetTypeToken(type).Token);
757 code.Write(moduleBuilder.GetTypeTokenForMemberRef(type));
761 public void Emit(OpCode opcode, SignatureHelper signature)
764 UpdateStack(opcode, signature.HasThis, signature.ReturnType, signature.ParameterCount);
765 code.Write(moduleBuilder.GetSignatureToken(signature).Token);
768 public void EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes)
770 __EmitCall(opc, method, optionalParameterTypes, null);
773 public void __EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
775 if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
782 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount + optionalParameterTypes.Length);
783 code.Write(moduleBuilder.__GetMethodToken(method, optionalParameterTypes, customModifiers).Token);
787 public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes)
789 EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes);
792 public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
794 __EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes, customModifiers);
797 public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
799 SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
800 sig.AddArguments(parameterTypes, null, null);
804 public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
806 SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
807 sig.AddArguments(parameterTypes, null, null);
809 sig.AddArguments(optionalParameterTypes, null, null);
813 public void __EmitCalli(OpCode opc, __StandAloneMethodSig sig)
818 UpdateStack(opc, false, sig.ReturnType, sig.ParameterCount);
822 CallingConventions callingConvention = sig.CallingConvention;
823 UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, sig.ReturnType, sig.ParameterCount);
825 ByteBuffer bb = new ByteBuffer(16);
826 Signature.WriteStandAloneMethodSig(moduleBuilder, bb, sig);
827 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(bb)));
830 public void EmitWriteLine(string text)
832 Universe u = moduleBuilder.universe;
833 Emit(OpCodes.Ldstr, text);
834 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("WriteLine", new Type[] { u.System_String }));
837 public void EmitWriteLine(FieldInfo field)
839 Universe u = moduleBuilder.universe;
840 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
843 Emit(OpCodes.Ldsfld, field);
847 Emit(OpCodes.Ldarg_0);
848 Emit(OpCodes.Ldfld, field);
850 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { field.FieldType }));
853 public void EmitWriteLine(LocalBuilder local)
855 Universe u = moduleBuilder.universe;
856 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
857 Emit(OpCodes.Ldloc, local);
858 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { local.LocalType }));
861 public void EndScope()
863 scope.endOffset = code.Position;
864 scope = scope.parent;
867 public void MarkLabel(Label loc)
869 Debug.Assert(stackHeight == -1 || labelStackHeight[loc.Index] == -1 || stackHeight == labelStackHeight[loc.Index]);
870 labels[loc.Index] = code.Position;
871 if (labelStackHeight[loc.Index] == -1)
873 if (stackHeight == -1)
875 // We're at a location that can only be reached by a backward branch,
876 // so according to the "backward branch constraint" that must mean the stack is empty,
877 // but note that this may be an unused label followed by another label that is used and
878 // that does have a non-zero stack height, so we don't yet set stackHeight here.
879 labelStackHeight[loc.Index] = 0;
883 labelStackHeight[loc.Index] = stackHeight;
888 Debug.Assert(stackHeight == -1 || stackHeight == labelStackHeight[loc.Index]);
889 stackHeight = labelStackHeight[loc.Index];
893 public void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
895 SequencePoint sp = new SequencePoint();
896 sp.document = document;
897 sp.offset = code.Position;
898 sp.startLine = startLine;
899 sp.startColumn = startColumn;
900 sp.endLine = endLine;
901 sp.endColumn = endColumn;
902 sequencePoints.Add(sp);
905 public void ThrowException(Type excType)
907 Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
911 internal int WriteBody(bool initLocals)
913 if (moduleBuilder.symbolWriter != null)
915 Debug.Assert(scope != null && scope.parent == null);
916 scope.endOffset = code.Position;
921 ByteBuffer bb = moduleBuilder.methodBodies;
923 int localVarSigTok = 0;
926 if (localsCount == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64 && !fatHeader)
928 rva = WriteTinyHeaderAndCode(bb);
932 rva = WriteFatHeaderAndCode(bb, ref localVarSigTok, initLocals);
935 if (moduleBuilder.symbolWriter != null)
937 if (sequencePoints.Count != 0)
939 ISymbolDocumentWriter document = sequencePoints[0].document;
940 int[] offsets = new int[sequencePoints.Count];
941 int[] lines = new int[sequencePoints.Count];
942 int[] columns = new int[sequencePoints.Count];
943 int[] endLines = new int[sequencePoints.Count];
944 int[] endColumns = new int[sequencePoints.Count];
945 for (int i = 0; i < sequencePoints.Count; i++)
947 if (sequencePoints[i].document != document)
949 throw new NotImplementedException();
951 offsets[i] = sequencePoints[i].offset;
952 lines[i] = sequencePoints[i].startLine;
953 columns[i] = sequencePoints[i].startColumn;
954 endLines[i] = sequencePoints[i].endLine;
955 endColumns[i] = sequencePoints[i].endColumn;
957 moduleBuilder.symbolWriter.DefineSequencePoints(document, offsets, lines, columns, endLines, endColumns);
960 WriteScope(scope, localVarSigTok);
965 private void ResolveBranches()
967 foreach (LabelFixup fixup in labelFixups)
970 if (fixup.label == -1)
972 code.Position = fixup.offset;
973 int count = code.GetInt32AtCurrentPosition();
974 int offset = fixup.offset + 4 + 4 * count;
976 for (int i = 0; i < count; i++)
978 int index = code.GetInt32AtCurrentPosition();
979 code.Write(labels[index] - offset);
984 code.Position = fixup.offset;
985 byte size = code.GetByteAtCurrentPosition();
986 int branchOffset = labels[fixup.label] - (code.Position + size);
989 WriteByteBranchOffset(branchOffset);
993 code.Write(branchOffset);
999 private int WriteTinyHeaderAndCode(ByteBuffer bb)
1001 int rva = bb.Position;
1002 const byte CorILMethod_TinyFormat = 0x2;
1003 bb.Write((byte)(CorILMethod_TinyFormat | (code.Length << 2)));
1008 private int WriteFatHeaderAndCode(ByteBuffer bb, ref int localVarSigTok, bool initLocals)
1010 // fat headers require 4-byte alignment
1012 int rva = bb.Position;
1014 if (localsCount != 0)
1016 localVarSigTok = moduleBuilder.GetSignatureToken(locals).Token;
1019 const byte CorILMethod_FatFormat = 0x03;
1020 const byte CorILMethod_MoreSects = 0x08;
1021 const byte CorILMethod_InitLocals = 0x10;
1023 short flagsAndSize = (short)(CorILMethod_FatFormat | (3 << 12));
1026 flagsAndSize |= CorILMethod_InitLocals;
1029 if (exceptions.Count > 0)
1031 flagsAndSize |= CorILMethod_MoreSects;
1034 bb.Write(flagsAndSize);
1036 bb.Write(code.Length);
1037 bb.Write(localVarSigTok);
1041 if (exceptions.Count > 0)
1046 foreach (ExceptionBlock block in exceptions)
1048 if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
1054 exceptions.Sort(exceptions[0]);
1055 if (exceptions.Count * 12 + 4 > 255)
1059 const byte CorILMethod_Sect_EHTable = 0x1;
1060 const byte CorILMethod_Sect_FatFormat = 0x40;
1061 const short COR_ILEXCEPTION_CLAUSE_EXCEPTION = 0x0000;
1062 const short COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001;
1063 const short COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002;
1064 const short COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004;
1068 bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
1069 int dataSize = exceptions.Count * 24 + 4;
1070 bb.Write((byte)dataSize);
1071 bb.Write((short)(dataSize >> 8));
1072 foreach (ExceptionBlock block in exceptions)
1074 if (block.exceptionType == MarkerType.Fault)
1076 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FAULT);
1078 else if (block.exceptionType == MarkerType.Filter)
1080 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FILTER);
1082 else if (block.exceptionType == MarkerType.Finally)
1084 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FINALLY);
1088 bb.Write((int)COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1090 bb.Write(block.tryOffset);
1091 bb.Write(block.tryLength);
1092 bb.Write(block.handlerOffset);
1093 bb.Write(block.handlerLength);
1094 if (block.exceptionType != MarkerType.Fault && block.exceptionType != MarkerType.Filter && block.exceptionType != MarkerType.Finally)
1096 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1100 bb.Write(block.filterOffset);
1106 bb.Write(CorILMethod_Sect_EHTable);
1107 bb.Write((byte)(exceptions.Count * 12 + 4));
1109 foreach (ExceptionBlock block in exceptions)
1111 if (block.exceptionType == MarkerType.Fault)
1113 bb.Write(COR_ILEXCEPTION_CLAUSE_FAULT);
1115 else if (block.exceptionType == MarkerType.Filter)
1117 bb.Write(COR_ILEXCEPTION_CLAUSE_FILTER);
1119 else if (block.exceptionType == MarkerType.Finally)
1121 bb.Write(COR_ILEXCEPTION_CLAUSE_FINALLY);
1125 bb.Write(COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1127 bb.Write((short)block.tryOffset);
1128 bb.Write((byte)block.tryLength);
1129 bb.Write((short)block.handlerOffset);
1130 bb.Write((byte)block.handlerLength);
1131 if (block.exceptionType != MarkerType.Fault && block.exceptionType != MarkerType.Filter && block.exceptionType != MarkerType.Finally)
1133 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1137 bb.Write(block.filterOffset);
1145 private void WriteCode(ByteBuffer bb)
1147 int codeOffset = bb.Position;
1148 foreach (int fixup in this.tokenFixups)
1150 moduleBuilder.tokenFixupOffsets.Add(fixup + codeOffset);
1155 private void WriteScope(Scope scope, int localVarSigTok)
1157 moduleBuilder.symbolWriter.OpenScope(scope.startOffset);
1158 foreach (LocalBuilder local in scope.locals)
1160 if (local.name != null)
1162 int startOffset = local.startOffset;
1163 int endOffset = local.endOffset;
1164 if (startOffset == 0 && endOffset == 0)
1166 startOffset = scope.startOffset;
1167 endOffset = scope.endOffset;
1169 moduleBuilder.symbolWriter.DefineLocalVariable2(local.name, 0, localVarSigTok, SymAddressKind.ILOffset, local.LocalIndex, 0, 0, startOffset, endOffset);
1172 foreach (Scope child in scope.children)
1174 WriteScope(child, localVarSigTok);
1176 moduleBuilder.symbolWriter.CloseScope(scope.endOffset);