~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/reflect/Emit/ILGenerator.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2008-2012 Jeroen Frijters
 
3
 
 
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.
 
7
 
 
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:
 
11
 
 
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.
 
19
 
 
20
  Jeroen Frijters
 
21
  jeroen@frijters.net
 
22
  
 
23
*/
 
24
using System;
 
25
using System.Runtime.InteropServices;
 
26
using System.Collections.Generic;
 
27
using System.Diagnostics.SymbolStore;
 
28
using System.Diagnostics;
 
29
using IKVM.Reflection.Writer;
 
30
 
 
31
namespace IKVM.Reflection.Emit
 
32
{
 
33
        public struct Label
 
34
        {
 
35
                // 1-based here, to make sure that an uninitialized Label isn't valid
 
36
                private readonly int index1;
 
37
 
 
38
                internal Label(int index)
 
39
                {
 
40
                        this.index1 = index + 1;
 
41
                }
 
42
 
 
43
                internal int Index
 
44
                {
 
45
                        get { return index1 - 1; }
 
46
                }
 
47
 
 
48
                public bool Equals(Label other)
 
49
                {
 
50
                        return other.index1 == index1;
 
51
                }
 
52
 
 
53
                public override bool Equals(object obj)
 
54
                {
 
55
                        return this == obj as Label?;
 
56
                }
 
57
 
 
58
                public override int GetHashCode()
 
59
                {
 
60
                        return index1;
 
61
                }
 
62
 
 
63
                public static bool operator ==(Label arg1, Label arg2)
 
64
                {
 
65
                        return arg1.index1 == arg2.index1;
 
66
                }
 
67
 
 
68
                public static bool operator !=(Label arg1, Label arg2)
 
69
                {
 
70
                        return !(arg1 == arg2);
 
71
                }
 
72
        }
 
73
 
 
74
        public sealed class LocalBuilder : LocalVariableInfo
 
75
        {
 
76
                internal string name;
 
77
                internal int startOffset;
 
78
                internal int endOffset;
 
79
 
 
80
                internal LocalBuilder(Type localType, int index, bool pinned)
 
81
                        : base(index, localType, pinned)
 
82
                {
 
83
                }
 
84
 
 
85
                internal LocalBuilder(Type localType, int index, bool pinned, CustomModifiers customModifiers)
 
86
                        : base(index, localType, pinned, customModifiers)
 
87
                {
 
88
                }
 
89
 
 
90
                public void SetLocalSymInfo(string name)
 
91
                {
 
92
                        this.name = name;
 
93
                }
 
94
 
 
95
                public void SetLocalSymInfo(string name, int startOffset, int endOffset)
 
96
                {
 
97
                        this.name = name;
 
98
                        this.startOffset = startOffset;
 
99
                        this.endOffset = endOffset;
 
100
                }
 
101
        }
 
102
 
 
103
        public sealed class ILGenerator
 
104
        {
 
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;
 
119
                private Scope scope;
 
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;
 
124
 
 
125
                private struct LabelFixup
 
126
                {
 
127
                        internal int label;
 
128
                        internal int offset;
 
129
                }
 
130
 
 
131
                internal sealed class ExceptionBlock : IComparer<ExceptionBlock>
 
132
                {
 
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;
 
141
 
 
142
                        internal ExceptionBlock(int ordinal)
 
143
                        {
 
144
                                this.ordinal = ordinal;
 
145
                        }
 
146
 
 
147
                        internal ExceptionBlock(ExceptionHandler h)
 
148
                        {
 
149
                                this.ordinal = -1;
 
150
                                this.tryOffset = h.TryOffset;
 
151
                                this.tryLength = h.TryLength;
 
152
                                this.handlerOffset = h.HandlerOffset;
 
153
                                this.handlerLength = h.HandlerLength;
 
154
                                this.kind = h.Kind;
 
155
                                this.filterOffsetOrExceptionTypeToken = kind == ExceptionHandlingClauseOptions.Filter ? h.FilterOffset : h.ExceptionTypeToken;
 
156
                        }
 
157
 
 
158
                        int IComparer<ExceptionBlock>.Compare(ExceptionBlock x, ExceptionBlock y)
 
159
                        {
 
160
                                // Mono's sort insists on doing unnecessary comparisons
 
161
                                if (x == y)
 
162
                                {
 
163
                                        return 0;
 
164
                                }
 
165
                                else if (x.tryOffset == y.tryOffset && x.tryLength == y.tryLength)
 
166
                                {
 
167
                                        return x.ordinal < y.ordinal ? -1 : 1;
 
168
                                }
 
169
                                else if (x.tryOffset >= y.tryOffset && x.handlerOffset + x.handlerLength <= y.handlerOffset + y.handlerLength)
 
170
                                {
 
171
                                        return -1;
 
172
                                }
 
173
                                else if (y.tryOffset >= x.tryOffset && y.handlerOffset + y.handlerLength <= x.handlerOffset + x.handlerLength)
 
174
                                {
 
175
                                        return 1;
 
176
                                }
 
177
                                else
 
178
                                {
 
179
                                        return x.ordinal < y.ordinal ? -1 : 1;
 
180
                                }
 
181
                        }
 
182
                }
 
183
 
 
184
                private struct SequencePoint
 
185
                {
 
186
                        internal ISymbolDocumentWriter document;
 
187
                        internal int offset;
 
188
                        internal int startLine;
 
189
                        internal int startColumn;
 
190
                        internal int endLine;
 
191
                        internal int endColumn;
 
192
                }
 
193
 
 
194
                private sealed class Scope
 
195
                {
 
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;
 
201
 
 
202
                        internal Scope(Scope parent)
 
203
                        {
 
204
                                this.parent = parent;
 
205
                        }
 
206
                }
 
207
 
 
208
                internal ILGenerator(ModuleBuilder moduleBuilder, int initialCapacity)
 
209
                {
 
210
                        this.code = new ByteBuffer(initialCapacity);
 
211
                        this.moduleBuilder = moduleBuilder;
 
212
                        this.locals = SignatureHelper.GetLocalVarSigHelper(moduleBuilder);
 
213
                        if (moduleBuilder.symbolWriter != null)
 
214
                        {
 
215
                                scope = new Scope(null);
 
216
                        }
 
217
                }
 
218
 
 
219
                // non-standard API
 
220
                public void __DisableExceptionBlockAssistance()
 
221
                {
 
222
                        exceptionBlockAssistanceMode = EBAM_DISABLE;
 
223
                }
 
224
 
 
225
                // non-standard API
 
226
                public void __CleverExceptionBlockAssistance()
 
227
                {
 
228
                        exceptionBlockAssistanceMode = EBAM_CLEVER;
 
229
                }
 
230
 
 
231
                // non-standard API
 
232
                public int __MaxStackSize
 
233
                {
 
234
                        get { return maxStack; }
 
235
                        set
 
236
                        {
 
237
                                maxStack = (ushort)value;
 
238
                                fatHeader = true;
 
239
                        }
 
240
                }
 
241
 
 
242
                // non-standard API
 
243
                // returns -1 if the current position is currently unreachable
 
244
                public int __StackHeight
 
245
                {
 
246
                        get { return stackHeight; }
 
247
                }
 
248
 
 
249
                // new in .NET 4.0
 
250
                public int ILOffset
 
251
                {
 
252
                        get { return code.Position; }
 
253
                }
 
254
 
 
255
                public void BeginCatchBlock(Type exceptionType)
 
256
                {
 
257
                        if (exceptionType == null)
 
258
                        {
 
259
                                // this must be a catch block after a filter
 
260
                                ExceptionBlock block = exceptionStack.Peek();
 
261
                                if (block.kind != ExceptionHandlingClauseOptions.Filter || block.handlerOffset != 0)
 
262
                                {
 
263
                                        throw new ArgumentNullException("exceptionType");
 
264
                                }
 
265
                                if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
 
266
                                {
 
267
                                        Emit(OpCodes.Endfilter);
 
268
                                }
 
269
                                stackHeight = 0;
 
270
                                UpdateStack(1);
 
271
                                block.handlerOffset = code.Position;
 
272
                        }
 
273
                        else
 
274
                        {
 
275
                                ExceptionBlock block = BeginCatchOrFilterBlock();
 
276
                                block.kind = ExceptionHandlingClauseOptions.Clause;
 
277
                                block.filterOffsetOrExceptionTypeToken = moduleBuilder.GetTypeTokenForMemberRef(exceptionType);
 
278
                                block.handlerOffset = code.Position;
 
279
                        }
 
280
                }
 
281
 
 
282
                private ExceptionBlock BeginCatchOrFilterBlock()
 
283
                {
 
284
                        ExceptionBlock block = exceptionStack.Peek();
 
285
                        if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
 
286
                        {
 
287
                                Emit(OpCodes.Leave, block.labelEnd);
 
288
                        }
 
289
                        stackHeight = 0;
 
290
                        UpdateStack(1);
 
291
                        if (block.tryLength == 0)
 
292
                        {
 
293
                                block.tryLength = code.Position - block.tryOffset;
 
294
                        }
 
295
                        else
 
296
                        {
 
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;
 
303
                                block = newBlock;
 
304
                                exceptions.Add(block);
 
305
                                exceptionStack.Push(block);
 
306
                        }
 
307
                        return block;
 
308
                }
 
309
 
 
310
                public Label BeginExceptionBlock()
 
311
                {
 
312
                        ExceptionBlock block = new ExceptionBlock(exceptions.Count);
 
313
                        block.labelEnd = DefineLabel();
 
314
                        block.tryOffset = code.Position;
 
315
                        exceptionStack.Push(block);
 
316
                        exceptions.Add(block);
 
317
                        stackHeight = 0;
 
318
                        return block.labelEnd;
 
319
                }
 
320
 
 
321
                public void BeginExceptFilterBlock()
 
322
                {
 
323
                        ExceptionBlock block = BeginCatchOrFilterBlock();
 
324
                        block.kind = ExceptionHandlingClauseOptions.Filter;
 
325
                        block.filterOffsetOrExceptionTypeToken = code.Position;
 
326
                }
 
327
 
 
328
                public void BeginFaultBlock()
 
329
                {
 
330
                        BeginFinallyFaultBlock(ExceptionHandlingClauseOptions.Fault);
 
331
                }
 
332
 
 
333
                public void BeginFinallyBlock()
 
334
                {
 
335
                        BeginFinallyFaultBlock(ExceptionHandlingClauseOptions.Finally);
 
336
                }
 
337
 
 
338
                private void BeginFinallyFaultBlock(ExceptionHandlingClauseOptions kind)
 
339
                {
 
340
                        ExceptionBlock block = exceptionStack.Peek();
 
341
                        if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
 
342
                        {
 
343
                                Emit(OpCodes.Leave, block.labelEnd);
 
344
                        }
 
345
                        if (block.handlerOffset == 0)
 
346
                        {
 
347
                                block.tryLength = code.Position - block.tryOffset;
 
348
                        }
 
349
                        else
 
350
                        {
 
351
                                block.handlerLength = code.Position - block.handlerOffset;
 
352
                                Label labelEnd;
 
353
                                if (exceptionBlockAssistanceMode != EBAM_COMPAT)
 
354
                                {
 
355
                                        labelEnd = block.labelEnd;
 
356
                                }
 
357
                                else
 
358
                                {
 
359
                                        MarkLabel(block.labelEnd);
 
360
                                        labelEnd = DefineLabel();
 
361
                                        Emit(OpCodes.Leave, labelEnd);
 
362
                                }
 
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;
 
368
                                block = newBlock;
 
369
                                exceptions.Add(block);
 
370
                                exceptionStack.Push(block);
 
371
                        }
 
372
                        block.handlerOffset = code.Position;
 
373
                        block.kind = kind;
 
374
                        stackHeight = 0;
 
375
                }
 
376
 
 
377
                public void EndExceptionBlock()
 
378
                {
 
379
                        ExceptionBlock block = exceptionStack.Pop();
 
380
                        if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
 
381
                        {
 
382
                                if (block.kind != ExceptionHandlingClauseOptions.Finally && block.kind != ExceptionHandlingClauseOptions.Fault)
 
383
                                {
 
384
                                        Emit(OpCodes.Leave, block.labelEnd);
 
385
                                }
 
386
                                else
 
387
                                {
 
388
                                        Emit(OpCodes.Endfinally);
 
389
                                }
 
390
                        }
 
391
                        MarkLabel(block.labelEnd);
 
392
                        block.handlerLength = code.Position - block.handlerOffset;
 
393
                }
 
394
 
 
395
                public void BeginScope()
 
396
                {
 
397
                        Scope newScope = new Scope(scope);
 
398
                        scope.children.Add(newScope);
 
399
                        scope = newScope;
 
400
                        scope.startOffset = code.Position;
 
401
                }
 
402
 
 
403
                public void UsingNamespace(string usingNamespace)
 
404
                {
 
405
                        if (moduleBuilder.symbolWriter != null)
 
406
                        {
 
407
                                moduleBuilder.symbolWriter.UsingNamespace(usingNamespace);
 
408
                        }
 
409
                }
 
410
 
 
411
                public LocalBuilder DeclareLocal(Type localType)
 
412
                {
 
413
                        return DeclareLocal(localType, false);
 
414
                }
 
415
 
 
416
                public LocalBuilder DeclareLocal(Type localType, bool pinned)
 
417
                {
 
418
                        LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned);
 
419
                        locals.AddArgument(localType, pinned);
 
420
                        if (scope != null)
 
421
                        {
 
422
                                scope.locals.Add(local);
 
423
                        }
 
424
                        return local;
 
425
                }
 
426
 
 
427
                public LocalBuilder __DeclareLocal(Type localType, bool pinned, CustomModifiers customModifiers)
 
428
                {
 
429
                        LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned, customModifiers);
 
430
                        locals.__AddArgument(localType, pinned, customModifiers);
 
431
                        if (scope != null)
 
432
                        {
 
433
                                scope.locals.Add(local);
 
434
                        }
 
435
                        return local;
 
436
                }
 
