2 Copyright (C) 2008-2011 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 List<CustomModifiers> localCustomModifiers;
156 private readonly List<int> tokenFixups = new List<int>();
157 private readonly List<int> labels = new List<int>();
158 private readonly List<int> labelStackHeight = new List<int>();
159 private readonly List<LabelFixup> labelFixups = new List<LabelFixup>();
160 private readonly List<SequencePoint> sequencePoints = new List<SequencePoint>();
161 private readonly List<ExceptionBlock> exceptions = new List<ExceptionBlock>();
162 private readonly Stack<ExceptionBlock> exceptionStack = new Stack<ExceptionBlock>();
163 private ushort maxStack;
164 private bool fatHeader;
165 private int stackHeight;
167 private byte exceptionBlockAssistanceMode = EBAM_COMPAT;
168 private const byte EBAM_COMPAT = 0;
169 private const byte EBAM_DISABLE = 1;
170 private const byte EBAM_CLEVER = 2;
172 private struct LabelFixup
178 private sealed class ExceptionBlock : IComparer<ExceptionBlock>
180 internal readonly int ordinal;
181 internal Label labelEnd;
182 internal int tryOffset;
183 internal int tryLength;
184 internal int handlerOffset;
185 internal int handlerLength;
186 internal Type exceptionType; // FINALLY = finally block, FILTER = handler with filter, FAULT = fault block
187 internal int filterOffset;
189 internal ExceptionBlock(int ordinal)
191 this.ordinal = ordinal;
194 int IComparer<ExceptionBlock>.Compare(ExceptionBlock x, ExceptionBlock y)
196 // Mono's sort insists on doing unnecessary comparisons
201 else if (x.tryOffset == y.tryOffset && x.tryLength == y.tryLength)
203 return x.ordinal < y.ordinal ? -1 : 1;
205 else if (x.tryOffset >= y.tryOffset && x.handlerOffset + x.handlerLength <= y.handlerOffset + y.handlerLength)
209 else if (y.tryOffset >= x.tryOffset && y.handlerOffset + y.handlerLength <= x.handlerOffset + x.handlerLength)
215 return x.ordinal < y.ordinal ? -1 : 1;
220 private struct SequencePoint
222 internal ISymbolDocumentWriter document;
224 internal int startLine;
225 internal int startColumn;
226 internal int endLine;
227 internal int endColumn;
230 private sealed class Scope
232 internal readonly Scope parent;
233 internal readonly List<Scope> children = new List<Scope>();
234 internal readonly List<LocalBuilder> locals = new List<LocalBuilder>();
235 internal int startOffset;
236 internal int endOffset;
238 internal Scope(Scope parent)
240 this.parent = parent;
244 internal ILGenerator(ModuleBuilder moduleBuilder, int initialCapacity)
246 this.code = new ByteBuffer(initialCapacity);
247 this.moduleBuilder = moduleBuilder;
248 if (moduleBuilder.symbolWriter != null)
250 scope = new Scope(null);
255 public void __DisableExceptionBlockAssistance()
257 exceptionBlockAssistanceMode = EBAM_DISABLE;
261 public void __CleverExceptionBlockAssistance()
263 exceptionBlockAssistanceMode = EBAM_CLEVER;
267 public int __MaxStackSize
269 get { return maxStack; }
272 maxStack = (ushort)value;
278 // returns -1 if the current position is currently unreachable
279 public int __StackHeight
281 get { return stackHeight; }
287 get { return code.Position; }
290 public void BeginCatchBlock(Type exceptionType)
292 ExceptionBlock block = exceptionStack.Peek();
293 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
295 if (exceptionType == null)
297 Emit(OpCodes.Endfilter);
301 Emit(OpCodes.Leave, block.labelEnd);
306 if (exceptionType == null)
308 if (block.exceptionType != FILTER || block.handlerOffset != 0)
310 throw new ArgumentNullException("exceptionType");
312 block.handlerOffset = code.Position;
316 if (block.tryLength == 0)
318 block.tryLength = code.Position - block.tryOffset;
322 block.handlerLength = code.Position - block.handlerOffset;
323 exceptionStack.Pop();
324 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
325 newBlock.labelEnd = block.labelEnd;
326 newBlock.tryOffset = block.tryOffset;
327 newBlock.tryLength = block.tryLength;
329 exceptions.Add(block);
330 exceptionStack.Push(block);
332 block.exceptionType = exceptionType;
333 if (exceptionType == FILTER)
335 block.filterOffset = code.Position;
339 block.handlerOffset = code.Position;
344 public Label BeginExceptionBlock()
346 ExceptionBlock block = new ExceptionBlock(exceptions.Count);
347 block.labelEnd = DefineLabel();
348 block.tryOffset = code.Position;
349 exceptionStack.Push(block);
350 exceptions.Add(block);
352 return block.labelEnd;
355 public void BeginExceptFilterBlock()
357 BeginCatchBlock(FILTER);
360 public void BeginFaultBlock()
362 BeginFinallyFaultBlock(FAULT);
365 public void BeginFinallyBlock()
367 BeginFinallyFaultBlock(FINALLY);
370 private void BeginFinallyFaultBlock(Type type)
372 ExceptionBlock block = exceptionStack.Peek();
373 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
375 Emit(OpCodes.Leave, block.labelEnd);
377 if (block.handlerOffset == 0)
379 block.tryLength = code.Position - block.tryOffset;
383 block.handlerLength = code.Position - block.handlerOffset;
385 if (exceptionBlockAssistanceMode != EBAM_COMPAT)
387 labelEnd = block.labelEnd;
391 MarkLabel(block.labelEnd);
392 labelEnd = DefineLabel();
393 Emit(OpCodes.Leave, labelEnd);
395 exceptionStack.Pop();
396 ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
397 newBlock.labelEnd = labelEnd;
398 newBlock.tryOffset = block.tryOffset;
399 newBlock.tryLength = code.Position - block.tryOffset;
401 exceptions.Add(block);
402 exceptionStack.Push(block);
404 block.handlerOffset = code.Position;
405 block.exceptionType = type;
409 public void EndExceptionBlock()
411 ExceptionBlock block = exceptionStack.Pop();
412 if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
414 if (block.filterOffset != 0 || (block.exceptionType != FINALLY && block.exceptionType != FAULT))
416 Emit(OpCodes.Leave, block.labelEnd);
420 Emit(OpCodes.Endfinally);
423 MarkLabel(block.labelEnd);
424 block.handlerLength = code.Position - block.handlerOffset;
427 public void BeginScope()
429 Scope newScope = new Scope(scope);
430 scope.children.Add(newScope);
432 scope.startOffset = code.Position;
435 public void UsingNamespace(string usingNamespace)
437 if (moduleBuilder.symbolWriter != null)
439 moduleBuilder.symbolWriter.UsingNamespace(usingNamespace);
443 public LocalBuilder DeclareLocal(Type localType)
445 return DeclareLocal(localType, false);
448 public LocalBuilder DeclareLocal(Type localType, bool pinned)
450 LocalBuilder local = new LocalBuilder(localType, locals.Count, pinned);
454 scope.locals.Add(local);
459 public LocalBuilder __DeclareLocal(Type localType, bool pinned, CustomModifiers customModifiers)
461 if (!customModifiers.IsEmpty)
463 if (localCustomModifiers == null)
465 localCustomModifiers = new List<CustomModifiers>();
467 // we lazily fill up the list (to sync with the locals list) and we don't need to
468 // make sure that the list has the same length as the locals list, because
469 // Signature.WriteLocalVarSig() can tolerate that.
470 while (localCustomModifiers.Count < locals.Count)
472 localCustomModifiers.Add(new CustomModifiers());
474 localCustomModifiers.Add(customModifiers);
476 return DeclareLocal(localType, pinned);
479 public Label DefineLabel()
481 Label label = new Label(labels.Count);
483 labelStackHeight.Add(-1);
487 public void Emit(OpCode opc)
489 Debug.Assert(opc != OpCodes.Ret || (opc == OpCodes.Ret && stackHeight <= 1));
492 code.Write((byte)(opc.Value >> 8));
494 code.Write((byte)opc.Value);
495 switch (opc.FlowControl)
497 case FlowControl.Branch:
498 case FlowControl.Break:
499 case FlowControl.Return:
500 case FlowControl.Throw:
504 UpdateStack(opc.StackDiff);
509 private void UpdateStack(int stackdiff)
511 if (stackHeight == -1)
513 // we're about to emit code that is either unreachable or reachable only via a backward branch
516 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
517 stackHeight += stackdiff;
518 Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
519 maxStack = Math.Max(maxStack, (ushort)stackHeight);
522 public void Emit(OpCode opc, byte arg)
528 public void Emit(OpCode opc, double arg)
534 public void Emit(OpCode opc, FieldInfo field)
537 WriteToken(moduleBuilder.GetFieldToken(field));
540 public void Emit(OpCode opc, short arg)
546 public void Emit(OpCode opc, int arg)
552 public void Emit(OpCode opc, long arg)
558 public void Emit(OpCode opc, Label label)
560 // We need special stackHeight handling for unconditional branches,
561 // because the branch and next flows have differing stack heights.
562 // Note that this assumes that unconditional branches do not push/pop.
563 int flowStackHeight = this.stackHeight;
565 if (opc == OpCodes.Leave || opc == OpCodes.Leave_S)
569 else if (opc.FlowControl != FlowControl.Branch)
571 flowStackHeight = this.stackHeight;
573 // if the label has already been marked, we can emit the branch offset directly
574 if (labels[label.Index] != -1)
576 if (labelStackHeight[label.Index] != flowStackHeight && (labelStackHeight[label.Index] != 0 || flowStackHeight != -1))
578 // the "backward branch constraint" prohibits this, so we don't need to support it
579 throw new NotSupportedException("'Backward branch constraints' violated");
581 if (opc.OperandType == OperandType.ShortInlineBrTarget)
583 WriteByteBranchOffset(labels[label.Index] - (code.Position + 1));
587 code.Write(labels[label.Index] - (code.Position + 4));
592 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == flowStackHeight || (flowStackHeight == -1 && labelStackHeight[label.Index] == 0));
593 labelStackHeight[label.Index] = flowStackHeight;
594 LabelFixup fix = new LabelFixup();
595 fix.label = label.Index;
596 fix.offset = code.Position;
597 labelFixups.Add(fix);
598 if (opc.OperandType == OperandType.ShortInlineBrTarget)
609 private void WriteByteBranchOffset(int offset)
611 if (offset < -128 || offset > 127)
613 throw new NotSupportedException("Branch offset of " + offset + " does not fit in one-byte branch target at position " + code.Position);
615 code.Write((byte)offset);
618 public void Emit(OpCode opc, Label[] labels)
621 LabelFixup fix = new LabelFixup();
623 fix.offset = code.Position;
624 labelFixups.Add(fix);
625 code.Write(labels.Length);
626 foreach (Label label in labels)
628 code.Write(label.Index);
629 if (this.labels[label.Index] != -1)
631 if (labelStackHeight[label.Index] != stackHeight)
633 // the "backward branch constraint" prohibits this, so we don't need to support it
634 throw new NotSupportedException();
639 Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == stackHeight);
640 labelStackHeight[label.Index] = stackHeight;
645 public void Emit(OpCode opc, LocalBuilder local)
647 if ((opc == OpCodes.Ldloc || opc == OpCodes.Ldloca || opc == OpCodes.Stloc) && local.LocalIndex < 256)
649 if (opc == OpCodes.Ldloc)
651 switch (local.LocalIndex)
654 Emit(OpCodes.Ldloc_0);
657 Emit(OpCodes.Ldloc_1);
660 Emit(OpCodes.Ldloc_2);
663 Emit(OpCodes.Ldloc_3);
666 Emit(OpCodes.Ldloc_S);
667 code.Write((byte)local.LocalIndex);
671 else if (opc == OpCodes.Ldloca)
673 Emit(OpCodes.Ldloca_S);
674 code.Write((byte)local.LocalIndex);
676 else if (opc == OpCodes.Stloc)
678 switch (local.LocalIndex)
681 Emit(OpCodes.Stloc_0);
684 Emit(OpCodes.Stloc_1);
687 Emit(OpCodes.Stloc_2);
690 Emit(OpCodes.Stloc_3);
693 Emit(OpCodes.Stloc_S);
694 code.Write((byte)local.LocalIndex);
702 switch (opc.OperandType)
704 case OperandType.InlineVar:
705 code.Write((ushort)local.LocalIndex);
707 case OperandType.ShortInlineVar:
708 code.Write((byte)local.LocalIndex);
714 private void WriteToken(FieldToken token)
716 if (token.IsPseudoToken)
718 tokenFixups.Add(code.Position);
720 code.Write(token.Token);
723 private void WriteToken(MethodToken token)
725 if (token.IsPseudoToken)
727 tokenFixups.Add(code.Position);
729 code.Write(token.Token);
732 private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
734 if (opc == OpCodes.Jmp)
738 else if (opc.FlowControl == FlowControl.Call)
741 if ((hasthis && opc != OpCodes.Newobj) || opc == OpCodes.Calli)
747 stackdiff -= parameterCount;
748 if (returnType != moduleBuilder.universe.System_Void)
753 UpdateStack(stackdiff);
757 public void Emit(OpCode opc, MethodInfo method)
759 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount);
761 WriteToken(moduleBuilder.GetMethodTokenForIL(method));
764 public void Emit(OpCode opc, ConstructorInfo constructor)
766 Emit(opc, constructor.GetMethodInfo());
769 public void Emit(OpCode opc, sbyte arg)
775 public void Emit(OpCode opc, float arg)
781 public void Emit(OpCode opc, string str)
784 code.Write(0x70000000 | moduleBuilder.UserStrings.Add(str));
787 public void Emit(OpCode opc, Type type)
790 if (opc == OpCodes.Ldtoken)
792 code.Write(moduleBuilder.GetTypeToken(type).Token);
796 code.Write(moduleBuilder.GetTypeTokenForMemberRef(type));
800 public void Emit(OpCode opcode, SignatureHelper signature)
803 UpdateStack(opcode, signature.HasThis, signature.ReturnType, signature.ParameterCount);
804 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(signature.GetSignature(moduleBuilder))));
807 public void EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes)
809 __EmitCall(opc, method, optionalParameterTypes, null);
812 public void __EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
814 if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
821 UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount + optionalParameterTypes.Length);
822 ByteBuffer sig = new ByteBuffer(16);
823 method.MethodSignature.WriteMethodRefSig(moduleBuilder, sig, optionalParameterTypes, customModifiers);
824 MemberRefTable.Record record = new MemberRefTable.Record();
825 if (method.Module == moduleBuilder)
827 record.Class = method.MetadataToken;
831 record.Class = moduleBuilder.GetTypeTokenForMemberRef(method.DeclaringType ?? method.Module.GetModuleType());
833 record.Name = moduleBuilder.Strings.Add(method.Name);
834 record.Signature = moduleBuilder.Blobs.Add(sig);
835 code.Write(0x0A000000 | moduleBuilder.MemberRef.FindOrAddRecord(record));
839 public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes)
841 EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes);
844 public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
846 __EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes, customModifiers);
849 public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
851 __EmitCalli(opc, moduleBuilder.universe.MakeStandAloneMethodSig(callingConvention, returnType, new CustomModifiers(), parameterTypes, null));
854 public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
856 __EmitCalli(opc, moduleBuilder.universe.MakeStandAloneMethodSig(callingConvention, returnType, new CustomModifiers(), parameterTypes, optionalParameterTypes, null));
859 public void __EmitCalli(OpCode opc, __StandAloneMethodSig sig)
864 UpdateStack(opc, false, sig.ReturnType, sig.ParameterCount);
868 CallingConventions callingConvention = sig.CallingConvention;
869 UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, sig.ReturnType, sig.ParameterCount);
871 ByteBuffer bb = new ByteBuffer(16);
872 Signature.WriteStandAloneMethodSig(moduleBuilder, bb, sig);
873 code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(bb)));
876 public void EmitWriteLine(string text)
878 Universe u = moduleBuilder.universe;
879 Emit(OpCodes.Ldstr, text);
880 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("WriteLine", new Type[] { u.System_String }));
883 public void EmitWriteLine(FieldInfo field)
885 Universe u = moduleBuilder.universe;
886 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
889 Emit(OpCodes.Ldsfld, field);
893 Emit(OpCodes.Ldarg_0);
894 Emit(OpCodes.Ldfld, field);
896 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { field.FieldType }));
899 public void EmitWriteLine(LocalBuilder local)
901 Universe u = moduleBuilder.universe;
902 Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
903 Emit(OpCodes.Ldloc, local);
904 Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { local.LocalType }));
907 public void EndScope()
909 scope.endOffset = code.Position;
910 scope = scope.parent;
913 public void MarkLabel(Label loc)
915 Debug.Assert(stackHeight == -1 || labelStackHeight[loc.Index] == -1 || stackHeight == labelStackHeight[loc.Index]);
916 labels[loc.Index] = code.Position;
917 if (labelStackHeight[loc.Index] == -1)
919 if (stackHeight == -1)
921 // We're at a location that can only be reached by a backward branch,
922 // so according to the "backward branch constraint" that must mean the stack is empty,
923 // but note that this may be an unused label followed by another label that is used and
924 // that does have a non-zero stack height, so we don't yet set stackHeight here.
925 labelStackHeight[loc.Index] = 0;
929 labelStackHeight[loc.Index] = stackHeight;
934 Debug.Assert(stackHeight == -1 || stackHeight == labelStackHeight[loc.Index]);
935 stackHeight = labelStackHeight[loc.Index];
939 public void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
941 SequencePoint sp = new SequencePoint();
942 sp.document = document;
943 sp.offset = code.Position;
944 sp.startLine = startLine;
945 sp.startColumn = startColumn;
946 sp.endLine = endLine;
947 sp.endColumn = endColumn;
948 sequencePoints.Add(sp);
951 public void ThrowException(Type excType)
953 Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
957 internal int WriteBody(bool initLocals)
959 if (moduleBuilder.symbolWriter != null)
961 Debug.Assert(scope != null && scope.parent == null);
962 scope.endOffset = code.Position;
967 ByteBuffer bb = moduleBuilder.methodBodies;
969 int localVarSigTok = 0;
972 if (locals.Count == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64 && !fatHeader)
974 rva = WriteTinyHeaderAndCode(bb);
978 rva = WriteFatHeaderAndCode(bb, ref localVarSigTok, initLocals);
981 if (moduleBuilder.symbolWriter != null)
983 if (sequencePoints.Count != 0)
985 ISymbolDocumentWriter document = sequencePoints[0].document;
986 int[] offsets = new int[sequencePoints.Count];
987 int[] lines = new int[sequencePoints.Count];
988 int[] columns = new int[sequencePoints.Count];
989 int[] endLines = new int[sequencePoints.Count];
990 int[] endColumns = new int[sequencePoints.Count];
991 for (int i = 0; i < sequencePoints.Count; i++)
993 if (sequencePoints[i].document != document)
995 throw new NotImplementedException();
997 offsets[i] = sequencePoints[i].offset;
998 lines[i] = sequencePoints[i].startLine;
999 columns[i] = sequencePoints[i].startColumn;
1000 endLines[i] = sequencePoints[i].endLine;
1001 endColumns[i] = sequencePoints[i].endColumn;
1003 moduleBuilder.symbolWriter.DefineSequencePoints(document, offsets, lines, columns, endLines, endColumns);
1006 WriteScope(scope, localVarSigTok);
1011 private void ResolveBranches()
1013 foreach (LabelFixup fixup in labelFixups)
1016 if (fixup.label == -1)
1018 code.Position = fixup.offset;
1019 int count = code.GetInt32AtCurrentPosition();
1020 int offset = fixup.offset + 4 + 4 * count;
1022 for (int i = 0; i < count; i++)
1024 int index = code.GetInt32AtCurrentPosition();
1025 code.Write(labels[index] - offset);
1030 code.Position = fixup.offset;
1031 byte size = code.GetByteAtCurrentPosition();
1032 int branchOffset = labels[fixup.label] - (code.Position + size);
1035 WriteByteBranchOffset(branchOffset);
1039 code.Write(branchOffset);
1045 private int WriteTinyHeaderAndCode(ByteBuffer bb)
1047 int rva = bb.Position;
1048 const byte CorILMethod_TinyFormat = 0x2;
1049 bb.Write((byte)(CorILMethod_TinyFormat | (code.Length << 2)));
1054 private int WriteFatHeaderAndCode(ByteBuffer bb, ref int localVarSigTok, bool initLocals)
1056 // fat headers require 4-byte alignment
1058 int rva = bb.Position;
1060 if (locals.Count != 0)
1062 ByteBuffer localVarSig = new ByteBuffer(locals.Count + 2);
1063 Signature.WriteLocalVarSig(moduleBuilder, localVarSig, locals, localCustomModifiers);
1064 localVarSigTok = 0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(localVarSig));
1067 const byte CorILMethod_FatFormat = 0x03;
1068 const byte CorILMethod_MoreSects = 0x08;
1069 const byte CorILMethod_InitLocals = 0x10;
1071 short flagsAndSize = (short)(CorILMethod_FatFormat | (3 << 12));
1074 flagsAndSize |= CorILMethod_InitLocals;
1077 if (exceptions.Count > 0)
1079 flagsAndSize |= CorILMethod_MoreSects;
1082 bb.Write(flagsAndSize);
1084 bb.Write(code.Length);
1085 bb.Write(localVarSigTok);
1089 if (exceptions.Count > 0)
1094 foreach (ExceptionBlock block in exceptions)
1096 if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
1102 exceptions.Sort(exceptions[0]);
1103 if (exceptions.Count * 12 + 4 > 255)
1107 const byte CorILMethod_Sect_EHTable = 0x1;
1108 const byte CorILMethod_Sect_FatFormat = 0x40;
1109 const short COR_ILEXCEPTION_CLAUSE_EXCEPTION = 0x0000;
1110 const short COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001;
1111 const short COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002;
1112 const short COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004;
1116 bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
1117 int dataSize = exceptions.Count * 24 + 4;
1118 bb.Write((byte)dataSize);
1119 bb.Write((short)(dataSize >> 8));
1120 foreach (ExceptionBlock block in exceptions)
1122 if (block.exceptionType == FAULT)
1124 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FAULT);
1126 else if (block.exceptionType == FILTER)
1128 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FILTER);
1130 else if (block.exceptionType == FINALLY)
1132 bb.Write((int)COR_ILEXCEPTION_CLAUSE_FINALLY);
1136 bb.Write((int)COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1138 bb.Write(block.tryOffset);
1139 bb.Write(block.tryLength);
1140 bb.Write(block.handlerOffset);
1141 bb.Write(block.handlerLength);
1142 if (block.exceptionType != FAULT && block.exceptionType != FILTER && block.exceptionType != FINALLY)
1144 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1148 bb.Write(block.filterOffset);
1154 bb.Write(CorILMethod_Sect_EHTable);
1155 bb.Write((byte)(exceptions.Count * 12 + 4));
1157 foreach (ExceptionBlock block in exceptions)
1159 if (block.exceptionType == FAULT)
1161 bb.Write(COR_ILEXCEPTION_CLAUSE_FAULT);
1163 else if (block.exceptionType == FILTER)
1165 bb.Write(COR_ILEXCEPTION_CLAUSE_FILTER);
1167 else if (block.exceptionType == FINALLY)
1169 bb.Write(COR_ILEXCEPTION_CLAUSE_FINALLY);
1173 bb.Write(COR_ILEXCEPTION_CLAUSE_EXCEPTION);
1175 bb.Write((short)block.tryOffset);
1176 bb.Write((byte)block.tryLength);
1177 bb.Write((short)block.handlerOffset);
1178 bb.Write((byte)block.handlerLength);
1179 if (block.exceptionType != FAULT && block.exceptionType != FILTER && block.exceptionType != FINALLY)
1181 bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
1185 bb.Write(block.filterOffset);
1193 private void WriteCode(ByteBuffer bb)
1195 int codeOffset = bb.Position;
1196 foreach (int fixup in this.tokenFixups)
1198 moduleBuilder.tokenFixupOffsets.Add(fixup + codeOffset);
1203 private void WriteScope(Scope scope, int localVarSigTok)
1205 moduleBuilder.symbolWriter.OpenScope(scope.startOffset);
1206 foreach (LocalBuilder local in scope.locals)
1208 if (local.name != null)
1210 int startOffset = local.startOffset;
1211 int endOffset = local.endOffset;
1212 if (startOffset == 0 && endOffset == 0)
1214 startOffset = scope.startOffset;
1215 endOffset = scope.endOffset;
1217 moduleBuilder.symbolWriter.DefineLocalVariable2(local.name, 0, localVarSigTok, SymAddressKind.ILOffset, local.LocalIndex, 0, 0, startOffset, endOffset);
1220 foreach (Scope child in scope.children)
1222 WriteScope(child, localVarSigTok);
1224 moduleBuilder.symbolWriter.CloseScope(scope.endOffset);