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 : LocalVariableInfo
77
internal int startOffset;
78
internal int endOffset;
80
internal LocalBuilder(Type localType, int index, bool pinned)
81
: base(index, localType, pinned)
85
internal LocalBuilder(Type localType, int index, bool pinned, CustomModifiers customModifiers)
86
: base(index, localType, pinned, customModifiers)
90
public void SetLocalSymInfo(string name)
95
public void SetLocalSymInfo(string name, int startOffset, int endOffset)
98
this.startOffset = startOffset;
99
this.endOffset = endOffset;
103
public sealed class ILGenerator
105
private readonly ModuleBuilder moduleBuilder;
106
private readonly ByteBuffer code;
107
private readonly SignatureHelper locals;
108
private int localsCount;
109
private readonly List<int> tokenFixups = new List<int>();
110
private readonly List<int> labels = new List<int>();
111
private readonly List<int> labelStackHeight = new List<int>();
112
private readonly List<LabelFixup> labelFixups = new List<LabelFixup>();
113
private readonly List<SequencePoint> sequencePoints = new List<SequencePoint>();
114
private readonly List<ExceptionBlock> exceptions = new List<ExceptionBlock>();
115
private readonly Stack<ExceptionBlock> exceptionStack = new Stack<ExceptionBlock>();
116
private ushort maxStack;
117
private bool fatHeader;
118
private int stackHeight;
120
private byte exceptionBlockAssistanceMode = EBAM_COMPAT;
121
private const byte EBAM_COMPAT = 0;
122
private const byte EBAM_DISABLE = 1;
123
private const byte EBAM_CLEVER = 2;
125
private struct LabelFixup
131
internal sealed class ExceptionBlock : IComparer<ExceptionBlock>
133
internal readonly int ordinal;
134
internal Label labelEnd;
135
internal int tryOffset;
136
internal int tryLength;
137
internal int handlerOffset;
138
internal int handlerLength;
139
internal int filterOffsetOrExceptionTypeToken;
140
internal ExceptionHandlingClauseOptions kind;
142
internal ExceptionBlock(int ordinal)
144
this.ordinal = ordinal;
147
internal ExceptionBlock(ExceptionHandler h)
150
this.tryOffset = h.TryOffset;
151
this.tryLength = h.TryLength;
152
this.handlerOffset = h.HandlerOffset;
153
this.handlerLength = h.HandlerLength;
155
this.filterOffsetOrExceptionTypeToken = kind == ExceptionHandlingClauseOptions.Filter ? h.FilterOffset : h.ExceptionTypeToken;
158
int IComparer<ExceptionBlock>.Compare(ExceptionBlock x, ExceptionBlock y)
160
// Mono's sort insists on doing unnecessary comparisons
165
else if (x.tryOffset == y.tryOffset && x.tryLength == y.tryLength)
167
return x.ordinal < y.ordinal ? -1 : 1;
169
else if (x.tryOffset >= y.tryOffset && x.handlerOffset + x.handlerLength <= y.handlerOffset + y.handlerLength)
173
else if (y.tryOffset >= x.tryOffset && y.handlerOffset + y.handlerLength <= x.handlerOffset + x.handlerLength)
179
return x.ordinal < y.ordinal ? -1 : 1;
184
private struct SequencePoint
186
internal ISymbolDocumentWriter document;
188
internal int startLine;
189
internal int startColumn;
190
internal int endLine;
191
internal int endColumn;
194
private sealed class Scope
196
internal readonly Scope parent;
197
internal readonly List<Scope> children = new List<Scope>();
198
internal readonly List<LocalBuilder> locals = new List<LocalBuilder>();
199
internal int startOffset;
200
internal int endOffset;
202
internal Scope(Scope parent)
204
this.parent = parent;
208
internal ILGenerator(ModuleBuilder moduleBuilder, int initialCapacity)
210
this.code = new ByteBuffer(initialCapacity);
211
this.moduleBuilder = moduleBuilder;
212
this.locals = SignatureHelper.GetLocalVarSigHelper(moduleBuilder);
213
if (moduleBuilder.symbolWriter != null)
215
scope = new Scope(null);
220
public void __DisableExceptionBlockAssistance()
222
exceptionBlockAssistanceMode = EBAM_DISABLE;
226
public void __CleverExceptionBlockAssistance()
228
exceptionBlockAssistanceMode = EBAM_CLEVER;
232
public int __MaxStackSize
234
get { return maxStack; }
237
maxStack = (ushort)value;
243
// returns -1 if the current position is currently unreachable
244
public int __StackHeight
246
get { return stackHeight; }
252
get { return code.Position; }
255
public void BeginCatchBlock(Type exceptionType)
257
if (exceptionType == null)
259
// this must be a catch block after a filter
260
ExceptionBlock block = exceptionStack.Peek();
261
if (block.kind != ExceptionHandlingClauseOptions.Filter || block.handlerOffset != 0)
263
throw new ArgumentNullException("exceptionType");
265
if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
267
Emit(OpCodes.Endfilter);
271
block.handlerOffset = code.Position;
275
ExceptionBlock block = BeginCatchOrFilterBlock();
276
block.kind = ExceptionHandlingClauseOptions.Clause;
277
block.filterOffsetOrExceptionTypeToken = moduleBuilder.GetTypeTokenForMemberRef(exceptionType);
278
block.handlerOffset = code.Position;
282
private ExceptionBlock BeginCatchOrFilterBlock()
284
ExceptionBlock block = exceptionStack.Peek();
285
if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
287
Emit(OpCodes.Leave, block.labelEnd);
291
if (block.tryLength == 0)
293
block.tryLength = code.Position - block.tryOffset;
297
block.handlerLength = code.Position - block.handlerOffset;
298
exceptionStack.Pop();
299
ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
300
newBlock.labelEnd = block.labelEnd;
301
newBlock.tryOffset = block.tryOffset;
302
newBlock.tryLength = block.tryLength;
304
exceptions.Add(block);
305
exceptionStack.Push(block);
310
public Label BeginExceptionBlock()
312
ExceptionBlock block = new ExceptionBlock(exceptions.Count);
313
block.labelEnd = DefineLabel();
314
block.tryOffset = code.Position;
315
exceptionStack.Push(block);
316
exceptions.Add(block);
318
return block.labelEnd;
321
public void BeginExceptFilterBlock()
323
ExceptionBlock block = BeginCatchOrFilterBlock();
324
block.kind = ExceptionHandlingClauseOptions.Filter;
325
block.filterOffsetOrExceptionTypeToken = code.Position;
328
public void BeginFaultBlock()
330
BeginFinallyFaultBlock(ExceptionHandlingClauseOptions.Fault);
333
public void BeginFinallyBlock()
335
BeginFinallyFaultBlock(ExceptionHandlingClauseOptions.Finally);
338
private void BeginFinallyFaultBlock(ExceptionHandlingClauseOptions kind)
340
ExceptionBlock block = exceptionStack.Peek();
341
if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
343
Emit(OpCodes.Leave, block.labelEnd);
345
if (block.handlerOffset == 0)
347
block.tryLength = code.Position - block.tryOffset;
351
block.handlerLength = code.Position - block.handlerOffset;
353
if (exceptionBlockAssistanceMode != EBAM_COMPAT)
355
labelEnd = block.labelEnd;
359
MarkLabel(block.labelEnd);
360
labelEnd = DefineLabel();
361
Emit(OpCodes.Leave, labelEnd);
363
exceptionStack.Pop();
364
ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
365
newBlock.labelEnd = labelEnd;
366
newBlock.tryOffset = block.tryOffset;
367
newBlock.tryLength = code.Position - block.tryOffset;
369
exceptions.Add(block);
370
exceptionStack.Push(block);
372
block.handlerOffset = code.Position;
377
public void EndExceptionBlock()
379
ExceptionBlock block = exceptionStack.Pop();
380
if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
382
if (block.kind != ExceptionHandlingClauseOptions.Finally && block.kind != ExceptionHandlingClauseOptions.Fault)
384
Emit(OpCodes.Leave, block.labelEnd);
388
Emit(OpCodes.Endfinally);
391
MarkLabel(block.labelEnd);
392
block.handlerLength = code.Position - block.handlerOffset;
395
public void BeginScope()
397
Scope newScope = new Scope(scope);
398
scope.children.Add(newScope);
400
scope.startOffset = code.Position;
403
public void UsingNamespace(string usingNamespace)
405
if (moduleBuilder.symbolWriter != null)
407
moduleBuilder.symbolWriter.UsingNamespace(usingNamespace);
411
public LocalBuilder DeclareLocal(Type localType)
413
return DeclareLocal(localType, false);
416
public LocalBuilder DeclareLocal(Type localType, bool pinned)
418
LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned);
419
locals.AddArgument(localType, pinned);
422
scope.locals.Add(local);
427
public LocalBuilder __DeclareLocal(Type localType, bool pinned, CustomModifiers customModifiers)
429
LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned, customModifiers);
430
locals.__AddArgument(localType, pinned, customModifiers);
433
scope.locals.Add(local);
438
public Label DefineLabel()
440
Label label = new Label(labels.Count);
442
labelStackHeight.Add(-1);
446
public void Emit(OpCode opc)
448
Debug.Assert(opc != OpCodes.Ret || (opc == OpCodes.Ret && stackHeight <= 1));
451
code.Write((byte)(opc.Value >> 8));
453
code.Write((byte)opc.Value);
454
switch (opc.FlowControl)
456
case FlowControl.Branch:
457
case FlowControl.Break:
458
case FlowControl.Return:
459
case FlowControl.Throw:
463
UpdateStack(opc.StackDiff);
468
private void UpdateStack(int stackdiff)
470
if (stackHeight == -1)
472
// we're about to emit code that is either unreachable or reachable only via a backward branch
475
Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
476
stackHeight += stackdiff;
477
Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
478
maxStack = Math.Max(maxStack, (ushort)stackHeight);
481
public void Emit(OpCode opc, byte arg)
487
public void Emit(OpCode opc, double arg)
493
public void Emit(OpCode opc, FieldInfo field)
496
WriteToken(moduleBuilder.GetFieldToken(field).Token);
499
public void Emit(OpCode opc, short arg)
505
public void Emit(OpCode opc, int arg)
511
public void Emit(OpCode opc, long arg)
517
public void Emit(OpCode opc, Label label)
519
// We need special stackHeight handling for unconditional branches,
520
// because the branch and next flows have differing stack heights.
521
// Note that this assumes that unconditional branches do not push/pop.
522
int flowStackHeight = this.stackHeight;
524
if (opc == OpCodes.Leave || opc == OpCodes.Leave_S)
528
else if (opc.FlowControl != FlowControl.Branch)
530
flowStackHeight = this.stackHeight;
532
// if the label has already been marked, we can emit the branch offset directly
533
if (labels[label.Index] != -1)
535
if (labelStackHeight[label.Index] != flowStackHeight && (labelStackHeight[label.Index] != 0 || flowStackHeight != -1))
537
// the "backward branch constraint" prohibits this, so we don't need to support it
538
throw new NotSupportedException("'Backward branch constraints' violated");
540
if (opc.OperandType == OperandType.ShortInlineBrTarget)
542
WriteByteBranchOffset(labels[label.Index] - (code.Position + 1));
546
code.Write(labels[label.Index] - (code.Position + 4));
551
Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == flowStackHeight || (flowStackHeight == -1 && labelStackHeight[label.Index] == 0));
552
labelStackHeight[label.Index] = flowStackHeight;
553
LabelFixup fix = new LabelFixup();
554
fix.label = label.Index;
555
fix.offset = code.Position;
556
labelFixups.Add(fix);
557
if (opc.OperandType == OperandType.ShortInlineBrTarget)
568
private void WriteByteBranchOffset(int offset)
570
if (offset < -128 || offset > 127)
572
throw new NotSupportedException("Branch offset of " + offset + " does not fit in one-byte branch target at position " + code.Position);
574
code.Write((byte)offset);
577
public void Emit(OpCode opc, Label[] labels)
580
LabelFixup fix = new LabelFixup();
582
fix.offset = code.Position;
583
labelFixups.Add(fix);
584
code.Write(labels.Length);
585
foreach (Label label in labels)
587
code.Write(label.Index);
588
if (this.labels[label.Index] != -1)
590
if (labelStackHeight[label.Index] != stackHeight)
592
// the "backward branch constraint" prohibits this, so we don't need to support it
593
throw new NotSupportedException();
598
Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == stackHeight);
599
labelStackHeight[label.Index] = stackHeight;
604
public void Emit(OpCode opc, LocalBuilder local)
606
if ((opc == OpCodes.Ldloc || opc == OpCodes.Ldloca || opc == OpCodes.Stloc) && local.LocalIndex < 256)
608
if (opc == OpCodes.Ldloc)
610
switch (local.LocalIndex)
613
Emit(OpCodes.Ldloc_0);
616
Emit(OpCodes.Ldloc_1);
619
Emit(OpCodes.Ldloc_2);
622
Emit(OpCodes.Ldloc_3);
625
Emit(OpCodes.Ldloc_S);
626
code.Write((byte)local.LocalIndex);
630
else if (opc == OpCodes.Ldloca)
632
Emit(OpCodes.Ldloca_S);
633
code.Write((byte)local.LocalIndex);
635
else if (opc == OpCodes.Stloc)
637
switch (local.LocalIndex)
640
Emit(OpCodes.Stloc_0);
643
Emit(OpCodes.Stloc_1);
646
Emit(OpCodes.Stloc_2);
649
Emit(OpCodes.Stloc_3);
652
Emit(OpCodes.Stloc_S);
653
code.Write((byte)local.LocalIndex);
661
switch (opc.OperandType)
663
case OperandType.InlineVar:
664
code.Write((ushort)local.LocalIndex);
666
case OperandType.ShortInlineVar:
667
code.Write((byte)local.LocalIndex);
673
private void WriteToken(int token)
675
if (ModuleBuilder.IsPseudoToken(token))
677
tokenFixups.Add(code.Position);
682
private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
684
if (opc == OpCodes.Jmp)
688
else if (opc.FlowControl == FlowControl.Call)
691
if ((hasthis && opc != OpCodes.Newobj) || opc == OpCodes.Calli)
697
stackdiff -= parameterCount;
698
if (returnType != moduleBuilder.universe.System_Void)
703
UpdateStack(stackdiff);
707
public void Emit(OpCode opc, MethodInfo method)
709
UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount);
711
WriteToken(moduleBuilder.GetMethodTokenForIL(method).Token);
714
public void Emit(OpCode opc, ConstructorInfo constructor)
716
Emit(opc, constructor.GetMethodInfo());
719
public void Emit(OpCode opc, sbyte arg)
725
public void Emit(OpCode opc, float arg)
731
public void Emit(OpCode opc, string str)
734
code.Write(moduleBuilder.GetStringConstant(str).Token);
737
public void Emit(OpCode opc, Type type)
740
if (opc == OpCodes.Ldtoken)
742
code.Write(moduleBuilder.GetTypeToken(type).Token);
746
code.Write(moduleBuilder.GetTypeTokenForMemberRef(type));
750
public void Emit(OpCode opcode, SignatureHelper signature)
753
UpdateStack(opcode, signature.HasThis, signature.ReturnType, signature.ParameterCount);
754
code.Write(moduleBuilder.GetSignatureToken(signature).Token);
757
public void EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes)
759
__EmitCall(opc, method, optionalParameterTypes, null);
762
public void __EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
764
if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
771
UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount + optionalParameterTypes.Length);
772
code.Write(moduleBuilder.__GetMethodToken(method, optionalParameterTypes, customModifiers).Token);
776
public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes)
778
EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes);
781
public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
783
__EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes, customModifiers);
786
public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
788
SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
789
sig.AddArguments(parameterTypes, null, null);
793
public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
795
SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
796
sig.AddArguments(parameterTypes, null, null);
798
sig.AddArguments(optionalParameterTypes, null, null);
802
public void __EmitCalli(OpCode opc, __StandAloneMethodSig sig)
807
UpdateStack(opc, false, sig.ReturnType, sig.ParameterCount);
811
CallingConventions callingConvention = sig.CallingConvention;
812
UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, sig.ReturnType, sig.ParameterCount);
814
ByteBuffer bb = new ByteBuffer(16);
815
Signature.WriteStandAloneMethodSig(moduleBuilder, bb, sig);
816
code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(bb)));
819
public void EmitWriteLine(string text)
821
Universe u = moduleBuilder.universe;
822
Emit(OpCodes.Ldstr, text);
823
Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("WriteLine", new Type[] { u.System_String }));
826
public void EmitWriteLine(FieldInfo field)
828
Universe u = moduleBuilder.universe;
829
Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
832
Emit(OpCodes.Ldsfld, field);
836
Emit(OpCodes.Ldarg_0);
837
Emit(OpCodes.Ldfld, field);
839
Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { field.FieldType }));
842
public void EmitWriteLine(LocalBuilder local)
844
Universe u = moduleBuilder.universe;
845
Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
846
Emit(OpCodes.Ldloc, local);
847
Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { local.LocalType }));
850
public void EndScope()
852
scope.endOffset = code.Position;
853
scope = scope.parent;
856
public void MarkLabel(Label loc)
858
Debug.Assert(stackHeight == -1 || labelStackHeight[loc.Index] == -1 || stackHeight == labelStackHeight[loc.Index]);
859
labels[loc.Index] = code.Position;
860
if (labelStackHeight[loc.Index] == -1)
862
if (stackHeight == -1)
864
// We're at a location that can only be reached by a backward branch,
865
// so according to the "backward branch constraint" that must mean the stack is empty,
866
// but note that this may be an unused label followed by another label that is used and
867
// that does have a non-zero stack height, so we don't yet set stackHeight here.
868
labelStackHeight[loc.Index] = 0;
872
labelStackHeight[loc.Index] = stackHeight;
877
Debug.Assert(stackHeight == -1 || stackHeight == labelStackHeight[loc.Index]);
878
stackHeight = labelStackHeight[loc.Index];
882
public void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
884
SequencePoint sp = new SequencePoint();
885
sp.document = document;
886
sp.offset = code.Position;
887
sp.startLine = startLine;
888
sp.startColumn = startColumn;
889
sp.endLine = endLine;
890
sp.endColumn = endColumn;
891
sequencePoints.Add(sp);
894
public void ThrowException(Type excType)
896
Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
900
internal int WriteBody(bool initLocals)
902
if (moduleBuilder.symbolWriter != null)
904
Debug.Assert(scope != null && scope.parent == null);
905
scope.endOffset = code.Position;
910
ByteBuffer bb = moduleBuilder.methodBodies;
912
int localVarSigTok = 0;
915
if (localsCount == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64 && !fatHeader)
917
rva = WriteTinyHeaderAndCode(bb);
921
if (localsCount != 0)
923
localVarSigTok = moduleBuilder.GetSignatureToken(locals).Token;
925
rva = WriteFatHeaderAndCode(bb, localVarSigTok, initLocals);
928
if (moduleBuilder.symbolWriter != null)
930
if (sequencePoints.Count != 0)
932
ISymbolDocumentWriter document = sequencePoints[0].document;
933
int[] offsets = new int[sequencePoints.Count];
934
int[] lines = new int[sequencePoints.Count];
935
int[] columns = new int[sequencePoints.Count];
936
int[] endLines = new int[sequencePoints.Count];
937
int[] endColumns = new int[sequencePoints.Count];
938
for (int i = 0; i < sequencePoints.Count; i++)
940
if (sequencePoints[i].document != document)
942
throw new NotImplementedException();
944
offsets[i] = sequencePoints[i].offset;
945
lines[i] = sequencePoints[i].startLine;
946
columns[i] = sequencePoints[i].startColumn;
947
endLines[i] = sequencePoints[i].endLine;
948
endColumns[i] = sequencePoints[i].endColumn;
950
moduleBuilder.symbolWriter.DefineSequencePoints(document, offsets, lines, columns, endLines, endColumns);
953
WriteScope(scope, localVarSigTok);
958
private void ResolveBranches()
960
foreach (LabelFixup fixup in labelFixups)
963
if (fixup.label == -1)
965
code.Position = fixup.offset;
966
int count = code.GetInt32AtCurrentPosition();
967
int offset = fixup.offset + 4 + 4 * count;
969
for (int i = 0; i < count; i++)
971
int index = code.GetInt32AtCurrentPosition();
972
code.Write(labels[index] - offset);
977
code.Position = fixup.offset;
978
byte size = code.GetByteAtCurrentPosition();
979
int branchOffset = labels[fixup.label] - (code.Position + size);
982
WriteByteBranchOffset(branchOffset);
986
code.Write(branchOffset);
992
internal static void WriteTinyHeader(ByteBuffer bb, int length)
994
const byte CorILMethod_TinyFormat = 0x2;
995
bb.Write((byte)(CorILMethod_TinyFormat | (length << 2)));
998
private int WriteTinyHeaderAndCode(ByteBuffer bb)
1000
int rva = bb.Position;
1001
WriteTinyHeader(bb, code.Length);
1002
AddTokenFixups(bb.Position, moduleBuilder.tokenFixupOffsets, tokenFixups);
1007
internal static void WriteFatHeader(ByteBuffer bb, bool initLocals, bool exceptions, ushort maxStack, int codeLength, int localVarSigTok)
1009
const byte CorILMethod_FatFormat = 0x03;
1010
const byte CorILMethod_MoreSects = 0x08;
1011
const byte CorILMethod_InitLocals = 0x10;
1013
short flagsAndSize = (short)(CorILMethod_FatFormat | (3 << 12));
1016
flagsAndSize |= CorILMethod_InitLocals;
1021
flagsAndSize |= CorILMethod_MoreSects;
1024
bb.Write(flagsAndSize);
1026
bb.Write(codeLength);
1027
bb.Write(localVarSigTok);
1030
private int WriteFatHeaderAndCode(ByteBuffer bb, int localVarSigTok, bool initLocals)
1032
// fat headers require 4-byte alignment
1034
int rva = bb.Position;
1035
WriteFatHeader(bb, initLocals, exceptions.Count > 0, maxStack, code.Length, localVarSigTok);
1036
AddTokenFixups(bb.Position, moduleBuilder.tokenFixupOffsets, tokenFixups);
1038
if (exceptions.Count > 0)
1040
exceptions.Sort(exceptions[0]);
1041
WriteExceptionHandlers(bb, exceptions);
1046
internal static void WriteExceptionHandlers(ByteBuffer bb, List<ExceptionBlock> exceptions)
1051
if (exceptions.Count * 12 + 4 > 255)
1057
foreach (ExceptionBlock block in exceptions)
1059
if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
1067
const byte CorILMethod_Sect_EHTable = 0x1;
1068
const byte CorILMethod_Sect_FatFormat = 0x40;
1072
bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
1073
int dataSize = exceptions.Count * 24 + 4;
1074
bb.Write((byte)dataSize);
1075
bb.Write((short)(dataSize >> 8));
1076
foreach (ExceptionBlock block in exceptions)
1078
bb.Write((int)block.kind);
1079
bb.Write(block.tryOffset);
1080
bb.Write(block.tryLength);
1081
bb.Write(block.handlerOffset);
1082
bb.Write(block.handlerLength);
1083
bb.Write(block.filterOffsetOrExceptionTypeToken);
1088
bb.Write(CorILMethod_Sect_EHTable);
1089
bb.Write((byte)(exceptions.Count * 12 + 4));
1091
foreach (ExceptionBlock block in exceptions)
1093
bb.Write((short)block.kind);
1094
bb.Write((short)block.tryOffset);
1095
bb.Write((byte)block.tryLength);
1096
bb.Write((short)block.handlerOffset);
1097
bb.Write((byte)block.handlerLength);
1098
bb.Write(block.filterOffsetOrExceptionTypeToken);
1103
internal static void AddTokenFixups(int codeOffset, List<int> tokenFixupOffsets, IEnumerable<int> tokenFixups)
1105
foreach (int fixup in tokenFixups)
1107
tokenFixupOffsets.Add(fixup + codeOffset);
1111
private void WriteScope(Scope scope, int localVarSigTok)
1113
moduleBuilder.symbolWriter.OpenScope(scope.startOffset);
1114
foreach (LocalBuilder local in scope.locals)
1116
if (local.name != null)
1118
int startOffset = local.startOffset;
1119
int endOffset = local.endOffset;
1120
if (startOffset == 0 && endOffset == 0)
1122
startOffset = scope.startOffset;
1123
endOffset = scope.endOffset;
1125
moduleBuilder.symbolWriter.DefineLocalVariable2(local.name, 0, localVarSigTok, SymAddressKind.ILOffset, local.LocalIndex, 0, 0, startOffset, endOffset);
1128
foreach (Scope child in scope.children)
1130
WriteScope(child, localVarSigTok);
1132
moduleBuilder.symbolWriter.CloseScope(scope.endOffset);