437
 
 
438
                public Label DefineLabel()
 
439
                {
 
440
                        Label label = new Label(labels.Count);
 
441
                        labels.Add(-1);
 
442
                        labelStackHeight.Add(-1);
 
443
                        return label;
 
444
                }
 
445
 
 
446
                public void Emit(OpCode opc)
 
447
                {
 
448
                        Debug.Assert(opc != OpCodes.Ret || (opc == OpCodes.Ret && stackHeight <= 1));
 
449
                        if (opc.Value < 0)
 
450
                        {
 
451
                                code.Write((byte)(opc.Value >> 8));
 
452
                        }
 
453
                        code.Write((byte)opc.Value);
 
454
                        switch (opc.FlowControl)
 
455
                        {
 
456
                                case FlowControl.Branch:
 
457
                                case FlowControl.Break:
 
458
                                case FlowControl.Return:
 
459
                                case FlowControl.Throw:
 
460
                                        stackHeight = -1;
 
461
                                        break;
 
462
                                default:
 
463
                                        UpdateStack(opc.StackDiff);
 
464
                                        break;
 
465
                        }
 
466
                }
 
467
 
 
468
                private void UpdateStack(int stackdiff)
 
469
                {
 
470
                        if (stackHeight == -1)
 
471
                        {
 
472
                                // we're about to emit code that is either unreachable or reachable only via a backward branch
 
473
                                stackHeight = 0;
 
474
                        }
 
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);
 
