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 sealed class MarkerType : Type
121 public override Type BaseType
123 get { throw new InvalidOperationException(); }
126 public override TypeAttributes Attributes
128 get { throw new InvalidOperationException(); }
131 public override string Name
133 get { throw new InvalidOperationException(); }
136 public override string FullName
138 get { throw new InvalidOperationException(); }
141 public override Module Module
143 get { throw new InvalidOperationException(); }
147 public sealed class ILGenerator
149 private static readonly Type FAULT = new MarkerType();
150 private static readonly Type FINALLY = new MarkerType();
151 private static readonly Type FILTER = new MarkerType();
152 private readonly ModuleBuilder moduleBuilder;
153 private readonly ByteBuffer code;
154 private readonly List<LocalBuilder> locals = new List<LocalBuilder>();
155 private readonly List<int> tokenFixups = new List<int>();
156 private readonly List<int> labels = new List<int>();
157 private readonly List<int> labelStackHeight = new List<int>();
158 private readonly List<LabelFixup> labelFixups = new List<LabelFixup>();
159 private readonly List<SequencePoint> sequencePoints = new List<SequencePoint>();
160 private readonly List<ExceptionBlock> exceptions = new List<ExceptionBlock>();
161 private readonly Stack<ExceptionBlock> exceptionStack = new Stack<ExceptionBlock>();
162 private ushort maxStack;
163 private bool fatHeader;
164 private int stackHeight;
166 private byte exceptionBlockAssistanceMode = EBAM_COMPAT;
167 private const byte EBAM_COMPAT = 0;
168 private const byte EBAM_DISABLE = 1;
169 private const byte EBAM_CLEVER = 2;
171 private struct LabelFixup
177 private sealed class ExceptionBlock : IComparer<ExceptionBlock>
179 internal readonly int ordinal;
180 internal Label labelEnd;
181 internal int tryOffset;
182 internal int tryLength;
183 internal int handlerOffset;
184 internal int handlerLength;
185 internal Type exceptionType; // FINALLY = finally block, FILTER = handler with filter, FAULT = fault block
186 internal int filterOffset;
188 internal ExceptionBlock(int ordinal)
190 this.ordinal = ordinal;
193 int IComparer<ExceptionBlock>.Compare(ExceptionBlock x, ExceptionBlock y)
195 // Mono's sort insists on doing unnecessary comparisons
200 else if (x.tryOffset == y.tryOffset && x.tryLength == y.tryLength)
202 return x.ordinal < y.ordinal ? -1 : 1;
204 else if (x.tryOffset >= y.tryOffset && x.handlerOffset + x.handlerLength <= y.handlerOffset + y.handlerLength)
208 else if (y.tryOffset >= x.tryOffset && y.handlerOffset + y.handlerLength <= x.handlerOffset + x.handlerLength)
214 return x.ordinal < y.ordinal ? -1 : 1;
219 private struct SequencePoint
221 internal ISymbolDocumentWriter document;
223 internal int startLine;
224 internal int startColumn;
225 internal int endLine;
226 internal int endColumn;
229 private sealed class Scope
231 internal readonly Scope parent;
232 internal readonly List<Scope> children = new List<Scope>();
233 internal readonly List<LocalBuilder> locals = new List<LocalBuilder>();
234 internal int startOffset;
235 internal int endOffset;
237 internal Scope(Scope parent)
239 this.parent = parent;
243 internal ILGenerator(ModuleBuilder moduleBuilder, int initialCapacity)
245 this.code = new ByteBuffer(initialCapacity);
246 this.moduleBuilder = moduleBuilder;
247 if (moduleBuilder.symbolWriter != null)
249 scope = new Scope(null);
253 private bool IsLabelReachable(Label label)
255 return labelStackHeight[label.Index] != -1;
259 public void __DisableExceptionBlockAssistance()
261 exceptionBlockAssistanceMode = EBAM_DISABLE;
265 public void __CleverExceptionBlockAssistance()
267 exceptionBlockAssistanceMode = EBAM_CLEVER;
271 public int __MaxStackSize
273 get { return maxStack; }
276 maxStack = (ushort)value;
284 get { return code.Position; }
287 public void BeginCatchBlock(Type exceptionType)
289 ExceptionBlock block = exceptionStack.Peek();
290 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
292 if (exceptionType == null)
294 Emit(OpCodes.Endfilter);
298 Emit(OpCodes.Leave, block.labelEnd);
303 if (exceptionType == null)
305 if (block.exceptionType != FILTER || block.handlerOffset != 0)
307 throw new ArgumentNullException("exceptionType");
309 block.handlerOffset = code.Position;
313 if (block.tryLength == 0)
315 block.tryLength = code.Position - block.tryOffset;
319 block.handlerLength = code.Position - block.handlerOffset;
320 exceptionStack.Pop();
321 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
322 newBlock.labelEnd = block.labelEnd;
323 newBlock.tryOffset = block.tryOffset;
324 newBlock.tryLength = block.tryLength;
326 exceptions.Add(block);
327 exceptionStack.Push(block);
329 block.exceptionType = exceptionType;
330 if (exceptionType == FILTER)
332 block.filterOffset = code.Position;
336 block.handlerOffset = code.Position;
341 public Label BeginExceptionBlock()
343 ExceptionBlock block = new ExceptionBlock(exceptions.Count);
344 block.labelEnd = DefineLabel();
345 block.tryOffset = code.Position;
346 exceptionStack.Push(block);
347 exceptions.Add(block);
349 return block.labelEnd;
352 public void BeginExceptFilterBlock()
354 BeginCatchBlock(FILTER);
357 public void BeginFaultBlock()
359 BeginFinallyFaultBlock(FAULT);
362 public void BeginFinallyBlock()
364 BeginFinallyFaultBlock(FINALLY);
367 private void BeginFinallyFaultBlock(Type type)
369 ExceptionBlock block = exceptionStack.Peek();
370 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
372 Emit(OpCodes.Leave, block.labelEnd);
374 if (block.handlerOffset == 0)
376 block.tryLength = code.Position - block.tryOffset;
380 block.handlerLength = code.Position - block.handlerOffset;
382 if (exceptionBlockAssistanceMode != EBAM_COMPAT)
384 labelEnd = block.labelEnd;
388 MarkLabel(block.labelEnd);
389 labelEnd = DefineLabel();
390 Emit(OpCodes.Leave, labelEnd);
392 exceptionStack.Pop();
393 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
394 newBlock.labelEnd = labelEnd;
395 newBlock.tryOffset = block.tryOffset;
396 newBlock.tryLength = code.Position - block.tryOffset;
398 exceptions.Add(block);
399 exceptionStack.Push(block);
401 block.handlerOffset = code.Position;
402 block.exceptionType = type;
406 public void EndExceptionBlock()
408 ExceptionBlock block = exceptionStack.Pop();
409 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
411 if (block.filterOffset != 0 || (block.exceptionType != FINALLY && block.exceptionType != FAULT))
413 Emit(OpCodes.Leave, block.labelEnd);
417 Emit(OpCodes.Endfinally);
420 MarkLabel(block.labelEnd);
421 block.handlerLength = code.Position - block.handlerOffset;
424 public void BeginScope()
426 Scope newScope = new Scope(scope);
427 scope.children.Add(newScope);
429 scope.startOffset = code.Position;
432 public void UsingNamespace(string usingNamespace)
434 if (moduleBuilder.symbolWriter != null)
436 moduleBuilder.symbolWriter.UsingNamespace(usingNamespace);
440 public LocalBuilder DeclareLocal(Type localType)
442 return DeclareLocal(localType, false);
445 public LocalBuilder DeclareLocal(Type localType, bool pinned)
447 LocalBuilder local = new LocalBuilder(localType, locals.Count, pinned);
451 scope.locals.Add(local);
456 public Label DefineLabel()
458 Label label = new Label(labels.Count);
460 labelStackHeight.Add(-1);
464 public void Emit(OpCode opc)
466 Debug.Assert(opc != OpCodes.Ret || (opc == OpCodes.Ret && stackHeight <= 1));
469 code.Write((byte)(opc.Value >> 8));
471 code.Write((byte)opc.Value);
472 switch (opc.FlowControl)
474 case FlowControl.Branch:
475 case FlowControl.Break:
476 case FlowControl.Return:
477 case FlowControl.Throw:
481 UpdateStack(opc.StackDiff);
486 private void UpdateStack(int stackdiff)
488 if (stackHeight == -1)
490 // we're about to emit code that is either unreachable or reachable only via a backward branch
493 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
494 stackHeight += stackdiff;
495 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
496 maxStack = Math.Max(maxStack, (ushort)stackHeight);
499 public void Emit(OpCode opc, byte arg)
505 public void Emit(OpCode opc, double arg)
511 public void Emit(OpCode opc, FieldInfo field)
514 WriteToken(moduleBuilder.GetFieldToken(field));
517 public void Emit(OpCode opc, short arg)
523 public void Emit(OpCode opc, int arg)
529 public void Emit(OpCode opc, long arg)
535 public void Emit(OpCode opc, Label label)
537 // We need special stackHeight handling for unconditional branches,
538 // because the branch and next flows have differing stack heights.
539 // Note that this assumes that unconditional branches do not push/pop.
540 int flowStackHeight = this.stackHeight;
542 if (opc == OpCodes.Leave || opc == OpCodes.Leave_S)
546 else if (opc.FlowControl != FlowControl.Branch)
548 flowStackHeight = this.stackHeight;
550 // if the label has already been marked, we can emit the branch offset directly
551 if (labels[label.Index] != -1)
553 if (labelStackHeight[label.Index] != flowStackHeight && (labelStackHeight[label.Index] != 0 || flowStackHeight != -1))
555 // the "backward branch constraint" prohibits this, so we don't need to support it
556 throw new NotSupportedException("'Backward branch constraints' violated");
558 if (opc.OperandType == OperandType.ShortInlineBrTarget)
560 WriteByteBranchOffset(labels[label.Index] - (code.Position + 1));
564 code.Write(labels[label.Index] - (code.Position + 4));
569 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == flowStackHeight || (flowStackHeight == -1 && labelStackHeight[label.Index] == 0));
570 labelStackHeight[label.Index] = flowStackHeight;
571 LabelFixup fix = new LabelFixup();
572 fix.label = label.Index;
573 fix.offset = code.Position;
574 labelFixups.Add(fix);
575 if (opc.OperandType == OperandType.ShortInlineBrTarget)
586 private void WriteByteBranchOffset(int offset)
588 if (offset < -128 || offset > 127)
590 throw new NotSupportedException("Branch offset of " + offset + " does not fit in one-byte branch target at position " + code.Position);
592 code.Write((byte)offset);
595 public void Emit(OpCode opc, Label[] labels)
598 LabelFixup fix = new LabelFixup();
600 fix.offset = code.Position;
601 labelFixups.Add(fix);
602 code.Write(labels.Length);
603 foreach (Label label in labels)
605 code.Write(label.Index);
606 if (this.labels[label.Index] != -1)
608 if (labelStackHeight[label.Index] != stackHeight)
610 // the "backward branch constraint" prohibits this, so we don't need to support it
611 throw new NotSupportedException();
616 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == stackHeight);
617 labelStackHeight[label.Index] = stackHeight;
622 public void Emit(OpCode opc, LocalBuilder local)
624 if ((opc == OpCodes.Ldloc || opc == OpCodes.Ldloca || opc == OpCodes.Stloc) && local.LocalIndex < 256)
626 if (opc == OpCodes.Ldloc)
628 switch (local.LocalIndex)
631 Emit(OpCodes.Ldloc_0);
634 Emit(OpCodes.Ldloc_1);
637 Emit(OpCodes.Ldloc_2);
640 Emit(OpCodes.Ldloc_3);
643 Emit(OpCodes.Ldloc_S);
644 code.Write((byte)local.LocalIndex);
648 else if (opc == OpCodes.Ldloca)
650 Emit(OpCodes.Ldloca_S);
651 code.Write((byte)local.LocalIndex);
653 else if (opc == OpCodes.Stloc)
655 switch (local.LocalIndex)
658 Emit(OpCodes.Stloc_0);
661 Emit(OpCodes.Stloc_1);
664 Emit(OpCodes.Stloc_2);
667 Emit(OpCodes.Stloc_3);
670 Emit(OpCodes.Stloc_S);
671 code.Write((byte)local.LocalIndex);
679 switch (opc.OperandType)
681 case OperandType.InlineVar:
682 code.Write((ushort)local.LocalIndex);
684 case OperandType.ShortInlineVar:
685 code.Write((byte)local.LocalIndex);
691 private void WriteToken(FieldToken token)
693 if (token.IsPseudoToken)
695 tokenFixups.Add(code.Position);
697 code.Write(token.Token);
700 private void WriteToken(MethodToken token)
702 if (token.IsPseudoToken)
704 tokenFixups.Add(code.Position);
706 code.Write(token.Token);
709 private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
711 if (opc == OpCodes.Jmp)
715 else if (opc.FlowControl == FlowControl.Call)
718 if ((hasthis && opc != OpCodes.Newobj) || opc == OpCodes.Calli)
724 stackdiff -= parameterCount;
725 if (returnType != moduleBuilder.universe.System_Void)
730 UpdateStack(stackdiff);
734 public void Emit(OpCode opc, MethodInfo method)
736 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount);
738 WriteToken(moduleBuilder.GetMethodTokenForIL(method));
741 public void Emit(OpCode opc, ConstructorInfo constructor)
743 Emit(opc, constructor.GetMethodInfo());
746 public void Emit(OpCode opc, sbyte arg)
752 public void Emit(OpCode opc, float arg)
758 public void Emit(OpCode opc, string str)
761 code.Write(0x70000000 | moduleBuilder.UserStrings.Add(str));
764 public void Emit(OpCode opc, Type type)
767 if (opc == OpCodes.Ldtoken)
769 code.Write(moduleBuilder.GetTypeToken(type).Token);
773 code.Write(moduleBuilder.GetTypeTokenForMemberRef(type));
777 public void Emit(OpCode opcode, SignatureHelper signature)
780 UpdateStack(opcode, signature.HasThis, signature.ReturnType, signature.ParameterCount);
781 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(signature.GetSignature(moduleBuilder))));
784 public void EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes)
786 if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
793 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount + optionalParameterTypes.Length);
794 ByteBuffer sig = new ByteBuffer(16);
795 method.MethodSignature.WriteMethodRefSig(moduleBuilder, sig, optionalParameterTypes);
796 MemberRefTable.Record record = new MemberRefTable.Record();
797 if (method.Module == moduleBuilder)
799 record.Class = method.MetadataToken;
803 record.Class = moduleBuilder.GetTypeTokenForMemberRef(method.DeclaringType ?? method.Module.GetModuleType());
805 record.Name = moduleBuilder.Strings.Add(method.Name);
806 record.Signature = moduleBuilder.Blobs.Add(sig);
807 code.Write(0x0A000000 | moduleBuilder.MemberRef.FindOrAddRecord(record));
811 public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes)
813 EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes);
816 public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
818 returnType = returnType ?? moduleBuilder.universe.System_Void;
820 UpdateStack(opc, false, returnType, parameterTypes.Length);
821 ByteBuffer sig = new ByteBuffer(16);
822 Signature.WriteStandAloneMethodSig(moduleBuilder, sig, callingConvention, returnType, parameterTypes);
823 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(sig)));
826 public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
828 returnType = returnType ?? moduleBuilder.universe.System_Void;
829 optionalParameterTypes = optionalParameterTypes ?? Type.EmptyTypes;
831 UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, returnType, parameterTypes.Length + optionalParameterTypes.Length);
832 ByteBuffer sig = new ByteBuffer(16);
833 Signature.WriteStandAloneMethodSig(moduleBuilder, sig, callingConvention, returnType, parameterTypes, optionalParameterTypes);
834 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(sig)));
837 public void EmitWriteLine(string text)
839 Universe u = moduleBuilder.universe;
840 Emit(OpCodes.Ldstr, text);
841 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("WriteLine", new Type[] { u.System_String }));
844 public void EmitWriteLine(FieldInfo field)
846 Universe u = moduleBuilder.universe;
847 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
850 Emit(OpCodes.Ldsfld, field);
854 Emit(OpCodes.Ldarg_0);
855 Emit(OpCodes.Ldfld, field);
857 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { field.FieldType }));
860 public void EmitWriteLine(LocalBuilder local)
862 Universe u = moduleBuilder.universe;
863 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
864 Emit(OpCodes.Ldloc, local);
865 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { local.LocalType }));
868 public void EndScope()
870 scope.endOffset = code.Position;
871 scope = scope.parent;
874 public void MarkLabel(Label loc)
876 Debug.Assert(stackHeight == -1 || labelStackHeight[loc.Index] == -1 || stackHeight == labelStackHeight[loc.Index]);
877 labels[loc.Index] = code.Position;
878 if (labelStackHeight[loc.Index] == -1)
880 if (stackHeight == -1)
882 // We're at a location that can only be reached by a backward branch,
883 // so according to the "backward branch constraint" that must mean the stack is empty,
884 // but note that this may be an unused label followed by another label that is used and
885 // that does have a non-zero stack height, so we don't yet set stackHeight here.
886 labelStackHeight[loc.Index] = 0;
890 labelStackHeight[loc.Index] = stackHeight;
895 Debug.Assert(stackHeight == -1 || stackHeight == labelStackHeight[loc.Index]);
896 stackHeight = labelStackHeight[loc.Index];
900 public void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
902 SequencePoint sp = new SequencePoint();
903 sp.document = document;
904 sp.offset = code.Position;
905 sp.startLine = startLine;
906 sp.startColumn = startColumn;
907 sp.endLine = endLine;
908 sp.endColumn = endColumn;
909 sequencePoints.Add(sp);
912 public void ThrowException(Type excType)
914 Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
918 internal int WriteBody(bool initLocals)
920 if (moduleBuilder.symbolWriter != null)
922 Debug.Assert(scope != null && scope.parent == null);
923 scope.endOffset = code.Position;
928 ByteBuffer bb = moduleBuilder.methodBodies;
930 int localVarSigTok = 0;
933 if (locals.Count == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64 && !fatHeader)
935 rva = WriteTinyHeaderAndCode(bb);
939 rva = WriteFatHeaderAndCode(bb, ref localVarSigTok, initLocals);
942 if (moduleBuilder.symbolWriter != null)
944 if (sequencePoints.Count != 0)
946 ISymbolDocumentWriter document = sequencePoints[0].document;
947 int[] offsets = new int[sequencePoints.Count];
948 int[] lines = new int[sequencePoints.Count];
949 int[] columns = new int[sequencePoints.Count];
950 int[] endLines = new int[sequencePoints.Count];
951 int[] endColumns = new int[sequencePoints.Count];
952 for (int i = 0; i < sequencePoints.Count; i++)
954 if (sequencePoints[i].document != document)
956 throw new NotImplementedException();
958 offsets[i] = sequencePoints[i].offset;
959 lines[i] = sequencePoints[i].startLine;
960 columns[i] = sequencePoints[i].startColumn;
961 endLines[i] = sequencePoints[i].endLine;
962 endColumns[i] = sequencePoints[i].endColumn;
964 moduleBuilder.symbolWriter.DefineSequencePoints(document, offsets, lines, columns, endLines, endColumns);
967 WriteScope(scope, localVarSigTok);
972 private void ResolveBranches()
974 foreach (LabelFixup fixup in labelFixups)
977 if (fixup.label == -1)
979 code.Position = fixup.offset;
980 int count = code.GetInt32AtCurrentPosition();
981 int offset = fixup.offset + 4 + 4 * count;
983 for (int i = 0; i < count; i++)
985 int index = code.GetInt32AtCurrentPosition();
986 code.Write(labels[index] - offset);
991 code.Position = fixup.offset;
992 byte size = code.GetByteAtCurrentPosition();
993 int branchOffset = labels[fixup.label] - (code.Position + size);
996 WriteByteBranchOffset(branchOffset);
1000 code.Write(branchOffset);
1006 private int WriteTinyHeaderAndCode(ByteBuffer bb)
1008 int rva = bb.Position;
1009 const byte CorILMethod_TinyFormat = 0x2;
1010 bb.Write((byte)(CorILMethod_TinyFormat | (code.Length << 2)));
1015 private int WriteFatHeaderAndCode(ByteBuffer bb, ref int localVarSigTok, bool initLocals)
1017 // fat headers require 4-byte alignment
1019 int rva = bb.Position;
1021 if (locals.Count != 0)
1023 ByteBuffer localVarSig = new ByteBuffer(locals.Count + 2);
1024 Signature.WriteLocalVarSig(moduleBuilder, localVarSig, locals);
1025 localVarSigTok = 0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(localVarSig));
1028 const byte CorILMethod_FatFormat = 0x03;
1029 const byte CorILMethod_MoreSects = 0x08;
1030 const byte CorILMethod_InitLocals = 0x10;
1032 short flagsAndSize = (short)(CorILMethod_FatFormat | (3 << 12));
1035 flagsAndSize |= CorILMethod_InitLocals;
1038 if (exceptions.Count > 0)
1040 flagsAndSize |= CorILMethod_MoreSects;
1043 bb.Write(flagsAndSize);
1045 bb.Write(code.Length);
1046 bb.Write(localVarSigTok);
1050 if (exceptions.Count > 0)
1055 foreach (ExceptionBlock block in exceptions)
1057 if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
1063 exceptions.Sort(exceptions[0]);
1064 if (exceptions.Count * 12 + 4 > 255)
1068 const byte CorILMethod_Sect_EHTable = 0x1;
1069 const byte CorILMethod_Sect_FatFormat = 0x40;
1070 const short COR_ILEXCEPTION_CLAUSE_EXCEPTION = 0x0000;
1071 const short COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001;
1072 const short COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002;
1073 const short COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004;
1077 bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
1078 int dataSize = exceptions.Count * 24 + 4;
1079 bb.Write((byte)dataSize);
1080 bb.Write((short)(dataSize >> 8));
1081 foreach (ExceptionBlock block in exceptions)
1083 if (block.exceptionType == FAULT)
1085 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FAULT);
1087 else if (block.exceptionType == FILTER)
1089 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FILTER);
1091 else if (block.exceptionType == FINALLY)
1093 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FINALLY);
1097 bb.Write((int)COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1099 bb.Write(block.tryOffset);
1100 bb.Write(block.tryLength);
1101 bb.Write(block.handlerOffset);
1102 bb.Write(block.handlerLength);
1103 if (block.exceptionType != FAULT && block.exceptionType != FILTER && block.exceptionType != FINALLY)
1105 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1109 bb.Write(block.filterOffset);
1115 bb.Write(CorILMethod_Sect_EHTable);
1116 bb.Write((byte)(exceptions.Count * 12 + 4));
1118 foreach (ExceptionBlock block in exceptions)
1120 if (block.exceptionType == FAULT)
1122 bb.Write(COR_ILEXCEPTION_CLAUSE_FAULT);
1124 else if (block.exceptionType == FILTER)
1126 bb.Write(COR_ILEXCEPTION_CLAUSE_FILTER);
1128 else if (block.exceptionType == FINALLY)
1130 bb.Write(COR_ILEXCEPTION_CLAUSE_FINALLY);
1134 bb.Write(COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1136 bb.Write((short)block.tryOffset);
1137 bb.Write((byte)block.tryLength);
1138 bb.Write((short)block.handlerOffset);
1139 bb.Write((byte)block.handlerLength);
1140 if (block.exceptionType != FAULT && block.exceptionType != FILTER && block.exceptionType != FINALLY)
1142 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1146 bb.Write(block.filterOffset);
1154 private void WriteCode(ByteBuffer bb)
1156 int codeOffset = bb.Position;
1157 foreach (int fixup in this.tokenFixups)
1159 moduleBuilder.tokenFixupOffsets.Add(fixup + codeOffset);
1164 private void WriteScope(Scope scope, int localVarSigTok)
1166 moduleBuilder.symbolWriter.OpenScope(scope.startOffset);
1167 foreach (LocalBuilder local in scope.locals)
1169 if (local.name != null)
1171 int startOffset = local.startOffset;
1172 int endOffset = local.endOffset;
1173 if (startOffset == 0 && endOffset == 0)
1175 startOffset = scope.startOffset;
1176 endOffset = scope.endOffset;
1178 moduleBuilder.symbolWriter.DefineLocalVariable2(local.name, 0, localVarSigTok, SymAddressKind.ILOffset, local.LocalIndex, 0, 0, startOffset, endOffset);
1181 foreach (Scope child in scope.children)
1183 WriteScope(child, localVarSigTok);
1185 moduleBuilder.symbolWriter.CloseScope(scope.endOffset);