479
                }
 
480
 
 
481
                public void Emit(OpCode opc, byte arg)
 
482
                {
 
483
                        Emit(opc);
 
484
                        code.Write(arg);
 
485
                }
 
486
 
 
487
                public void Emit(OpCode opc, double arg)
 
488
                {
 
489
                        Emit(opc);
 
490
                        code.Write(arg);
 
491
                }
 
492
 
 
493
                public void Emit(OpCode opc, FieldInfo field)
 
494
                {
 
495
                        Emit(opc);
 
496
                        WriteToken(moduleBuilder.GetFieldToken(field).Token);
 
497
                }
 
498
 
 
499
                public void Emit(OpCode opc, short arg)
 
500
                {
 
501
                        Emit(opc);
 
502
                        code.Write(arg);
 
503
                }
 
504
 
 
505
                public void Emit(OpCode opc, int arg)
 
506
                {
 
507
                        Emit(opc);
 
508
                        code.Write(arg);
 
509
                }
 
510
 
 
511
                public void Emit(OpCode opc, long arg)
 
512
                {
 
513
                        Emit(opc);
 
514
                        code.Write(arg);
 
515
                }
 
516
 
 
517
                public void Emit(OpCode opc, Label label)
 
518
                {
 
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;
 
523
                        Emit(opc);
 
524
                        if (opc == OpCodes.Leave || opc == OpCodes.Leave_S)
 
525
                        {
 
526
                                flowStackHeight = 0;
 
527
                        }
 
528
                        else if (opc.FlowControl != FlowControl.Branch)
 
529
                        {
 
530
                                flowStackHeight = this.stackHeight;
 
531
                        }
 
532
                        // if the label has already been marked, we can emit the branch offset directly
 
533
                        if (labels[label.Index] != -1)
 
534
                        {
 
535
                                if (labelStackHeight[label.Index] != flowStackHeight && (labelStackHeight[label.Index] != 0 || flowStackHeight != -1))
 
536
                                {
 
537
                                        // the "backward branch constraint" prohibits this, so we don't need to support it
 
538
                                        throw new NotSupportedException("'Backward branch constraints' violated");
 
539
                                }
 
540
                                if (opc.OperandType == OperandType.ShortInlineBrTarget)
 
541
                                {
 
542
                                        WriteByteBranchOffset(labels[label.Index] - (code.Position + 1));
 
543
                                }
 
544
                                else
 
545
                                {
 
546
                                        code.Write(labels[label.Index] - (code.Position + 4));
 
547
                                }
 
548
                        }
 
549
                        else
 
550
                        {
 
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)
 
558
                                {
 
559
                                        code.Write((byte)1);
 
560
                                }
 
561
                                else
 
562
                                {
 
563
                                        code.Write(4);
 
564
                                }
 
565
                        }
 
566
                }
 
567
 
 
568
                private void WriteByteBranchOffset(int offset)
 
569
                {
 
570
                        if (offset < -128 || offset > 127)
 
571
                        {
 
572
                                throw new NotSupportedException("Branch offset of " + offset + " does not fit in one-byte branch target at position " + code.Position);
 
573
                        }
 
574
                        code.Write((byte)offset);
 
575
                }
 
576
 
 
577
                public void Emit(OpCode opc, Label[] labels)
 
578
                {
 
579
                        Emit(opc);
 
580
                        LabelFixup fix = new LabelFixup();
 
581
                        fix.label = -1;
 
582
                        fix.offset = code.Position;
 
583
                        labelFixups.Add(fix);
 
584
                        code.Write(labels.Length);
 
585
                        foreach (Label label in labels)
 
586
                        {
 
587
                                code.Write(label.Index);
 
588
                                if (this.labels[label.Index] != -1)
 
589
                                {
 
590
                                        if (labelStackHeight[label.Index] != stackHeight)
 
591
                                        {
 
592
                                                // the "backward branch constraint" prohibits this, so we don't need to support it
 
593
                                                throw new NotSupportedException();
 
594
                                        }
 
595
                                }
 
596
                                else
 
597
                                {
 
598
                                        Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == stackHeight);
 
599
                                        labelStackHeight[label.Index] = stackHeight;
 
600
                                }
 
601
                        }
 
602
                }
 
603
 
 
604
                public void Emit(OpCode opc, LocalBuilder local)
 
605
                {
 
606
                        if ((opc == OpCodes.Ldloc || opc == OpCodes.Ldloca || opc == OpCodes.Stloc) && local.LocalIndex < 256)
 
607
                        {
 
608
                                if (opc == OpCodes.Ldloc)
 
609
                                {
 
610
                                        switch (local.LocalIndex)
 
611
                                        {
 
612
                                                case 0:
 
613
                                                        Emit(OpCodes.Ldloc_0);
 
614
                                                        break;
 
615
                                                case 1:
 
616
                                                        Emit(OpCodes.Ldloc_1);
 
617
                                                        break;
 
618
                                                case 2:
 
619
                                                        Emit(OpCodes.Ldloc_2);
 
620
                                                        break;
 
621
                                                case 3:
 
622
                                                        Emit(OpCodes.Ldloc_3);
 
623
                                                        break;
 
624
                                                default:
 
625
                                                        Emit(OpCodes.Ldloc_S);
 
626
                                                        code.Write((byte)local.LocalIndex);
 
627
                                                        break;
 
628
                                        }
 
629
                                }
 
630
                                else if (opc == OpCodes.Ldloca)
 
631
                                {
 
632
                                        Emit(OpCodes.Ldloca_S);
 
633
                                        code.Write((byte)local.LocalIndex);
 
634
                                }
 
635
                                else if (opc == OpCodes.Stloc)
 
636
                                {
 
637
                                        switch (local.LocalIndex)
 
638
                                        {
 
639
                                                case 0:
 
640
                                                        Emit(OpCodes.Stloc_0);
 
641
                                                        break;
 
642
                                                case 1:
 
643
                                                        Emit(OpCodes.Stloc_1);
 
644
                                                        break;
 
645
                                                case 2:
 
646
                                                        Emit(OpCodes.Stloc_2);
 
647
                                                        break;
 
648
                                                case 3:
 
649
                                                        Emit(OpCodes.Stloc_3);
 
650
                                                        break;
 
651
                                                default:
 
652
                                                        Emit(OpCodes.Stloc_S);
 
653
                                                        code.Write((byte)local.LocalIndex);
 
654
                                                        break;
 
655
                                        }
 
656
                                }
 
657
                        }
 
658
                        else
 
659
                        {
 
660
                                Emit(opc);
 
661
                                switch (opc.OperandType)
 
662
                                {
 
663
                                        case OperandType.InlineVar:
 
664
                                                code.Write((ushort)local.LocalIndex);
 
665
                                                break;
 
666
                                        case OperandType.ShortInlineVar:
 
667
                                                code.Write((byte)local.LocalIndex);
 
668
                                                break;
 
669
                                }
 
670
                        }
 
671
                }
 
672
 
 
673
                private void WriteToken(int token)
 
674
                {
 
675
                        if (ModuleBuilder.IsPseudoToken(token))
 
676
                        {
 
677
                                tokenFixups.Add(code.Position);
 
678
                        }
 
679
                        code.Write(token);
 
680
                }
 
681
 
 
682
                private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
 
683
                {
 
684
                        if (opc == OpCodes.Jmp)
 
685
                        {
 
686
                                stackHeight = -1;
 
687
                        }
 
688
                        else if (opc.FlowControl == FlowControl.Call)
 
689
                        {
 
690
                                int stackdiff = 0;
 
691
                                if ((hasthis && opc != OpCodes.Newobj) || opc == OpCodes.Calli)
 
692
                                {
 
693
                                        // pop this
 
694
                                        stackdiff--;
 
695
                                }
 
696
                                // pop parameters
 
697
                                stackdiff -= parameterCount;
 
698
                                if (returnType != moduleBuilder.universe.System_Void)
 
699
                                {
 
700
                                        // push return value
 
701
                                        stackdiff++;
 
702
                                }
 
703
                                UpdateStack(stackdiff);
 
704
                        }
 
705
                }
 
706
 
 
707
                public void Emit(OpCode opc, MethodInfo method)
 
708
                {
 
709
                        UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount);
 
710
                        Emit(opc);
 
711
                        WriteToken(moduleBuilder.GetMethodTokenForIL(method).Token);
 
712
                }
 
713
 
 
714
                public void Emit(OpCode opc, ConstructorInfo constructor)
 
715
                {
 
716
                        Emit(opc, constructor.GetMethodInfo());
 
717
                }
 
718
 
 
719
                public void Emit(OpCode opc, sbyte arg)
 
720
                {
 
721
                        Emit(opc);
 
722
                        code.Write(arg);
 
723
                }
 
724
 
 
725
                public void Emit(OpCode opc, float arg)
 
726
                {
 
727
                        Emit(opc);
 
728
                        code.Write(arg);
 
729
                }
 
730
 
 
731
                public void Emit(OpCode opc, string str)
 
732
                {
 
733
                        Emit(opc);
 
734
                        code.Write(moduleBuilder.GetStringConstant(str).Token);
 
735
                }
 
736
 
 
737
                public void Emit(OpCode opc, Type type)
 
738
                {
 
739
                        Emit(opc);
 
740
                        if (opc == OpCodes.Ldtoken)
 
741
                        {
 
742
                                code.Write(moduleBuilder.GetTypeToken(type).Token);
 
743
                        }
 
744
                        else
 
745
                        {
 
746
                                code.Write(moduleBuilder.GetTypeTokenForMemberRef(type));
 
747
                        }
 
748
                }
 
749
 
 
750
                public void Emit(OpCode opcode, SignatureHelper signature)
 
751
                {
 
752
                        Emit(opcode);
 
753
                        UpdateStack(opcode, signature.HasThis, signature.ReturnType, signature.ParameterCount);
 
754
                        code.Write(moduleBuilder.GetSignatureToken(signature).Token);
 
755
                }
 
756
 
 
757
                public void EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes)
 
758
                {
 
759
                        __EmitCall(opc, method, optionalParameterTypes, null);
 
760
                }
 
761
 
 
762
                public void __EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
 
763
                {
 
764
                        if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
 
765
                        {
 
766
                                Emit(opc, method);
 
767
                        }
 
768
                        else
 
769
                        {
 
770
                                Emit(opc);
 
771
                                UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount + optionalParameterTypes.Length);
 
772
                                code.Write(moduleBuilder.__GetMethodToken(method, optionalParameterTypes, customModifiers).Token);
 
773
                        }
 
774
                }
 
775
 
 
776
                public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes)
 
777
                {
 
778
                        EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes);
 
779
                }
 
780
 
 
781
                public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
 
782
                {
 
783
                        __EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes, customModifiers);
 
784
                }
 
785
 
 
786
                public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
 
787
                {
 
788
                        SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
 
789
                        sig.AddArguments(parameterTypes, null, null);
 
790
                        Emit(opc, sig);
 
791
                }
 
792
 
 
793
                public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
 
794
                {
 
795
                        SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
 
796
                        sig.AddArguments(parameterTypes, null, null);
 
797
                        sig.AddSentinel();
 
798
                        sig.AddArguments(optionalParameterTypes, null, null);
 
799
                        Emit(opc, sig);
 
800
                }
 
801
 
 
802
                public void __EmitCalli(OpCode opc, __StandAloneMethodSig sig)
 
803
                {
 
804
                        Emit(opc);
 
805
                        if (sig.IsUnmanaged)
 
806
                        {
 
807
                                UpdateStack(opc, false, sig.ReturnType, sig.ParameterCount);
 
808
                        }
 
809
                        else
 
810
                        {
 
811
                                CallingConventions callingConvention = sig.CallingConvention;
 
812
                                UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, sig.ReturnType, sig.ParameterCount);
 
813
                        }
 
814
                        ByteBuffer bb = new ByteBuffer(16);
 
815
                        Signature.WriteStandAloneMethodSig(moduleBuilder, bb, sig);
 
816
                        code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(bb)));
 
817
                }
 
818
 
 
819
                public void EmitWriteLine(string text)
 
820
                {
 
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 }));
 
824
                }
 
825
 
 
826
                public void EmitWriteLine(FieldInfo field)
 
827
                {
 
828
                        Universe u = moduleBuilder.universe;
 
829
                        Emit(OpCodes.Call, u.Import(typeof(Console)).GetMethod("get_Out"));
 
830
                        if (field.IsStatic)
 
831
                        {
 
832
                                Emit(OpCodes.Ldsfld, field);
 
833
                        }
 
834
                        else
 
835
                        {
 
836
                                Emit(OpCodes.Ldarg_0);
 
837
                                Emit(OpCodes.Ldfld, field);
 
838
                        }
 
839
                        Emit(OpCodes.Callvirt, u.Import(typeof(System.IO.TextWriter)).GetMethod("WriteLine", new Type[] { field.FieldType }));
 
840
                }
 
841
 
 
842
                public void EmitWriteLine(LocalBuilder local)
 
843
                {
 
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 }));
 
848
                }
 
849
 
 
850
                public void EndScope()
 
851
                {
 
852
                        scope.endOffset = code.Position;
 
853
                        scope = scope.parent;
 
854
                }
 
855
 
 
856
                public void MarkLabel(Label loc)
 
857
                {
 
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)
 
861
                        {
 
862
                                if (stackHeight == -1)
 
863
                                {
 
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;
 
869
                                }
 
870
                                else
 
871
                                {
 
872
                                        labelStackHeight[loc.Index] = stackHeight;
 
873
                                }
 
874
                        }
 
875
                        else
 
876
                        {
 
877
                                Debug.Assert(stackHeight == -1 || stackHeight == labelStackHeight[loc.Index]);
 
878
                                stackHeight = labelStackHeight[loc.Index];
 
879
                        }
 
880
                }
 
881
 
 
882
                public void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
 
883
                {
 
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);
 
892
                }
 
893
 
 
894
                public void ThrowException(Type excType)
 
895
                {
 
896
                        Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
 
897
                        Emit(OpCodes.Throw);
 
898
                }
 
899
 
 
900
                internal int WriteBody(bool initLocals)
 
901
                {
 
902
                        if (moduleBuilder.symbolWriter != null)
 
903
                        {
 
904
                                Debug.Assert(scope != null && scope.parent == null);
 
905
                                scope.endOffset = code.Position;
 
906
                        }
 
907
 
 
908
                        ResolveBranches();
 
909
 
 
910
                        ByteBuffer bb = moduleBuilder.methodBodies;
 
911
 
 
912
                        int localVarSigTok = 0;
 
913
 
 
914
                        int rva;
 
915
                        if (localsCount == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64 && !fatHeader)
 
916
                        {
 
917
                                rva = WriteTinyHeaderAndCode(bb);
 
918
                        }
 
919
                        else
 
920
                        {
 
921
                                if (localsCount != 0)
 
922
                                {
 
923
                                        localVarSigTok = moduleBuilder.GetSignatureToken(locals).Token;
 
924
                                }
 
925
                                rva = WriteFatHeaderAndCode(bb, localVarSigTok, initLocals);
 
926
                        }
 
927
 
 
928
                        if (moduleBuilder.symbolWriter != null)
 
929
                        {
 
930
                                if (sequencePoints.Count != 0)
 
931
                                {
 
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++)
 
939
                                        {
 
940
                                                if (sequencePoints[i].document != document)
 
941
                                                {
 
942
                                                        throw new NotImplementedException();
 
943
                                                }
 
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;
 
949
                                        }
 
950
                                        moduleBuilder.symbolWriter.DefineSequencePoints(document, offsets, lines, columns, endLines, endColumns);
 
951
                                }
 
952
 
 
953
                                WriteScope(scope, localVarSigTok);
 
954
                        }
 
955
                        return rva;
 
956
                }
 
957
 
 
958
                private void ResolveBranches()
 
959
                {
 
960
                        foreach (LabelFixup fixup in labelFixups)
 
961
                        {
 
962
                                // is it a switch?
 
963
                                if (fixup.label == -1)
 
964
                                {
 
965
                                        code.Position = fixup.offset;
 
966
                                        int count = code.GetInt32AtCurrentPosition();
 
967
                                        int offset = fixup.offset + 4 + 4 * count;
 
968
                                        code.Position += 4;
 
969
                                        for (int i = 0; i < count; i++)
 
970
                                        {
 
971
                                                int index = code.GetInt32AtCurrentPosition();
 
972
                                                code.Write(labels[index] - offset);
 
973
                                        }
 
974
                                }
 
975
                                else
 
976
                                {
 
977
                                        code.Position = fixup.offset;
 
978
                                        byte size = code.GetByteAtCurrentPosition();
 
979
                                        int branchOffset = labels[fixup.label] - (code.Position + size);
 
980
                                        if (size == 1)
 
981
                                        {
 
982
                                                WriteByteBranchOffset(branchOffset);
 
983
                                        }
 
984
                                        else
 
985
                                        {
 
986
                                                code.Write(branchOffset);
 
987
                                        }
 
988
                                }
 
989
                        }
 
990
                }
 
991
 
 
992
                internal static void WriteTinyHeader(ByteBuffer bb, int length)
 
993
                {
 
994
                        const byte CorILMethod_TinyFormat = 0x2;
 
995
                        bb.Write((byte)(CorILMethod_TinyFormat | (length << 2)));
 
996
                }
 
997
 
 
998
                private int WriteTinyHeaderAndCode(ByteBuffer bb)
 
999
                {
 
1000
                        int rva = bb.Position;
 
1001
                        WriteTinyHeader(bb, code.Length);
 
1002
                        AddTokenFixups(bb.Position, moduleBuilder.tokenFixupOffsets, tokenFixups);
 
1003
                        bb.Write(code);
 
1004
                        return rva;
 
1005
                }
 
1006
 
 
1007
                internal static void WriteFatHeader(ByteBuffer bb, bool initLocals, bool exceptions, ushort maxStack, int codeLength, int localVarSigTok)
 
1008
                {
 
1009
                        const byte CorILMethod_FatFormat = 0x03;
 
1010
                        const byte CorILMethod_MoreSects = 0x08;
 
1011
                        const byte CorILMethod_InitLocals = 0x10;
 
1012
 
 
1013
                        short flagsAndSize = (short)(CorILMethod_FatFormat | (3 << 12));
 
1014
                        if (initLocals)
 
1015
                        {
 
1016
                                flagsAndSize |= CorILMethod_InitLocals;
 
1017
                        }
 
1018
 
 
1019
                        if (exceptions)
 
1020
                        {
 
1021
                                flagsAndSize |= CorILMethod_MoreSects;
 
1022
                        }
 
1023
 
 
1024
                        bb.Write(flagsAndSize);
 
1025
                        bb.Write(maxStack);
 
1026
                        bb.Write(codeLength);
 
1027
                        bb.Write(localVarSigTok);
 
1028
                }
 
1029
 
 
1030
                private int WriteFatHeaderAndCode(ByteBuffer bb, int localVarSigTok, bool initLocals)
 
1031
                {
 
1032
                        // fat headers require 4-byte alignment
 
1033
                        bb.Align(4);
 
1034
                        int rva = bb.Position;
 
1035
                        WriteFatHeader(bb, initLocals, exceptions.Count > 0, maxStack, code.Length, localVarSigTok);
 
1036
                        AddTokenFixups(bb.Position, moduleBuilder.tokenFixupOffsets, tokenFixups);
 
1037
                        bb.Write(code);
 
1038
                        if (exceptions.Count > 0)
 
1039
                        {
 
1040
                                exceptions.Sort(exceptions[0]);
 
1041
                                WriteExceptionHandlers(bb, exceptions);
 
1042
                        }
 
1043
                        return rva;
 
1044
                }
 
1045
 
 
1046
                internal static void WriteExceptionHandlers(ByteBuffer bb, List<ExceptionBlock> exceptions)
 
1047
                {
 
1048
                        bb.Align(4);
 
1049
 
 
1050
                        bool fat = false;
 
1051
                        if (exceptions.Count * 12 + 4 > 255)
 
1052
                        {
 
1053
                                fat = true;
 
1054
                        }
 
1055
                        else
 
1056
                        {
 
1057
                                foreach (ExceptionBlock block in exceptions)
 
1058
                                {
 
1059
                                        if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
 
1060
                                        {
 
1061
                                                fat = true;
 
1062
                                                break;
 
1063
                                        }
 
1064
                                }
 
1065
                        }
 
1066
 
 
1067
                        const byte CorILMethod_Sect_EHTable = 0x1;
 
1068
                        const byte CorILMethod_Sect_FatFormat = 0x40;
 
1069
 
 
1070
                        if (fat)
 
1071
                        {
 
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)
 
1077
                                {
 
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);
 
1084
                                }
 
1085
                        }
 
1086
                        else
 
1087
                        {
 
1088
                                bb.Write(CorILMethod_Sect_EHTable);
 
1089
                                bb.Write((byte)(exceptions.Count * 12 + 4));
 
1090
                                bb.Write((short)0);
 
1091
                                foreach (ExceptionBlock block in exceptions)
 
1092
                                {
 
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);
 
1099
                                }
 
1100
                        }
 
1101
                }
 
1102
 
 
1103
                internal static void AddTokenFixups(int codeOffset, List<int> tokenFixupOffsets, IEnumerable<int> tokenFixups)
 
1104
                {
 
1105
                        foreach (int fixup in tokenFixups)
 
1106
                        {
 
1107
                                tokenFixupOffsets.Add(fixup + codeOffset);
 
1108
                        }
 
1109
                }
 
1110
 
 
1111
                private void WriteScope(Scope scope, int localVarSigTok)
 
1112
                {
 
1113
                        moduleBuilder.symbolWriter.OpenScope(scope.startOffset);
 
1114
                        foreach (LocalBuilder local in scope.locals)
 
1115
                        {
 
1116
                                if (local.name != null)
 
1117
                                {
 
1118
                                        int startOffset = local.startOffset;
 
1119
                                        int endOffset = local.endOffset;
 
1120
                                        if (startOffset == 0 && endOffset == 0)
 
1121
                                        {
 
1122
                                                startOffset = scope.startOffset;
 
1123
                                                endOffset = scope.endOffset;
 
1124
                                        }
 
1125
                                        moduleBuilder.symbolWriter.DefineLocalVariable2(local.name, 0, localVarSigTok, SymAddressKind.ILOffset, local.LocalIndex, 0, 0, startOffset, endOffset);
 
1126
                                }
 
1127
                        }
 
1128
                        foreach (Scope child in scope.children)
 
1129
                        {
 
1130
                                WriteScope(child, localVarSigTok);
 
1131
                        }
 
1132
                        moduleBuilder.symbolWriter.CloseScope(scope.endOffset);
 
1133
                }
 
1134
        }
 
1135
}