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

« back to all changes in this revision

Viewing changes to external/ikvm/runtime/CodeEmitter.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) 2002-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
//#define LABELCHECK
 
25
#define CHECK_INVARIANTS
 
26
using System;
 
27
using System.Collections.Generic;
 
28
#if STATIC_COMPILER
 
29
using IKVM.Reflection;
 
30
using IKVM.Reflection.Emit;
 
31
using Type = IKVM.Reflection.Type;
 
32
#else
 
33
using System.Reflection;
 
34
using System.Reflection.Emit;
 
35
#endif
 
36
using System.Runtime.InteropServices;
 
37
using System.Diagnostics.SymbolStore;
 
38
using System.Diagnostics;
 
39
 
 
40
namespace IKVM.Internal
 
41
{
 
42
        sealed class CodeEmitterLabel
 
43
        {
 
44
                internal readonly Label Label;
 
45
                internal int Temp;
 
46
 
 
47
                internal CodeEmitterLabel(Label label)
 
48
                {
 
49
                        this.Label = label;
 
50
                }
 
51
        }
 
52
 
 
53
        sealed class CodeEmitterLocal
 
54
        {
 
55
                private Type type;
 
56
                private string name;
 
57
                private LocalBuilder local;
 
58
 
 
59
                internal CodeEmitterLocal(Type type)
 
60
                {
 
61
                        this.type = type;
 
62
                }
 
63
 
 
64
                internal Type LocalType
 
65
                {
 
66
                        get { return type; }
 
67
                }
 
68
 
 
69
                internal void SetLocalSymInfo(string name)
 
70
                {
 
71
                        this.name = name;
 
72
                }
 
73
 
 
74
                internal int __LocalIndex
 
75
                {
 
76
                        get { return local == null ? 0xFFFF : local.LocalIndex; }
 
77
                }
 
78
 
 
79
                internal void Emit(ILGenerator ilgen, OpCode opcode)
 
80
                {
 
81
                        if (local == null)
 
82
                        {
 
83
                                // it's a temporary local that is only allocated on-demand
 
84
                                local = ilgen.DeclareLocal(type);
 
85
                        }
 
86
                        ilgen.Emit(opcode, local);
 
87
                }
 
88
 
 
89
                internal void Declare(ILGenerator ilgen)
 
90
                {
 
91
                        local = ilgen.DeclareLocal(type);
 
92
                        if (name != null)
 
93
                        {
 
94
                                local.SetLocalSymInfo(name);
 
95
                        }
 
96
                }
 
97
        }
 
98
 
 
99
        sealed class CodeEmitter
 
100
        {
 
101
                private static readonly MethodInfo objectToString = Types.Object.GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
 
102
                private static readonly MethodInfo verboseCastFailure = JVM.SafeGetEnvironmentVariable("IKVM_VERBOSE_CAST") == null ? null : ByteCodeHelperMethods.VerboseCastFailure;
 
103
                private static readonly MethodInfo monitorEnter = JVM.Import(typeof(System.Threading.Monitor)).GetMethod("Enter", BindingFlags.Public | BindingFlags.Static, null, new Type[] { Types.Object }, null);
 
104
                private static readonly MethodInfo monitorExit = JVM.Import(typeof(System.Threading.Monitor)).GetMethod("Exit", BindingFlags.Public | BindingFlags.Static, null, new Type[] { Types.Object }, null);
 
105
                private static readonly bool experimentalOptimizations = JVM.SafeGetEnvironmentVariable("IKVM_EXPERIMENTAL_OPTIMIZATIONS") != null;
 
106
                private static MethodInfo memoryBarrier;
 
107
                private ILGenerator ilgen_real;
 
108
#if !STATIC_COMPILER
 
109
                private bool inFinally;
 
110
                private Stack<bool> exceptionStack = new Stack<bool>();
 
111
#endif
 
112
                private IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter linenums;
 
113
                private CodeEmitterLocal[] tempLocals = new CodeEmitterLocal[32];
 
114
                private ISymbolDocumentWriter symbols;
 
115
                private List<OpCodeWrapper> code = new List<OpCodeWrapper>(10);
 
116
                private readonly Type declaringType;
 
117
#if LABELCHECK
 
118
                private Dictionary<CodeEmitterLabel, System.Diagnostics.StackFrame> labels = new Dictionary<CodeEmitterLabel, System.Diagnostics.StackFrame>();
 
119
#endif
 
120
 
 
121
                static CodeEmitter()
 
122
                {
 
123
                        if (experimentalOptimizations)
 
124
                        {
 
125
                                Console.Error.WriteLine("IKVM.NET experimental optimizations enabled.");
 
126
                        }
 
127
                }
 
128
 
 
129
                enum CodeType : short
 
130
                {
 
131
                        Unreachable,
 
132
                        OpCode,
 
133
                        BeginScope,
 
134
                        EndScope,
 
135
                        DeclareLocal,
 
136
                        ReleaseTempLocal,
 
137
                        SequencePoint,
 
138
                        LineNumber,
 
139
                        Label,
 
140
                        BeginExceptionBlock,
 
141
                        BeginCatchBlock,
 
142
                        BeginFaultBlock,
 
143
                        BeginFinallyBlock,
 
144
                        EndExceptionBlock,
 
145
                        MemoryBarrier,
 
146
                        TailCallPrevention,
 
147
                        ClearStack,
 
148
                        MonitorEnter,
 
149
                        MonitorExit,
 
150
                }
 
151
 
 
152
                enum CodeTypeFlags : short
 
153
                {
 
154
                        None = 0,
 
155
                        EndFaultOrFinally = 1,
 
156
                }
 
157
 
 
158
                struct OpCodeWrapper
 
159
                {
 
160
                        internal readonly CodeType pseudo;
 
161
                        private readonly CodeTypeFlags flags;
 
162
                        internal readonly OpCode opcode;
 
163
                        private readonly object data;
 
164
 
 
165
                        internal OpCodeWrapper(CodeType pseudo, object data)
 
166
                        {
 
167
                                this.pseudo = pseudo;
 
168
                                this.flags = CodeTypeFlags.None;
 
169
                                this.opcode = OpCodes.Nop;
 
170
                                this.data = data;
 
171
                        }
 
172
 
 
173
                        internal OpCodeWrapper(CodeType pseudo, CodeTypeFlags flags)
 
174
                        {
 
175
                                this.pseudo = pseudo;
 
176
                                this.flags = flags;
 
177
                                this.opcode = OpCodes.Nop;
 
178
                                this.data = null;
 
179
                        }
 
180
 
 
181
                        internal OpCodeWrapper(OpCode opcode, object data)
 
182
                        {
 
183
                                this.pseudo = CodeType.OpCode;
 
184
                                this.flags = CodeTypeFlags.None;
 
185
                                this.opcode = opcode;
 
186
                                this.data = data;
 
187
                        }
 
188
 
 
189
                        internal bool Match(OpCodeWrapper other)
 
190
                        {
 
191
                                return other.pseudo == pseudo
 
192
                                        && other.opcode == opcode
 
193
                                        && (other.data == data || (data != null && data.Equals(other.data)));
 
194
                        }
 
195
 
 
196
                        internal bool HasLabel
 
197
                        {
 
198
                                get { return data is CodeEmitterLabel; }
 
199
                        }
 
200
 
 
201
                        internal CodeEmitterLabel Label
 
202
                        {
 
203
                                get { return (CodeEmitterLabel)data; }
 
204
                        }
 
205
 
 
206
                        internal bool MatchLabel(OpCodeWrapper other)
 
207
                        {
 
208
                                return data == other.data;
 
209
                        }
 
210
 
 
211
                        internal CodeEmitterLabel[] Labels
 
212
                        {
 
213
                                get { return (CodeEmitterLabel[])data; }
 
214
                        }
 
215
 
 
216
                        internal bool HasLocal
 
217
                        {
 
218
                                get { return data is CodeEmitterLocal; }
 
219
                        }
 
220
 
 
221
                        internal CodeEmitterLocal Local
 
222
                        {
 
223
                                get { return (CodeEmitterLocal)data; }
 
224
                        }
 
225
 
 
226
                        internal bool MatchLocal(OpCodeWrapper other)
 
227
                        {
 
228
                                return data == other.data;
 
229
                        }
 
230
 
 
231
                        internal bool HasValueByte
 
232
                        {
 
233
                                get { return data is byte; }
 
234
                        }
 
235
 
 
236
                        internal byte ValueByte
 
237
                        {
 
238
                                get { return (byte)data; }
 
239
                        }
 
240
 
 
241
                        internal short ValueInt16
 
242
                        {
 
243
                                get { return (short)data; }
 
244
                        }
 
245
 
 
246
                        internal int ValueInt32
 
247
                        {
 
248
                                get { return (int)data; }
 
249
                        }
 
250
 
 
251
                        internal long ValueInt64
 
252
                        {
 
253
                                get { return (long)data; }
 
254
                        }
 
255
 
 
256
                        internal Type Type
 
257
                        {
 
258
                                get { return (Type)data; }
 
259
                        }
 
260
 
 
261
                        internal FieldInfo FieldInfo
 
262
                        {
 
263
                                get { return (FieldInfo)data; }
 
264
                        }
 
265
 
 
266
                        internal MethodBase MethodBase
 
267
                        {
 
268
                                get { return (MethodBase)data; }
 
269
                        }
 
270
 
 
271
                        internal int Size
 
272
                        {
 
273
                                get
 
274
                                {
 
275
                                        switch (pseudo)
 
276
                                        {
 
277
                                                case CodeType.Unreachable:
 
278
                                                case CodeType.BeginScope:
 
279
                                                case CodeType.EndScope:
 
280
                                                case CodeType.DeclareLocal:
 
281
                                                case CodeType.ReleaseTempLocal:
 
282
                                                case CodeType.LineNumber:
 
283
                                                case CodeType.Label:
 
284
                                                case CodeType.BeginExceptionBlock:
 
285
                                                        return 0;
 
286
                                                case CodeType.SequencePoint:
 
287
                                                        return 1;
 
288
                                                case CodeType.BeginCatchBlock:
 
289
                                                case CodeType.BeginFaultBlock:
 
290
                                                case CodeType.BeginFinallyBlock:
 
291
                                                case CodeType.EndExceptionBlock:
 
292
#if STATIC_COMPILER
 
293
                                                        return 0;
 
294
#else
 
295
                                                        if ((flags & CodeTypeFlags.EndFaultOrFinally) != 0)
 
296
                                                        {
 
297
                                                                return 1 + 2;
 
298
                                                        }
 
299
                                                        return 5 + 2;
 
300
#endif
 
301
                                                case CodeType.MemoryBarrier:
 
302
                                                case CodeType.MonitorEnter:
 
303
                                                case CodeType.MonitorExit:
 
304
                                                        return 5;
 
305
                                                case CodeType.TailCallPrevention:
 
306
                                                        return 2;
 
307
                                                case CodeType.ClearStack:
 
308
                                                        return 2;
 
309
                                                case CodeType.OpCode:
 
310
                                                        if (data == null)
 
311
                                                        {
 
312
                                                                return opcode.Size;
 
313
                                                        }
 
314
                                                        else if (data is int)
 
315
                                                        {
 
316
                                                                return opcode.Size + 4;;
 
317
                                                        }
 
318
                                                        else if (data is long)
 
319
                                                        {
 
320
                                                                return opcode.Size + 8;
 
321
                                                        }
 
322
                                                        else if (data is MethodInfo)
 
323
                                                        {
 
324
                                                                return opcode.Size + 4;
 
325
                                                        }
 
326
                                                        else if (data is ConstructorInfo)
 
327
                                                        {
 
328
                                                                return opcode.Size + 4;
 
329
                                                        }
 
330
                                                        else if (data is FieldInfo)
 
331
                                                        {
 
332
                                                                return opcode.Size + 4;
 
333
                                                        }
 
334
                                                        else if (data is sbyte)
 
335
                                                        {
 
336
                                                                return opcode.Size + 1;
 
337
                                                        }
 
338
                                                        else if (data is byte)
 
339
                                                        {
 
340
                                                                return opcode.Size + 1;
 
341
                                                        }
 
342
                                                        else if (data is short)
 
343
                                                        {
 
344
                                                                return opcode.Size + 2;
 
345
                                                        }
 
346
                                                        else if (data is float)
 
347
                                                        {
 
348
                                                                return opcode.Size + 4;
 
349
                                                        }
 
350
                                                        else if (data is double)
 
351
                                                        {
 
352
                                                                return opcode.Size + 8;
 
353
                                                        }
 
354
                                                        else if (data is string)
 
355
                                                        {
 
356
                                                                return opcode.Size + 4;
 
357
                                                        }
 
358
                                                        else if (data is Type)
 
359
                                                        {
 
360
                                                                return opcode.Size + 4;
 
361
                                                        }
 
362
                                                        else if (data is CodeEmitterLocal)
 
363
                                                        {
 
364
                                                                int index = ((CodeEmitterLocal)data).__LocalIndex;
 
365
                                                                if(index < 4 && opcode.Value != OpCodes.Ldloca.Value && opcode.Value != OpCodes.Ldloca_S.Value)
 
366
                                                                {
 
367
                                                                        return 1;
 
368
                                                                }
 
369
                                                                else if(index < 256)
 
370
                                                                {
 
371
                                                                        return 2;
 
372
                                                                }
 
373
                                                                else
 
374
                                                                {
 
375
                                                                        return 4;
 
376
                                                                }
 
377
                                                        }
 
378
                                                        else if (data is CodeEmitterLabel)
 
379
                                                        {
 
380
                                                                switch(opcode.OperandType)
 
381
                                                                {
 
382
                                                                        case OperandType.InlineBrTarget:
 
383
                                                                                return opcode.Size + 4;
 
384
                                                                        case OperandType.ShortInlineBrTarget:
 
385
                                                                                return opcode.Size + 1;
 
386
                                                                        default:
 
387
                                                                                throw new InvalidOperationException();
 
388
                                                                }
 
389
                                                        }
 
390
                                                        else if (data is CodeEmitterLabel[])
 
391
                                                        {
 
392
                                                                return 5 + ((CodeEmitterLabel[])data).Length * 4;
 
393
                                                        }
 
394
                                                        else if (data is CalliWrapper)
 
395
                                                        {
 
396
                                                                return 5;
 
397
                                                        }
 
398
                                                        else
 
399
                                                        {
 
400
                                                                throw new InvalidOperationException();
 
401
                                                        }
 
402
                                                default:
 
403
                                                        throw new InvalidOperationException();
 
404
                                        }
 
405
                                }
 
406
                        }
 
407
 
 
408
                        internal void RealEmit(int ilOffset, CodeEmitter codeEmitter, ref int lineNumber)
 
409
                        {
 
410
                                if (pseudo == CodeType.OpCode)
 
411
                                {
 
412
                                        if (lineNumber != -1)
 
413
                                        {
 
414
                                                if (codeEmitter.linenums == null)
 
415
                                                {
 
416
                                                        codeEmitter.linenums = new IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter(32);
 
417
                                                }
 
418
                                                codeEmitter.linenums.AddMapping(ilOffset, lineNumber);
 
419
                                                lineNumber = -1;
 
420
                                        }
 
421
                                        codeEmitter.RealEmitOpCode(opcode, data);
 
422
                                }
 
423
                                else if (pseudo == CodeType.LineNumber)
 
424
                                {
 
425
                                        lineNumber = (int)data;
 
426
                                }
 
427
                                else
 
428
                                {
 
429
                                        codeEmitter.RealEmitPseudoOpCode(ilOffset, pseudo, data);
 
430
                                }
 
431
                        }
 
432
 
 
433
                        public override string ToString()
 
434
                        {
 
435
                                return pseudo.ToString() + " " + data;
 
436
                        }
 
437
                }
 
438
 
 
439
                sealed class CalliWrapper
 
440
                {
 
441
                        internal readonly CallingConvention unmanagedCallConv;
 
442
                        internal readonly Type returnType;
 
443
                        internal readonly Type[] parameterTypes;
 
444
 
 
445
                        internal CalliWrapper(CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
 
446
                        {
 
447
                                this.unmanagedCallConv = unmanagedCallConv;
 
448
                                this.returnType = returnType;
 
449
                                this.parameterTypes = parameterTypes == null ? null : (Type[])parameterTypes.Clone();
 
450
                        }
 
451
                }
 
452
 
 
453
                internal static CodeEmitter Create(MethodBuilder mb)
 
454
                {
 
455
                        return new CodeEmitter(mb.GetILGenerator(), mb.DeclaringType);
 
456
                }
 
457
 
 
458
#if !STATIC_COMPILER
 
459
                internal static CodeEmitter Create(DynamicMethod dm)
 
460
                {
 
461
                        return new CodeEmitter(dm.GetILGenerator(), null);
 
462
                }
 
463
#endif
 
464
 
 
465
                private CodeEmitter(ILGenerator ilgen, Type declaringType)
 
466
                {
 
467
#if STATIC_COMPILER
 
468
                        ilgen.__DisableExceptionBlockAssistance();
 
469
#endif
 
470
                        this.ilgen_real = ilgen;
 
471
                        this.declaringType = declaringType;
 
472
                }
 
473
 
 
474
                private void EmitPseudoOpCode(CodeType type, object data)
 
475
                {
 
476
                        code.Add(new OpCodeWrapper(type, data));
 
477
                }
 
478
 
 
479
                private void EmitOpCode(OpCode opcode, object arg)
 
480
                {
 
481
                        code.Add(new OpCodeWrapper(opcode, arg));
 
482
                }
 
483
 
 
484
                private void RealEmitPseudoOpCode(int ilOffset, CodeType type, object data)
 
485
                {
 
486
                        switch (type)
 
487
                        {
 
488
                                case CodeType.Unreachable:
 
489
                                        break;
 
490
                                case CodeType.BeginScope:
 
491
                                        ilgen_real.BeginScope();
 
492
                                        break;
 
493
                                case CodeType.EndScope:
 
494
                                        ilgen_real.EndScope();
 
495
                                        break;
 
496
                                case CodeType.DeclareLocal:
 
497
                                        ((CodeEmitterLocal)data).Declare(ilgen_real);
 
498
                                        break;
 
499
                                case CodeType.ReleaseTempLocal:
 
500
                                        break;
 
501
                                case CodeType.SequencePoint:
 
502
                                        ilgen_real.MarkSequencePoint(symbols, (int)data, 0, (int)data + 1, 0);
 
503
                                        // we emit a nop to make sure we always have an instruction associated with the sequence point
 
504
                                        ilgen_real.Emit(OpCodes.Nop);
 
505
                                        break;
 
506
                                case CodeType.Label:
 
507
                                        ilgen_real.MarkLabel(((CodeEmitterLabel)data).Label);
 
508
                                        break;
 
509
                                case CodeType.BeginExceptionBlock:
 
510
                                        ilgen_real.BeginExceptionBlock();
 
511
                                        break;
 
512
                                case CodeType.BeginCatchBlock:
 
513
                                        ilgen_real.BeginCatchBlock((Type)data);
 
514
                                        break;
 
515
                                case CodeType.BeginFaultBlock:
 
516
                                        ilgen_real.BeginFaultBlock();
 
517
                                        break;
 
518
                                case CodeType.BeginFinallyBlock:
 
519
                                        ilgen_real.BeginFinallyBlock();
 
520
                                        break;
 
521
                                case CodeType.EndExceptionBlock:
 
522
                                        ilgen_real.EndExceptionBlock();
 
523
#if !STATIC_COMPILER
 
524
                                        // HACK to keep the verifier happy we need this bogus jump
 
525
                                        // (because of the bogus Leave that Ref.Emit ends the try block with)
 
526
                                        ilgen_real.Emit(OpCodes.Br_S, (sbyte)-2);
 
527
#endif
 
528
                                        break;
 
529
                                case CodeType.MemoryBarrier:
 
530
                                        if (memoryBarrier == null)
 
531
                                        {
 
532
                                                memoryBarrier = JVM.Import(typeof(System.Threading.Thread)).GetMethod("MemoryBarrier", Type.EmptyTypes);
 
533
                                        }
 
534
                                        ilgen_real.Emit(OpCodes.Call, memoryBarrier);
 
535
                                        break;
 
536
                                case CodeType.MonitorEnter:
 
537
                                        ilgen_real.Emit(OpCodes.Call, monitorEnter);
 
538
                                        break;
 
539
                                case CodeType.MonitorExit:
 
540
                                        ilgen_real.Emit(OpCodes.Call, monitorExit);
 
541
                                        break;
 
542
                                case CodeType.TailCallPrevention:
 
543
                                        ilgen_real.Emit(OpCodes.Ldnull);
 
544
                                        ilgen_real.Emit(OpCodes.Pop);
 
545
                                        break;
 
546
                                case CodeType.ClearStack:
 
547
                                        ilgen_real.Emit(OpCodes.Leave_S, (byte)0);
 
548
                                        break;
 
549
                                default:
 
550
                                        throw new InvalidOperationException();
 
551
                        }
 
552
                }
 
553
 
 
554
                private void RealEmitOpCode(OpCode opcode, object arg)
 
555
                {
 
556
                        if (arg == null)
 
557
                        {
 
558
                                ilgen_real.Emit(opcode);
 
559
                        }
 
560
                        else if (arg is int)
 
561
                        {
 
562
                                ilgen_real.Emit(opcode, (int)arg);
 
563
                        }
 
564
                        else if (arg is long)
 
565
                        {
 
566
                                ilgen_real.Emit(opcode, (long)arg);
 
567
                        }
 
568
                        else if (arg is MethodInfo)
 
569
                        {
 
570
                                ilgen_real.Emit(opcode, (MethodInfo)arg);
 
571
                        }
 
572
                        else if (arg is ConstructorInfo)
 
573
                        {
 
574
                                ilgen_real.Emit(opcode, (ConstructorInfo)arg);
 
575
                        }
 
576
                        else if (arg is FieldInfo)
 
577
                        {
 
578
                                ilgen_real.Emit(opcode, (FieldInfo)arg);
 
579
                        }
 
580
                        else if (arg is sbyte)
 
581
                        {
 
582
                                ilgen_real.Emit(opcode, (sbyte)arg);
 
583
                        }
 
584
                        else if (arg is byte)
 
585
                        {
 
586
                                ilgen_real.Emit(opcode, (byte)arg);
 
587
                        }
 
588
                        else if (arg is short)
 
589
                        {
 
590
                                ilgen_real.Emit(opcode, (short)arg);
 
591
                        }
 
592
                        else if (arg is float)
 
593
                        {
 
594
                                ilgen_real.Emit(opcode, (float)arg);
 
595
                        }
 
596
                        else if (arg is double)
 
597
                        {
 
598
                                ilgen_real.Emit(opcode, (double)arg);
 
599
                        }
 
600
                        else if (arg is string)
 
601
                        {
 
602
                                ilgen_real.Emit(opcode, (string)arg);
 
603
                        }
 
604
                        else if (arg is Type)
 
605
                        {
 
606
                                ilgen_real.Emit(opcode, (Type)arg);
 
607
                        }
 
608
                        else if (arg is CodeEmitterLocal)
 
609
                        {
 
610
                                CodeEmitterLocal local = (CodeEmitterLocal)arg;
 
611
                                local.Emit(ilgen_real, opcode);
 
612
                        }
 
613
                        else if (arg is CodeEmitterLabel)
 
614
                        {
 
615
                                CodeEmitterLabel label = (CodeEmitterLabel)arg;
 
616
                                ilgen_real.Emit(opcode, label.Label);
 
617
                        }
 
618
                        else if (arg is CodeEmitterLabel[])
 
619
                        {
 
620
                                CodeEmitterLabel[] labels = (CodeEmitterLabel[])arg;
 
621
                                Label[] real = new Label[labels.Length];
 
622
                                for (int i = 0; i < labels.Length; i++)
 
623
                                {
 
624
                                        real[i] = labels[i].Label;
 
625
                                }
 
626
                                ilgen_real.Emit(opcode, real);
 
627
                        }
 
628
                        else if (arg is CalliWrapper)
 
629
                        {
 
630
                                CalliWrapper args = (CalliWrapper)arg;
 
631
                                ilgen_real.EmitCalli(opcode, args.unmanagedCallConv, args.returnType, args.parameterTypes);
 
632
                        }
 
633
                        else
 
634
                        {
 
635
                                throw new InvalidOperationException();
 
636
                        }
 
637
                }
 
638
 
 
639
                private void RemoveJumpNext()
 
640
                {
 
641
                        for (int i = 1; i < code.Count; i++)
 
642
                        {
 
643
                                if (code[i].pseudo == CodeType.Label)
 
644
                                {
 
645
                                        if (code[i - 1].opcode == OpCodes.Br
 
646
                                                && code[i - 1].MatchLabel(code[i]))
 
647
                                        {
 
648
                                                code.RemoveAt(i - 1);
 
649
                                                i--;
 
650
                                        }
 
651
                                        else if (i >= 2
 
652
                                                && code[i - 1].pseudo == CodeType.LineNumber
 
653
                                                && code[i - 2].opcode == OpCodes.Br
 
654
                                                && code[i - 2].MatchLabel(code[i]))
 
655
                                        {
 
656
                                                code.RemoveAt(i - 2);
 
657
                                                i--;
 
658
                                        }
 
659
                                }
 
660
                        }
 
661
                }
 
662
 
 
663
                private void AnnihilateStoreReleaseTempLocals()
 
664
                {
 
665
                        for (int i = 1; i < code.Count; i++)
 
666
                        {
 
667
                                if (code[i].opcode == OpCodes.Stloc)
 
668
                                {
 
669
                                        if (code[i + 1].pseudo == CodeType.ReleaseTempLocal
 
670
                                                && code[i].Local == code[i + 1].Local)
 
671
                                        {
 
672
                                                code[i] = new OpCodeWrapper(OpCodes.Pop, null);
 
673
                                        }
 
674
                                        else if (code[i + 1].opcode == OpCodes.Ldloc
 
675
                                                && code[i + 1].Local == code[i].Local
 
676
                                                && code[i + 2].pseudo == CodeType.ReleaseTempLocal
 
677
                                                && code[i + 2].Local == code[i].Local)
 
678
                                        {
 
679
                                                code.RemoveRange(i, 2);
 
680
                                        }
 
681
                                }
 
682
                        }
 
683
                }
 
684
 
 
685
                private void AnnihilatePops()
 
686
                {
 
687
                        for (int i = 1; i < code.Count; i++)
 
688
                        {
 
689
                                if (code[i].opcode == OpCodes.Pop)
 
690
                                {
 
691
                                        // search backwards for a candidate push to annihilate
 
692
                                        int stack = 0;
 
693
                                        for (int j = i - 1; j >= 0; j--)
 
694
                                        {
 
695
                                                if (IsSideEffectFreePush(j))
 
696
                                                {
 
697
                                                        if (stack == 0)
 
698
                                                        {
 
699
                                                                code.RemoveAt(i);
 
700
                                                                code.RemoveAt(j);
 
701
                                                                i -= 2;
 
702
                                                                break;
 
703
                                                        }
 
704
                                                        stack++;
 
705
                                                }
 
706
                                                else if (code[j].opcode == OpCodes.Stloc)
 
707
                                                {
 
708
                                                        stack--;
 
709
                                                }
 
710
                                                else if (code[j].opcode == OpCodes.Shl
 
711
                                                        || code[j].opcode == OpCodes.And
 
712
                                                        || code[j].opcode == OpCodes.Add
 
713
                                                        || code[j].opcode == OpCodes.Sub)
 
714
                                                {
 
715
                                                        if (stack == 0)
 
716
                                                        {
 
717
                                                                break;
 
718
                                                        }
 
719
                                                        stack--;
 
720
                                                }
 
721
                                                else if (code[j].opcode == OpCodes.Conv_Ovf_I4
 
722
                                                        || code[j].opcode == OpCodes.Conv_I8
 
723
                                                        || code[j].opcode == OpCodes.Ldlen)
 
724
                                                {
 
725
                                                        if (stack == 0)
 
726
                                                        {
 
727
                                                                break;
 
728
                                                        }
 
729
                                                        // no stack effect
 
730
                                                }
 
731
                                                else
 
732
                                                {
 
733
                                                        break;
 
734
                                                }
 
735
                                        }
 
736
                                }
 
737
                        }
 
738
                }
 
739
 
 
740
                private bool IsSideEffectFreePush(int index)
 
741
                {
 
742
                        if (code[index].opcode == OpCodes.Ldstr)
 
743
                        {
 
744
                                return true;
 
745
                        }
 
746
                        else if (code[index].opcode == OpCodes.Ldnull)
 
747
                        {
 
748
                                return true;
 
749
                        }
 
750
                        else if (code[index].opcode == OpCodes.Ldsfld)
 
751
                        {
 
752
                                FieldInfo field = code[index].FieldInfo;
 
753
                                if (field != null)
 
754
                                {
 
755
                                        // Here we are considering BeforeFieldInit to mean that we really don't care about
 
756
                                        // when the type is initialized (which is what we mean in the rest of the IKVM code as well)
 
757
                                        // but it is good to point it out here because strictly speaking we're violating the
 
758
                                        // BeforeFieldInit contract here by considering dummy loads not to be field accesses.
 
759
                                        if ((field.DeclaringType.Attributes & TypeAttributes.BeforeFieldInit) != 0)
 
760
                                        {
 
761
                                                return true;
 
762
                                        }
 
763
                                        // If we're accessing a field in the current type, it can't trigger the static initializer
 
764
                                        // (unless beforefieldinit is set, but see above for that scenario)
 
765
                                        if (field.DeclaringType == declaringType)
 
766
                                        {
 
767
                                                return true;
 
768
                                        }
 
769
                                }
 
770
                                return false;
 
771
                        }
 
772
                        else if (code[index].opcode == OpCodes.Ldc_I4)
 
773
                        {
 
774
                                return true;
 
775
                        }
 
776
                        else if (code[index].opcode == OpCodes.Ldc_I8)
 
777
                        {
 
778
                                return true;
 
779
                        }
 
780
                        else if (code[index].opcode == OpCodes.Ldc_R4)
 
781
                        {
 
782
                                return true;
 
783
                        }
 
784
                        else if (code[index].opcode == OpCodes.Ldc_R8)
 
785
                        {
 
786
                                return true;
 
787
                        }
 
788
                        else if (code[index].opcode == OpCodes.Ldloc)
 
789
                        {
 
790
                                return true;
 
791
                        }
 
792
                        else if (code[index].opcode == OpCodes.Ldarg)
 
793
                        {
 
794
                                return true;
 
795
                        }
 
796
                        else if (code[index].opcode == OpCodes.Ldarg_S)
 
797
                        {
 
798
                                return true;
 
799
                        }
 
800
                        else if (code[index].opcode == OpCodes.Ldarg_0)
 
801
                        {
 
802
                                return true;
 
803
                        }
 
804
                        else if (code[index].opcode == OpCodes.Ldarg_1)
 
805
                        {
 
806
                                return true;
 
807
                        }
 
808
                        else if (code[index].opcode == OpCodes.Ldarg_2)
 
809
                        {
 
810
                                return true;
 
811
                        }
 
812
                        else if (code[index].opcode == OpCodes.Ldarg_3)
 
813
                        {
 
814
                                return true;
 
815
                        }
 
816
                        else
 
817
                        {
 
818
                                return false;
 
819
                        }
 
820
                }
 
821
 
 
822
                private void OptimizeBranchSizes()
 
823
                {
 
824
                        int offset = 0;
 
825
                        for (int i = 0; i < code.Count; i++)
 
826
                        {
 
827
                                if (code[i].pseudo == CodeType.Label)
 
828
                                {
 
829
                                        code[i].Label.Temp = offset;
 
830
                                }
 
831
                                offset += code[i].Size;
 
832
                        }
 
833
                        offset = 0;
 
834
                        for (int i = 0; i < code.Count; i++)
 
835
                        {
 
836
                                int prevOffset = offset;
 
837
                                offset += code[i].Size;
 
838
                                if (code[i].HasLabel && code[i].opcode.OperandType == OperandType.InlineBrTarget)
 
839
                                {
 
840
                                        CodeEmitterLabel label = code[i].Label;
 
841
                                        int diff = label.Temp - (prevOffset + code[i].opcode.Size + 1);
 
842
                                        if (-128 <= diff && diff <= 127)
 
843
                                        {
 
844
                                                OpCode opcode = code[i].opcode;
 
845
                                                if (opcode == OpCodes.Brtrue)
 
846
                                                {
 
847
                                                        opcode = OpCodes.Brtrue_S;
 
848
                                                }
 
849
                                                else if (opcode == OpCodes.Brfalse)
 
850
                                                {
 
851
                                                        opcode = OpCodes.Brfalse_S;
 
852
                                                }
 
853
                                                else if (opcode == OpCodes.Br)
 
854
                                                {
 
855
                                                        opcode = OpCodes.Br_S;
 
856
                                                }
 
857
                                                else if (opcode == OpCodes.Beq)
 
858
                                                {
 
859
                                                        opcode = OpCodes.Beq_S;
 
860
                                                }
 
861
                                                else if (opcode == OpCodes.Bne_Un)
 
862
                                                {
 
863
                                                        opcode = OpCodes.Bne_Un_S;
 
864
                                                }
 
865
                                                else if (opcode == OpCodes.Ble)
 
866
                                                {
 
867
                                                        opcode = OpCodes.Ble_S;
 
868
                                                }
 
869
                                                else if (opcode == OpCodes.Ble_Un)
 
870
                                                {
 
871
                                                        opcode = OpCodes.Ble_Un_S;
 
872
                                                }
 
873
                                                else if (opcode == OpCodes.Blt)
 
874
                                                {
 
875
                                                        opcode = OpCodes.Blt_S;
 
876
                                                }
 
877
                                                else if (opcode == OpCodes.Blt_Un)
 
878
                                                {
 
879
                                                        opcode = OpCodes.Blt_Un_S;
 
880
                                                }
 
881
                                                else if (opcode == OpCodes.Bge)
 
882
                                                {
 
883
                                                        opcode = OpCodes.Bge_S;
 
884
                                                }
 
885
                                                else if (opcode == OpCodes.Bge_Un)
 
886
                                                {
 
887
                                                        opcode = OpCodes.Bge_Un_S;
 
888
                                                }
 
889
                                                else if (opcode == OpCodes.Bgt)
 
890
                                                {
 
891
                                                        opcode = OpCodes.Bgt_S;
 
892
                                                }
 
893
                                                else if (opcode == OpCodes.Bgt_Un)
 
894
                                                {
 
895
                                                        opcode = OpCodes.Bgt_Un_S;
 
896
                                                }
 
897
                                                else if (opcode == OpCodes.Leave)
 
898
                                                {
 
899
                                                        opcode = OpCodes.Leave_S;
 
900
                                                }
 
901
                                                code[i] = new OpCodeWrapper(opcode, label);
 
902
                                        }
 
903
                                }
 
904
                        }
 
905
                }
 
906
 
 
907
                private void OptimizePatterns()
 
908
                {
 
909
                        SetLabelRefCounts();
 
910
                        for (int i = 1; i < code.Count; i++)
 
911
                        {
 
912
                                if (code[i].opcode == OpCodes.Isinst
 
913
                                        && code[i + 1].opcode == OpCodes.Ldnull
 
914
                                        && code[i + 2].opcode == OpCodes.Cgt_Un
 
915
                                        && (code[i + 3].opcode == OpCodes.Brfalse || code[i + 3].opcode == OpCodes.Brtrue))
 
916
                                {
 
917
                                        code.RemoveRange(i + 1, 2);
 
918
                                }
 
919
                                else if (code[i].opcode == OpCodes.Ldelem_I1
 
920
                                        && code[i + 1].opcode == OpCodes.Ldc_I4 && code[i + 1].ValueInt32 == 255
 
921
                                        && code[i + 2].opcode == OpCodes.And)
 
922
                                {
 
923
                                        code[i] = new OpCodeWrapper(OpCodes.Ldelem_U1, null);
 
924
                                        code.RemoveRange(i + 1, 2);
 
925
                                }
 
926
                                else if (code[i].opcode == OpCodes.Ldelem_I1
 
927
                                        && code[i + 1].opcode == OpCodes.Conv_I8
 
928
                                        && code[i + 2].opcode == OpCodes.Ldc_I8 && code[i + 2].ValueInt64 == 255
 
929
                                        && code[i + 3].opcode == OpCodes.And)
 
930
                                {
 
931
                                        code[i] = new OpCodeWrapper(OpCodes.Ldelem_U1, null);
 
932
                                        code.RemoveRange(i + 2, 2);
 
933
                                }
 
934
                                else if (code[i].opcode == OpCodes.Ldc_I4
 
935
                                        && code[i + 1].opcode == OpCodes.Ldc_I4
 
936
                                        && code[i + 2].opcode == OpCodes.And)
 
937
                                {
 
938
                                        code[i] = new OpCodeWrapper(OpCodes.Ldc_I4, code[i].ValueInt32 & code[i + 1].ValueInt32);
 
939
                                        code.RemoveRange(i + 1, 2);
 
940
                                }
 
941
                                else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, Types.Double)             // dcmpl
 
942
                                        || MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, Types.Single))          // fcmpl
 
943
                                {
 
944
                                        PatchCompare(i, OpCodes.Ble_Un, OpCodes.Blt_Un, OpCodes.Bge, OpCodes.Bgt);
 
945
                                }
 
946
                                else if (MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, Types.Double)             // dcmpg
 
947
                                        || MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, Types.Single))          // fcmpg
 
948
                                {
 
949
                                        PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge_Un, OpCodes.Bgt_Un);
 
950
                                }
 
951
                                else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt, Types.Int64))                // lcmp
 
952
                                {
 
953
                                        PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge, OpCodes.Bgt);
 
954
                                }
 
955
                                else if (i < code.Count - 10
 
956
                                        && code[i].opcode == OpCodes.Ldc_I4
 
957
                                        && code[i + 1].opcode == OpCodes.Dup
 
958
                                        && code[i + 2].opcode == OpCodes.Ldc_I4_M1
 
959
                                        && code[i + 3].opcode == OpCodes.Bne_Un
 
960
                                        && code[i + 4].opcode == OpCodes.Pop
 
961
                                        && code[i + 5].opcode == OpCodes.Neg
 
962
                                        && code[i + 6].opcode == OpCodes.Br
 
963
                                        && code[i + 7].pseudo == CodeType.Label && code[i + 7].MatchLabel(code[i + 3]) && code[i + 7].Label.Temp == 1
 
964
                                        && code[i + 8].opcode == OpCodes.Div
 
965
                                        && code[i + 9].pseudo == CodeType.Label && code[i + 9].Label == code[i + 6].Label && code[i + 9].Label.Temp == 1)
 
966
                                {
 
967
                                        int divisor = code[i].ValueInt32;
 
968
                                        if (divisor == -1)
 
969
                                        {
 
970
                                                code[i] = code[i + 5];
 
971
                                                code.RemoveRange(i + 1, 9);
 
972
                                        }
 
973
                                        else
 
974
                                        {
 
975
                                                code[i + 1] = code[i + 8];
 
976
                                                code.RemoveRange(i + 2, 8);
 
977
                                        }
 
978
                                }
 
979
                                else if (i < code.Count - 11
 
980
                                        && code[i].opcode == OpCodes.Ldc_I8
 
981
                                        && code[i + 1].opcode == OpCodes.Dup
 
982
                                        && code[i + 2].opcode == OpCodes.Ldc_I4_M1
 
983
                                        && code[i + 3].opcode == OpCodes.Conv_I8
 
984
                                        && code[i + 4].opcode == OpCodes.Bne_Un
 
985
                                        && code[i + 5].opcode == OpCodes.Pop
 
986
                                        && code[i + 6].opcode == OpCodes.Neg
 
987
                                        && code[i + 7].opcode == OpCodes.Br
 
988
                                        && code[i + 8].pseudo == CodeType.Label && code[i + 8].MatchLabel(code[i + 4]) && code[i + 8].Label.Temp == 1
 
989
                                        && code[i + 9].opcode == OpCodes.Div
 
990
                                        && code[i + 10].pseudo == CodeType.Label && code[i + 10].MatchLabel(code[i + 7]) && code[i + 10].Label.Temp == 1)
 
991
                                {
 
992
                                        long divisor = code[i].ValueInt64;
 
993
                                        if (divisor == -1)
 
994
                                        {
 
995
                                                code[i] = code[i + 6];
 
996
                                                code.RemoveRange(i + 1, 10);
 
997
                                        }
 
998
                                        else
 
999
                                        {
 
1000
                                                code[i + 1] = code[i + 9];
 
1001
                                                code.RemoveRange(i + 2, 9);
 
1002
                                        }
 
1003
                                }
 
1004
                                else if (code[i].opcode == OpCodes.Box
 
1005
                                        && code[i + 1].opcode == OpCodes.Unbox && code[i + 1].Type == code[i].Type)
 
1006
                                {
 
1007
                                        CodeEmitterLocal local = new CodeEmitterLocal(code[i].Type);
 
1008
                                        code[i] = new OpCodeWrapper(OpCodes.Stloc, local);
 
1009
                                        code[i + 1] = new OpCodeWrapper(OpCodes.Ldloca, local);
 
1010
                                }
 
1011
                                else if (i < code.Count - 13
 
1012
                                        && code[i + 0].opcode == OpCodes.Box
 
1013
                                        && code[i + 1].opcode == OpCodes.Dup
 
1014
                                        && code[i + 2].opcode == OpCodes.Brtrue
 
1015
                                        && code[i + 3].opcode == OpCodes.Pop
 
1016
                                        && code[i + 4].opcode == OpCodes.Ldloca && code[i + 4].Local.LocalType == code[i + 0].Type
 
1017
                                        && code[i + 5].opcode == OpCodes.Initobj && code[i + 5].Type == code[i + 0].Type
 
1018
                                        && code[i + 6].opcode == OpCodes.Ldloc && code[i + 6].Local == code[i + 4].Local
 
1019
                                        && code[i + 7].pseudo == CodeType.ReleaseTempLocal && code[i + 7].Local == code[i + 6].Local
 
1020
                                        && code[i + 8].opcode == OpCodes.Br
 
1021
                                        && code[i + 9].pseudo == CodeType.Label && code[i + 9].MatchLabel(code[i + 2]) && code[i + 9].Label.Temp == 1
 
1022
                                        && code[i + 10].opcode == OpCodes.Unbox && code[i + 10].Type == code[i + 0].Type
 
1023
                                        && code[i + 11].opcode == OpCodes.Ldobj && code[i + 11].Type == code[i + 0].Type
 
1024
                                        && code[i + 12].pseudo == CodeType.Label && code[i + 12].MatchLabel(code[i + 8]) && code[i + 12].Label.Temp == 1)
 
1025
                                {
 
1026
                                        code.RemoveRange(i, 13);
 
1027
                                }
 
1028
 
 
1029
                                // NOTE intentionally not an else, because we want to optimize the code generated by the earlier compare optimization
 
1030
                                if (i < code.Count - 6
 
1031
                                        && code[i].opcode.FlowControl == FlowControl.Cond_Branch
 
1032
                                        && code[i + 1].opcode == OpCodes.Ldc_I4 && code[i + 1].ValueInt32 == 1
 
1033
                                        && code[i + 2].opcode == OpCodes.Br
 
1034
                                        && code[i + 3].pseudo == CodeType.Label && code[i + 3].MatchLabel(code[i]) && code[i + 3].Label.Temp == 1
 
1035
                                        && code[i + 4].opcode == OpCodes.Ldc_I4 && code[i + 4].ValueInt32 == 0
 
1036
                                        && code[i + 5].pseudo == CodeType.Label && code[i + 5].MatchLabel(code[i + 2]) && code[i + 5].Label.Temp == 1)
 
1037
                                {
 
1038
                                        if (code[i].opcode == OpCodes.Bne_Un)
 
1039
                                        {
 
1040
                                                code[i] = new OpCodeWrapper(OpCodes.Ceq, null);
 
1041
                                                code.RemoveRange(i + 1, 5);
 
1042
                                        }
 
1043
                                        else if (code[i].opcode == OpCodes.Beq)
 
1044
                                        {
 
1045
                                                code[i + 0] = new OpCodeWrapper(OpCodes.Ceq, null);
 
1046
                                                code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0);
 
1047
                                                code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null);
 
1048
                                                code.RemoveRange(i + 3, 3);
 
1049
                                        }
 
1050
                                        else if (code[i].opcode == OpCodes.Ble || code[i].opcode == OpCodes.Ble_Un)
 
1051
                                        {
 
1052
                                                code[i] = new OpCodeWrapper(OpCodes.Cgt, null);
 
1053
                                                code.RemoveRange(i + 1, 5);
 
1054
                                        }
 
1055
                                        else if (code[i].opcode == OpCodes.Blt)
 
1056
                                        {
 
1057
                                                code[i] = new OpCodeWrapper(OpCodes.Clt, null);
 
1058
                                                code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0);
 
1059
                                                code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null);
 
1060
                                                code.RemoveRange(i + 3, 3);
 
1061
                                        }
 
1062
                                        else if (code[i].opcode == OpCodes.Blt_Un)
 
1063
                                        {
 
1064
                                                code[i] = new OpCodeWrapper(OpCodes.Clt_Un, null);
 
1065
                                                code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0);
 
1066
                                                code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null);
 
1067
                                                code.RemoveRange(i + 3, 3);
 
1068
                                        }
 
1069
                                        else if (code[i].opcode == OpCodes.Bge || code[i].opcode == OpCodes.Bge_Un)
 
1070
                                        {
 
1071
                                                code[i] = new OpCodeWrapper(OpCodes.Clt, null);
 
1072
                                                code.RemoveRange(i + 1, 5);
 
1073
                                        }
 
1074
                                        else if (code[i].opcode == OpCodes.Bgt)
 
1075
                                        {
 
1076
                                                code[i] = new OpCodeWrapper(OpCodes.Cgt, null);
 
1077
                                                code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0);
 
1078
                                                code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null);
 
1079
                                                code.RemoveRange(i + 3, 3);
 
1080
                                        }
 
1081
                                        else if (code[i].opcode == OpCodes.Bgt_Un)
 
1082
                                        {
 
1083
                                                code[i] = new OpCodeWrapper(OpCodes.Cgt_Un, null);
 
1084
                                                code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0);
 
1085
                                                code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null);
 
1086
                                                code.RemoveRange(i + 3, 3);
 
1087
                                        }
 
1088
                                }
 
1089
                        }
 
1090
                }
 
1091
 
 
1092
                private bool MatchCompare(int index, OpCode cmp1, OpCode cmp2, Type type)
 
1093
                {
 
1094
                        return code[index].opcode == OpCodes.Stloc && code[index].Local.LocalType == type
 
1095
                                && code[index + 1].opcode == OpCodes.Stloc && code[index + 1].Local.LocalType == type
 
1096
                                && code[index + 2].opcode == OpCodes.Ldloc && code[index + 2].MatchLocal(code[index + 1])
 
1097
                                && code[index + 3].opcode == OpCodes.Ldloc && code[index + 3].MatchLocal(code[index])
 
1098
                                && code[index + 4].opcode == cmp1
 
1099
                                && code[index + 5].opcode == OpCodes.Ldloc && code[index + 5].MatchLocal(code[index + 1])
 
1100
                                && code[index + 6].opcode == OpCodes.Ldloc && code[index + 6].MatchLocal(code[index])
 
1101
                                && code[index + 7].opcode == cmp2
 
1102
                                && code[index + 8].opcode == OpCodes.Sub
 
1103
                                && code[index + 9].pseudo == CodeType.ReleaseTempLocal && code[index + 9].Local == code[index].Local
 
1104
                                && code[index + 10].pseudo == CodeType.ReleaseTempLocal && code[index + 10].Local == code[index + 1].Local
 
1105
                                && ((code[index + 11].opcode.FlowControl == FlowControl.Cond_Branch && code[index + 11].HasLabel) ||
 
1106
                                        (code[index + 11].opcode == OpCodes.Ldc_I4_0
 
1107
                                        && (code[index + 12].opcode.FlowControl == FlowControl.Cond_Branch && code[index + 12].HasLabel)));
 
1108
                }
 
1109
 
 
1110
                private void PatchCompare(int index, OpCode ble, OpCode blt, OpCode bge, OpCode bgt)
 
1111
                {
 
1112
                        if (code[index + 11].opcode == OpCodes.Brtrue)
 
1113
                        {
 
1114
                                code[index] = new OpCodeWrapper(OpCodes.Bne_Un, code[index + 11].Label);
 
1115
                                code.RemoveRange(index + 1, 11);
 
1116
                        }
 
1117
                        else if (code[index + 11].opcode == OpCodes.Brfalse)
 
1118
                        {
 
1119
                                code[index] = new OpCodeWrapper(OpCodes.Beq, code[index + 11].Label);
 
1120
                                code.RemoveRange(index + 1, 11);
 
1121
                        }
 
1122
                        else if (code[index + 11].opcode == OpCodes.Ldc_I4_0)
 
1123
                        {
 
1124
                                if (code[index + 12].opcode == OpCodes.Ble)
 
1125
                                {
 
1126
                                        code[index] = new OpCodeWrapper(ble, code[index + 12].Label);
 
1127
                                        code.RemoveRange(index + 1, 12);
 
1128
                                }
 
1129
                                else if (code[index + 12].opcode == OpCodes.Blt)
 
1130
                                {
 
1131
                                        code[index] = new OpCodeWrapper(blt, code[index + 12].Label);
 
1132
                                        code.RemoveRange(index + 1, 12);
 
1133
                                }
 
1134
                                else if (code[index + 12].opcode == OpCodes.Bge)
 
1135
                                {
 
1136
                                        code[index] = new OpCodeWrapper(bge, code[index + 12].Label);
 
1137
                                        code.RemoveRange(index + 1, 12);
 
1138
                                }
 
1139
                                else if (code[index + 12].opcode == OpCodes.Bgt)
 
1140
                                {
 
1141
                                        code[index] = new OpCodeWrapper(bgt, code[index + 12].Label);
 
1142
                                        code.RemoveRange(index + 1, 12);
 
1143
                                }
 
1144
                        }
 
1145
                }
 
1146
 
 
1147
                private void OptimizeEncodings()
 
1148
                {
 
1149
                        for (int i = 0; i < code.Count; i++)
 
1150
                        {
 
1151
                                if (code[i].opcode == OpCodes.Ldc_I4)
 
1152
                                {
 
1153
                                        code[i] = OptimizeLdcI4(code[i].ValueInt32);
 
1154
                                }
 
1155
                                else if (code[i].opcode == OpCodes.Ldc_I8)
 
1156
                                {
 
1157
                                        OptimizeLdcI8(i);
 
1158
                                }
 
1159
                        }
 
1160
                }
 
1161
 
 
1162
                private OpCodeWrapper OptimizeLdcI4(int value)
 
1163
                {
 
1164
                        switch (value)
 
1165
                        {
 
1166
                                case -1:
 
1167
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_M1, null);
 
1168
                                case 0:
 
1169
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_0, null);
 
1170
                                case 1:
 
1171
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_1, null);
 
1172
                                case 2:
 
1173
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_2, null);
 
1174
                                case 3:
 
1175
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_3, null);
 
1176
                                case 4:
 
1177
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_4, null);
 
1178
                                case 5:
 
1179
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_5, null);
 
1180
                                case 6:
 
1181
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_6, null);
 
1182
                                case 7:
 
1183
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_7, null);
 
1184
                                case 8:
 
1185
                                        return new OpCodeWrapper(OpCodes.Ldc_I4_8, null);
 
1186
                                default:
 
1187
                                        if (value >= -128 && value <= 127)
 
1188
                                        {
 
1189
                                                return new OpCodeWrapper(OpCodes.Ldc_I4_S, (sbyte)value);
 
1190
                                        }
 
1191
                                        else
 
1192
                                        {
 
1193
                                                return new OpCodeWrapper(OpCodes.Ldc_I4, value);
 
1194
                                        }
 
1195
                        }
 
1196
                }
 
1197
 
 
1198
                private void OptimizeLdcI8(int index)
 
1199
                {
 
1200
                        long value = code[index].ValueInt64;
 
1201
                        OpCode opc = OpCodes.Nop;
 
1202
                        switch (value)
 
1203
                        {
 
1204
                                case -1:
 
1205
                                        opc = OpCodes.Ldc_I4_M1;
 
1206
                                        break;
 
1207
                                case 0:
 
1208
                                        opc = OpCodes.Ldc_I4_0;
 
1209
                                        break;
 
1210
                                case 1:
 
1211
                                        opc = OpCodes.Ldc_I4_1;
 
1212
                                        break;
 
1213
                                case 2:
 
1214
                                        opc = OpCodes.Ldc_I4_2;
 
1215
                                        break;
 
1216
                                case 3:
 
1217
                                        opc = OpCodes.Ldc_I4_3;
 
1218
                                        break;
 
1219
                                case 4:
 
1220
                                        opc = OpCodes.Ldc_I4_4;
 
1221
                                        break;
 
1222
                                case 5:
 
1223
                                        opc = OpCodes.Ldc_I4_5;
 
1224
                                        break;
 
1225
                                case 6:
 
1226
                                        opc = OpCodes.Ldc_I4_6;
 
1227
                                        break;
 
1228
                                case 7:
 
1229
                                        opc = OpCodes.Ldc_I4_7;
 
1230
                                        break;
 
1231
                                case 8:
 
1232
                                        opc = OpCodes.Ldc_I4_8;
 
1233
                                        break;
 
1234
                                default:
 
1235
                                        if (value >= -2147483648L && value <= 4294967295L)
 
1236
                                        {
 
1237
                                                if (value >= -128 && value <= 127)
 
1238
                                                {
 
1239
                                                        code[index] = new OpCodeWrapper(OpCodes.Ldc_I4_S, (sbyte)value);
 
1240
                                                }
 
1241
                                                else
 
1242
                                                {
 
1243
                                                        code[index] = new OpCodeWrapper(OpCodes.Ldc_I4, (int)value);
 
1244
                                                }
 
1245
                                                if (value < 0)
 
1246
                                                {
 
1247
                                                        code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_I8, null));
 
1248
                                                }
 
1249
                                                else
 
1250
                                                {
 
1251
                                                        code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_U8, null));
 
1252
                                                }
 
1253
                                        }
 
1254
                                        break;
 
1255
                        }
 
1256
                        if (opc != OpCodes.Nop)
 
1257
                        {
 
1258
                                code[index] = new OpCodeWrapper(opc, null);
 
1259
                                code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_I8, null));
 
1260
                        }
 
1261
                }
 
1262
 
 
1263
                private void ChaseBranches()
 
1264
                {
 
1265
                        /*
 
1266
                         * Here we do a couple of different optimizations to unconditional branches:
 
1267
                         *  - a branch to a ret or endfinally will be replaced
 
1268
                         *    by the ret or endfinally instruction (because that is always at least as efficient)
 
1269
                         *  - a branch to a branch will remove the indirection
 
1270
                         *  - a leave to a branch or leave will remove the indirection
 
1271
                         */
 
1272
                        SetLabelIndexes();
 
1273
                        for (int i = 0; i < code.Count; i++)
 
1274
                        {
 
1275
                                if (code[i].opcode == OpCodes.Br)
 
1276
                                {
 
1277
                                        int target = code[i].Label.Temp + 1;
 
1278
                                        if (code[target].pseudo == CodeType.LineNumber)
 
1279
                                        {
 
1280
                                                // line number info on endfinally or ret is probably useless anyway
 
1281
                                                target++;
 
1282
                                        }
 
1283
                                        if (code[target].opcode == OpCodes.Endfinally || code[target].opcode == OpCodes.Ret)
 
1284
                                        {
 
1285
                                                code[i] = code[target];
 
1286
                                        }
 
1287
                                        else
 
1288
                                        {
 
1289
                                                CodeEmitterLabel label = null;
 
1290
                                                while (code[target].opcode == OpCodes.Br && target != i)
 
1291
                                                {
 
1292
                                                        label = code[target].Label;
 
1293
                                                        target = code[target].Label.Temp + 1;
 
1294
                                                }
 
1295
                                                if (label != null)
 
1296
                                                {
 
1297
                                                        code[i] = new OpCodeWrapper(OpCodes.Br, label);
 
1298
                                                }
 
1299
                                        }
 
1300
                                }
 
1301
                                else if (code[i].opcode == OpCodes.Leave)
 
1302
                                {
 
1303
                                        int target = code[i].Label.Temp + 1;
 
1304
                                        CodeEmitterLabel label = null;
 
1305
                                        while ((code[target].opcode == OpCodes.Br || code[target].opcode == OpCodes.Leave) && target != i)
 
1306
                                        {
 
1307
                                                label = code[target].Label;
 
1308
                                                target = code[target].Label.Temp + 1;
 
1309
                                        }
 
1310
                                        if (label != null)
 
1311
                                        {
 
1312
                                                code[i] = new OpCodeWrapper(OpCodes.Leave, label);
 
1313
                                        }
 
1314
                                }
 
1315
                        }
 
1316
                }
 
1317
 
 
1318
                private void RemoveSingletonBranches()
 
1319
                {
 
1320
                        /*
 
1321
                         * Here we try to remove unconditional branches that jump to a label with ref count of one
 
1322
                         * and where the code is not otherwise used.
 
1323
                         */
 
1324
                        SetLabelRefCounts();
 
1325
                        // now increment label refcounts for labels that are also reachable via the preceding instruction
 
1326
                        bool reachable = true;
 
1327
                        for (int i = 0; i < code.Count; i++)
 
1328
                        {
 
1329
                                if (reachable)
 
1330
                                {
 
1331
                                        switch (code[i].pseudo)
 
1332
                                        {
 
1333
                                                case CodeType.Label:
 
1334
                                                        code[i].Label.Temp++;
 
1335
                                                        break;
 
1336
                                                case CodeType.BeginCatchBlock:
 
1337
                                                case CodeType.BeginFaultBlock:
 
1338
                                                case CodeType.BeginFinallyBlock:
 
1339
                                                case CodeType.EndExceptionBlock:
 
1340
                                                        throw new InvalidOperationException();
 
1341
                                                case CodeType.OpCode:
 
1342
                                                        switch (code[i].opcode.FlowControl)
 
1343
                                                        {
 
1344
                                                                case FlowControl.Branch:
 
1345
                                                                case FlowControl.Return:
 
1346
                                                                case FlowControl.Throw:
 
1347
                                                                        reachable = false;
 
1348
                                                                        break;
 
1349
                                                        }
 
1350
                                                        break;
 
1351
                                        }
 
1352
                                }
 
1353
                                else
 
1354
                                {
 
1355
                                        switch (code[i].pseudo)
 
1356
                                        {
 
1357
                                                case CodeType.Label:
 
1358
                                                        reachable = code[i].Label.Temp > 0;
 
1359
                                                        break;
 
1360
                                                case CodeType.BeginCatchBlock:
 
1361
                                                case CodeType.BeginFaultBlock:
 
1362
                                                case CodeType.BeginFinallyBlock:
 
1363
                                                        reachable = true;
 
1364
                                                        break;
 
1365
                                        }
 
1366
                                }
 
1367
                        }
 
1368
 
 
1369
                        // now remove the unconditional branches to labels with a refcount of one
 
1370
                        for (int i = 0; i < code.Count; i++)
 
1371
                        {
 
1372
                                if (code[i].opcode == OpCodes.Br && code[i].Label.Temp == 1)
 
1373
                                {
 
1374
                                        int target = FindLabel(code[i].Label) + 1;
 
1375
                                        for (int j = target; j < code.Count; j++)
 
1376
                                        {
 
1377
                                                switch (code[j].pseudo)
 
1378
                                                {
 
1379
                                                        case CodeType.OpCode:
 
1380
                                                                if (code[j].HasLocal && FindLocal(code[j].Local) > i)
 
1381
                                                                {
 
1382
                                                                        // we cannot local variable usage before the declaration
 
1383
                                                                        goto breakOuter;
 
1384
                                                                }
 
1385
                                                                switch (code[j].opcode.FlowControl)
 
1386
                                                                {
 
1387
                                                                        case FlowControl.Branch:
 
1388
                                                                        case FlowControl.Return:
 
1389
                                                                        case FlowControl.Throw:
 
1390
                                                                                // we've found a viable sequence of opcode to move to the branch location
 
1391
                                                                                List<OpCodeWrapper> range = code.GetRange(target, j - target + 1);
 
1392
                                                                                if (target < i)
 
1393
                                                                                {
 
1394
                                                                                        code.RemoveAt(i);
 
1395
                                                                                        code.InsertRange(i, range);
 
1396
                                                                                        code.RemoveRange(target - 1, range.Count + 1);
 
1397
                                                                                        i -= range.Count + 1;
 
1398
                                                                                }
 
1399
                                                                                else
 
1400
                                                                                {
 
1401
                                                                                        code.RemoveRange(target - 1, range.Count + 1);
 
1402
                                                                                        code.RemoveAt(i);
 
1403
                                                                                        code.InsertRange(i, range);
 
1404
                                                                                }
 
1405
                                                                                goto breakOuter;
 
1406
                                                                }
 
1407
                                                                break;
 
1408
                                                        case CodeType.Label:
 
1409
                                                        case CodeType.BeginExceptionBlock:
 
1410
                                                        case CodeType.DeclareLocal:
 
1411
                                                                goto breakOuter;
 
1412
                                                }
 
1413
                                        }
 
1414
                                breakOuter: ;
 
1415
                                }
 
1416
                        }
 
1417
                }
 
1418
 
 
1419
                private int FindLabel(CodeEmitterLabel label)
 
1420
                {
 
1421
                        for (int i = 0; i < code.Count; i++)
 
1422
                        {
 
1423
                                if (code[i].pseudo == CodeType.Label && code[i].Label == label)
 
1424
                                {
 
1425
                                        return i;
 
1426
                                }
 
1427
                        }
 
1428
                        throw new InvalidOperationException();
 
1429
                }
 
1430
 
 
1431
                private int FindLocal(CodeEmitterLocal local)
 
1432
                {
 
1433
                        for (int i = 0; i < code.Count; i++)
 
1434
                        {
 
1435
                                if (code[i].pseudo == CodeType.DeclareLocal && code[i].Local == local)
 
1436
                                {
 
1437
                                        return i;
 
1438
                                }
 
1439
                        }
 
1440
                        // if the local variable isn't declared, it is a temporary that is allocated on demand
 
1441
                        // (so we can move their usage freely)
 
1442
                        return 0;
 
1443
                }
 
1444
 
 
1445
                private void SortPseudoOpCodes()
 
1446
                {
 
1447
                        for (int i = 0; i < code.Count - 1; i++)
 
1448
                        {
 
1449
                                switch (code[i].pseudo)
 
1450
                                {
 
1451
                                        case CodeType.ReleaseTempLocal:
 
1452
                                                for (int j = i - 1; ; j--)
 
1453
                                                {
 
1454
                                                        if (j == -1)
 
1455
                                                        {
 
1456
                                                                code.RemoveAt(i);
 
1457
                                                                break;
 
1458
                                                        }
 
1459
                                                        if (code[j].HasLocal && code[j].Local == code[i].Local)
 
1460
                                                        {
 
1461
                                                                MoveInstruction(i, j + 1);
 
1462
                                                                break;
 
1463
                                                        }
 
1464
                                                }
 
1465
                                                break;
 
1466
                                }
 
1467
                        }
 
1468
                }
 
1469
 
 
1470
                private void MoveInstruction(int i, int j)
 
1471
                {
 
1472
                        if (i == j - 1 || i == j + 1)
 
1473
                        {
 
1474
                                OpCodeWrapper temp = code[i];
 
1475
                                code[i] = code[j];
 
1476
                                code[j] = temp;
 
1477
                        }
 
1478
                        else if (i < j)
 
1479
                        {
 
1480
                                code.Insert(j, code[i]);
 
1481
                                code.RemoveAt(i);
 
1482
                        }
 
1483
                        else if (i > j)
 
1484
                        {
 
1485
                                OpCodeWrapper temp = code[i];
 
1486
                                code.RemoveAt(i);
 
1487
                                code.Insert(j, temp);
 
1488
                        }
 
1489
                }
 
1490
 
 
1491
                private void ClearLabelTemp()
 
1492
                {
 
1493
                        for (int i = 0; i < code.Count; i++)
 
1494
                        {
 
1495
                                if (code[i].pseudo == CodeType.Label)
 
1496
                                {
 
1497
                                        code[i].Label.Temp = 0;
 
1498
                                }
 
1499
                        }
 
1500
                }
 
1501
 
 
1502
                private void SetLabelIndexes()
 
1503
                {
 
1504
                        for (int i = 0; i < code.Count; i++)
 
1505
                        {
 
1506
                                if (code[i].pseudo == CodeType.Label)
 
1507
                                {
 
1508
                                        code[i].Label.Temp = i;
 
1509
                                }
 
1510
                        }
 
1511
                }
 
1512
 
 
1513
                private void SetLabelRefCounts()
 
1514
                {
 
1515
                        ClearLabelTemp();
 
1516
                        for (int i = 0; i < code.Count; i++)
 
1517
                        {
 
1518
                                if (code[i].pseudo == CodeType.OpCode)
 
1519
                                {
 
1520
                                        if (code[i].HasLabel)
 
1521
                                        {
 
1522
                                                code[i].Label.Temp++;
 
1523
                                        }
 
1524
                                        else if (code[i].opcode == OpCodes.Switch)
 
1525
                                        {
 
1526
                                                foreach (CodeEmitterLabel label in code[i].Labels)
 
1527
                                                {
 
1528
                                                        label.Temp++;
 
1529
                                                }
 
1530
                                        }
 
1531
                                }
 
1532
                        }
 
1533
                }
 
1534
 
 
1535
                private void RemoveUnusedLabels()
 
1536
                {
 
1537
                        SetLabelRefCounts();
 
1538
                        for (int i = 0; i < code.Count; i++)
 
1539
                        {
 
1540
                                while (code[i].pseudo == CodeType.Label && code[i].Label.Temp == 0)
 
1541
                                {
 
1542
                                        code.RemoveAt(i);
 
1543
                                }
 
1544
                        }
 
1545
                }
 
1546
 
 
1547
                private void RemoveDeadCode()
 
1548
                {
 
1549
                        ClearLabelTemp();
 
1550
                        const int ReachableFlag = 1;
 
1551
                        const int ProcessedFlag = 2;
 
1552
                        bool reachable = true;
 
1553
                        bool done = false;
 
1554
                        while (!done)
 
1555
                        {
 
1556
                                done = true;
 
1557
                                for (int i = 0; i < code.Count; i++)
 
1558
                                {
 
1559
                                        if (reachable)
 
1560
                                        {
 
1561
                                                if (code[i].pseudo == CodeType.Label)
 
1562
                                                {
 
1563
                                                        if (code[i].Label.Temp == ProcessedFlag)
 
1564
                                                        {
 
1565
                                                                done = false;
 
1566
                                                        }
 
1567
                                                        code[i].Label.Temp |= ReachableFlag;
 
1568
                                                }
 
1569
                                                else if (code[i].pseudo == CodeType.OpCode)
 
1570
                                                {
 
1571
                                                        if (code[i].HasLabel)
 
1572
                                                        {
 
1573
                                                                if (code[i].Label.Temp == ProcessedFlag)
 
1574
                                                                {
 
1575
                                                                        done = false;
 
1576
                                                                }
 
1577
                                                                code[i].Label.Temp |= ReachableFlag;
 
1578
                                                        }
 
1579
                                                        else if (code[i].opcode == OpCodes.Switch)
 
1580
                                                        {
 
1581
                                                                foreach (CodeEmitterLabel label in code[i].Labels)
 
1582
                                                                {
 
1583
                                                                        if (label.Temp == ProcessedFlag)
 
1584
                                                                        {
 
1585
                                                                                done = false;
 
1586
                                                                        }
 
1587
                                                                        label.Temp |= ReachableFlag;
 
1588
                                                                }
 
1589
                                                        }
 
1590
                                                        switch (code[i].opcode.FlowControl)
 
1591
                                                        {
 
1592
                                                                case FlowControl.Cond_Branch:
 
1593
                                                                        if (!code[i].HasLabel && code[i].opcode != OpCodes.Switch)
 
1594
                                                                        {
 
1595
                                                                                throw new NotSupportedException();
 
1596
                                                                        }
 
1597
                                                                        break;
 
1598
                                                                case FlowControl.Branch:
 
1599
                                                                case FlowControl.Return:
 
1600
                                                                case FlowControl.Throw:
 
1601
                                                                        reachable = false;
 
1602
                                                                        break;
 
1603
                                                        }
 
1604
                                                }
 
1605
                                        }
 
1606
                                        else if (code[i].pseudo == CodeType.BeginCatchBlock)
 
1607
                                        {
 
1608
                                                reachable = true;
 
1609
                                        }
 
1610
                                        else if (code[i].pseudo == CodeType.BeginFaultBlock)
 
1611
                                        {
 
1612
                                                reachable = true;
 
1613
                                        }
 
1614
                                        else if (code[i].pseudo == CodeType.BeginFinallyBlock)
 
1615
                                        {
 
1616
                                                reachable = true;
 
1617
                                        }
 
1618
                                        else if (code[i].pseudo == CodeType.Label && (code[i].Label.Temp & ReachableFlag) != 0)
 
1619
                                        {
 
1620
                                                reachable = true;
 
1621
                                        }
 
1622
                                        if (code[i].pseudo == CodeType.Label)
 
1623
                                        {
 
1624
                                                code[i].Label.Temp |= ProcessedFlag;
 
1625
                                        }
 
1626
                                }
 
1627
                        }
 
1628
                        reachable = true;
 
1629
                        int firstUnreachable = -1;
 
1630
                        for (int i = 0; i < code.Count; i++)
 
1631
                        {
 
1632
                                if (reachable)
 
1633
                                {
 
1634
                                        if (code[i].pseudo == CodeType.OpCode)
 
1635
                                        {
 
1636
                                                switch (code[i].opcode.FlowControl)
 
1637
                                                {
 
1638
                                                        case FlowControl.Branch:
 
1639
                                                        case FlowControl.Return:
 
1640
                                                        case FlowControl.Throw:
 
1641
                                                                reachable = false;
 
1642
                                                                firstUnreachable = i + 1;
 
1643
                                                                break;
 
1644
                                                }
 
1645
                                        }
 
1646
                                }
 
1647
                                else
 
1648
                                {
 
1649
                                        switch (code[i].pseudo)
 
1650
                                        {
 
1651
                                                case CodeType.OpCode:
 
1652
                                                        break;
 
1653
                                                case CodeType.Label:
 
1654
                                                        if ((code[i].Label.Temp & ReachableFlag) != 0)
 
1655
                                                        {
 
1656
                                                                goto case CodeType.BeginCatchBlock;
 
1657
                                                        }
 
1658
                                                        break;
 
1659
                                                case CodeType.BeginCatchBlock:
 
1660
                                                case CodeType.BeginFaultBlock:
 
1661
                                                case CodeType.BeginFinallyBlock:
 
1662
                                                        code.RemoveRange(firstUnreachable, i - firstUnreachable);
 
1663
                                                        i = firstUnreachable;
 
1664
                                                        firstUnreachable = -1;
 
1665
                                                        reachable = true;
 
1666
                                                        break;
 
1667
                                                default:
 
1668
                                                        code.RemoveRange(firstUnreachable, i - firstUnreachable);
 
1669
                                                        i = firstUnreachable;
 
1670
                                                        firstUnreachable++;
 
1671
                                                        break;
 
1672
                                        }
 
1673
                                }
 
1674
                        }
 
1675
                        if (!reachable)
 
1676
                        {
 
1677
                                code.RemoveRange(firstUnreachable, code.Count - firstUnreachable);
 
1678
                        }
 
1679
 
 
1680
                        // TODO can't we incorporate this in the above code?
 
1681
                        // remove exception blocks with empty try blocks
 
1682
                        // (which can happen if the try block is unreachable)
 
1683
                        for (int i = 0; i < code.Count; i++)
 
1684
                        {
 
1685
                        restart:
 
1686
                                if (code[i].pseudo == CodeType.BeginExceptionBlock)
 
1687
                                {
 
1688
                                        for (int k = 0; ; k++)
 
1689
                                        {
 
1690
                                                switch (code[i + k].pseudo)
 
1691
                                                {
 
1692
                                                        case CodeType.BeginCatchBlock:
 
1693
                                                        case CodeType.BeginFaultBlock:
 
1694
                                                        case CodeType.BeginFinallyBlock:
 
1695
                                                                int depth = 0;
 
1696
                                                                for (int j = i + 1; ; j++)
 
1697
                                                                {
 
1698
                                                                        switch (code[j].pseudo)
 
1699
                                                                        {
 
1700
                                                                                case CodeType.BeginExceptionBlock:
 
1701
                                                                                        depth++;
 
1702
                                                                                        break;
 
1703
                                                                                case CodeType.EndExceptionBlock:
 
1704
                                                                                        if (depth == 0)
 
1705
                                                                                        {
 
1706
                                                                                                code.RemoveRange(i, (j - i) + 1);
 
1707
                                                                                                goto restart;
 
1708
                                                                                        }
 
1709
                                                                                        depth--;
 
1710
                                                                                        break;
 
1711
                                                                        }
 
1712
                                                                }
 
1713
                                                        case CodeType.OpCode:
 
1714
                                                                goto next;
 
1715
                                                }
 
1716
                                        }
 
1717
                                }
 
1718
                        next: ;
 
1719
                        }
 
1720
                }
 
1721
 
 
1722
                private void DeduplicateBranchSourceTargetCode()
 
1723
                {
 
1724
                        SetLabelIndexes();
 
1725
                        for (int i = 0; i < code.Count; i++)
 
1726
                        {
 
1727
                                if (code[i].opcode == OpCodes.Br && code[i].HasLabel)
 
1728
                                {
 
1729
                                        int source = i - 1;
 
1730
                                        int target = code[i].Label.Temp - 1;
 
1731
                                        while (source >= 0 && target >= 0)
 
1732
                                        {
 
1733
                                                switch (code[source].pseudo)
 
1734
                                                {
 
1735
                                                        case CodeType.LineNumber:
 
1736
                                                        case CodeType.OpCode:
 
1737
                                                                break;
 
1738
                                                        default:
 
1739
                                                                goto break_while;
 
1740
                                                }
 
1741
                                                if (!code[source].Match(code[target]))
 
1742
                                                {
 
1743
                                                        break;
 
1744
                                                }
 
1745
                                                switch (code[source].opcode.FlowControl)
 
1746
                                                {
 
1747
                                                        case FlowControl.Branch:
 
1748
                                                        case FlowControl.Cond_Branch:
 
1749
                                                                goto break_while;
 
1750
                                                }
 
1751
                                                source--;
 
1752
                                                target--;
 
1753
                                        }
 
1754
                                break_while: ;
 
1755
                                        source++;
 
1756
                                        target++;
 
1757
                                        if (source != i && target > 0 && source != target - 1)
 
1758
                                        {
 
1759
                                                // TODO for now we only do this optimization if there happens to be an appriopriate label
 
1760
                                                if (code[target - 1].pseudo == CodeType.Label)
 
1761
                                                {
 
1762
                                                        code[source] = new OpCodeWrapper(OpCodes.Br, code[target - 1].Label);
 
1763
                                                        for (int j = source + 1; j <= i; j++)
 
1764
                                                        {
 
1765
                                                                // We can't depend on DCE for code correctness (we have to maintain all MSIL invariants at all times),
 
1766
                                                                // so we patch out the unused code.
 
1767
                                                                code[j] = new OpCodeWrapper(CodeType.Unreachable, null);
 
1768
                                                        }
 
1769
                                                }
 
1770
                                        }
 
1771
                                }
 
1772
                        }
 
1773
                }
 
1774
 
 
1775
                private void OptimizeStackTransfer()
 
1776
                {
 
1777
                        for (int i = 0; i < code.Count; i++)
 
1778
                        {
 
1779
                                if (code[i].opcode == OpCodes.Ldloc
 
1780
                                        && code[i + 1].opcode == OpCodes.Stloc
 
1781
                                        && code[i + 2].pseudo == CodeType.BeginExceptionBlock
 
1782
                                        && code[i + 3].opcode == OpCodes.Ldloc && code[i + 3].MatchLocal(code[i + 1])
 
1783
                                        && code[i + 4].pseudo == CodeType.ReleaseTempLocal && code[i + 4].MatchLocal(code[i + 3]))
 
1784
                                {
 
1785
                                        code[i + 1] = code[i];
 
1786
                                        code[i] = code[i + 2];
 
1787
                                        code.RemoveRange(i + 2, 3);
 
1788
                                }
 
1789
                        }
 
1790
                }
 
1791
 
 
1792
                private void MergeExceptionBlocks()
 
1793
                {
 
1794
                        // The first loop will convert all Begin[Exception|Catch|Fault|Finally]Block and EndExceptionBlock
 
1795
                        // pseudo opcodes into a cyclic linked list (EndExceptionBlock links back to BeginExceptionBlock)
 
1796
                        // to allow for easy traversal in the next loop.
 
1797
                        int[] extra = new int[code.Count];
 
1798
                        Stack<int> stack = new Stack<int>();
 
1799
                        int currentBeginExceptionBlock = -1;
 
1800
                        int currentLast = -1;
 
1801
                        for (int i = 0; i < code.Count; i++)
 
1802
                        {
 
1803
                                switch (code[i].pseudo)
 
1804
                                {
 
1805
                                        case CodeType.BeginExceptionBlock:
 
1806
                                                stack.Push(currentBeginExceptionBlock);
 
1807
                                                currentBeginExceptionBlock = i;
 
1808
                                                currentLast = i;
 
1809
                                                break;
 
1810
                                        case CodeType.EndExceptionBlock:
 
1811
                                                extra[currentLast] = i;
 
1812
                                                extra[i] = currentBeginExceptionBlock;
 
1813
                                                currentBeginExceptionBlock = stack.Pop();
 
1814
                                                currentLast = currentBeginExceptionBlock;
 
1815
                                                if (currentLast != -1)
 
1816
                                                {
 
1817
                                                        while (extra[currentLast] != 0)
 
1818
                                                        {
 
1819
                                                                currentLast = extra[currentLast];
 
1820
                                                        }
 
1821
                                                }
 
1822
                                                break;
 
1823
                                        case CodeType.BeginCatchBlock:
 
1824
                                        case CodeType.BeginFaultBlock:
 
1825
                                        case CodeType.BeginFinallyBlock:
 
1826
                                                extra[currentLast] = i;
 
1827
                                                currentLast = i;
 
1828
                                                break;
 
1829
                                }
 
1830
                        }
 
1831
 
 
1832
                        // Now we look for consecutive exception blocks that have the same fault handler
 
1833
                        for (int i = 0; i < code.Count - 1; i++)
 
1834
                        {
 
1835
                                if (code[i].pseudo == CodeType.EndExceptionBlock
 
1836
                                        && code[i + 1].pseudo == CodeType.BeginExceptionBlock)
 
1837
                                {
 
1838
                                        if (IsFaultOnlyBlock(extra, extra[i]) && IsFaultOnlyBlock(extra, i + 1))
 
1839
                                        {
 
1840
                                                int beginFault1 = extra[extra[i]];
 
1841
                                                int beginFault2 = extra[i + 1];
 
1842
                                                int length1 = extra[beginFault1] - beginFault1;
 
1843
                                                int length2 = extra[beginFault2] - beginFault2;
 
1844
                                                if (length1 == length2 && MatchHandlers(beginFault1, beginFault2, length1))
 
1845
                                                {
 
1846
                                                        // Check if the labels at the start of the handler are reachable from outside
 
1847
                                                        // of the new combined block.
 
1848
                                                        for (int j = i + 2; j < beginFault2; j++)
 
1849
                                                        {
 
1850
                                                                if (code[j].pseudo == CodeType.OpCode)
 
1851
                                                                {
 
1852
                                                                        break;
 
1853
                                                                }
 
1854
                                                                else if (code[j].pseudo == CodeType.Label)
 
1855
                                                                {
 
1856
                                                                        if (HasBranchTo(0, extra[i], code[j].Label)
 
1857
                                                                                || HasBranchTo(beginFault2 + length2, code.Count, code[j].Label))
 
1858
                                                                        {
 
1859
                                                                                goto no_merge;
 
1860
                                                                        }
 
1861
                                                                }
 
1862
                                                        }
 
1863
                                                        // Merge the two blocks by overwritting the first fault block and
 
1864
                                                        // the BeginExceptionBlock of the second block.
 
1865
                                                        for (int j = beginFault1; j < i + 2; j++)
 
1866
                                                        {
 
1867
                                                                code[j] = new OpCodeWrapper(OpCodes.Nop, null);
 
1868
                                                        }
 
1869
                                                        // Repair the linking structure.
 
1870
                                                        extra[extra[i]] = beginFault2;
 
1871
                                                        extra[extra[beginFault2]] = extra[i];
 
1872
                                                }
 
1873
                                        }
 
1874
                                no_merge: ;
 
1875
                                }
 
1876
                        }
 
1877
                }
 
1878
 
 
1879
                private bool HasBranchTo(int start, int end, CodeEmitterLabel label)
 
1880
                {
 
1881
                        for (int i = start; i < end; i++)
 
1882
                        {
 
1883
                                if (code[i].HasLabel)
 
1884
                                {
 
1885
                                        if (code[i].Label == label)
 
1886
                                        {
 
1887
                                                return true;
 
1888
                                        }
 
1889
                                }
 
1890
                                else if (code[i].opcode == OpCodes.Switch)
 
1891
                                {
 
1892
                                        foreach (CodeEmitterLabel swlbl in code[i].Labels)
 
1893
                                        {
 
1894
                                                if (swlbl == label)
 
1895
                                                {
 
1896
                                                        return true;
 
1897
                                                }
 
1898
                                        }
 
1899
                                }
 
1900
                        }
 
1901
                        return false;
 
1902
                }
 
1903
 
 
1904
                private bool MatchHandlers(int beginFault1, int beginFault2, int length)
 
1905
                {
 
1906
                        for (int i = 0; i < length; i++)
 
1907
                        {
 
1908
                                if (!code[beginFault1 + i].Match(code[beginFault2 + i]))
 
1909
                                {
 
1910
                                        return false;
 
1911
                                }
 
1912
                        }
 
1913
                        return true;
 
1914
                }
 
1915
 
 
1916
                private bool IsFaultOnlyBlock(int[] extra, int begin)
 
1917
                {
 
1918
                        return code[extra[begin]].pseudo == CodeType.BeginFaultBlock
 
1919
                                && code[extra[extra[begin]]].pseudo == CodeType.EndExceptionBlock;
 
1920
                }
 
1921
 
 
1922
                private void ConvertSynchronizedFaultToFinally()
 
1923
                {
 
1924
                        bool labelIndexSet = false;
 
1925
                        int start = -1;
 
1926
                        int nest = 0;
 
1927
                        int next = -1;
 
1928
                        for (int i = 0; i < code.Count; i++)
 
1929
                        {
 
1930
                                switch (code[i].pseudo)
 
1931
                                {
 
1932
                                        case CodeType.BeginExceptionBlock:
 
1933
                                                if (nest == 0)
 
1934
                                                {
 
1935
                                                        start = i;
 
1936
                                                }
 
1937
                                                else if (nest == 1 && next <= start)
 
1938
                                                {
 
1939
                                                        next = i;
 
1940
                                                }
 
1941
                                                nest++;
 
1942
                                                break;
 
1943
                                        case CodeType.BeginCatchBlock:
 
1944
                                        case CodeType.BeginFinallyBlock:
 
1945
                                                if (nest == 1)
 
1946
                                                {
 
1947
                                                        nest = 0;
 
1948
                                                        if (next > start)
 
1949
                                                        {
 
1950
                                                                // while we were processing the outer block, we encountered a nested BeginExceptionBlock
 
1951
                                                                // so now that we've failed the outer, restart at the first nested block
 
1952
                                                                i = start = next;
 
1953
                                                                nest = 1;
 
1954
                                                        }
 
1955
                                                }
 
1956
                                                else
 
1957
                                                {
 
1958
                                                        next = -1;
 
1959
                                                }
 
1960
                                                break;
 
1961
                                        case CodeType.BeginFaultBlock:
 
1962
                                                if (nest == 1)
 
1963
                                                {
 
1964
                                                        int beginFault = i;
 
1965
                                                        if (code[i + 1].pseudo == CodeType.LineNumber)
 
1966
                                                        {
 
1967
                                                                i++;
 
1968
                                                        }
 
1969
                                                        // check if the fault handler is the synchronized block exit pattern
 
1970
                                                        if (code[i + 1].opcode == OpCodes.Ldloc
 
1971
                                                                && code[i + 2].pseudo == CodeType.MonitorExit
 
1972
                                                                && code[i + 3].opcode == OpCodes.Endfinally)
 
1973
                                                        {
 
1974
                                                                if (!labelIndexSet)
 
1975
                                                                {
 
1976
                                                                        labelIndexSet = true;
 
1977
                                                                        SetLabelIndexes();
 
1978
                                                                }
 
1979
                                                                // now make two passes through the try block to 1) see if all leave
 
1980
                                                                // opcodes that leave the try block do a synchronized block exit
 
1981
                                                                // and 2) patch out the synchronized block exit
 
1982
                                                                for (int pass = 0; pass < 2; pass++)
 
1983
                                                                {
 
1984
                                                                        for (int j = start; j < i; j++)
 
1985
                                                                        {
 
1986
                                                                                if (code[j].opcode == OpCodes.Leave)
 
1987
                                                                                {
 
1988
                                                                                        int target = code[j].Label.Temp;
 
1989
                                                                                        if (target < start || target > i)
 
1990
                                                                                        {
 
1991
                                                                                                // check if the code preceding the leave matches the fault block
 
1992
                                                                                                if ((code[j - 1].opcode == OpCodes.Pop || code[j - 1].opcode == OpCodes.Stloc)
 
1993
                                                                                                        && code[j - 2].pseudo == CodeType.MonitorExit
 
1994
                                                                                                        && code[j - 3].Match(code[i + 1]))
 
1995
                                                                                                {
 
1996
                                                                                                        if (pass == 1)
 
1997
                                                                                                        {
 
1998
                                                                                                                // move the leave to the top of the sequence we're removing
 
1999
                                                                                                                code[j - 3] = code[j - 1];
 
2000
                                                                                                                code[j - 2] = code[j - 0];
 
2001
                                                                                                                code[j - 1] = new OpCodeWrapper(CodeType.Unreachable, CodeTypeFlags.None);
 
2002
                                                                                                                code[j - 0] = new OpCodeWrapper(CodeType.Unreachable, CodeTypeFlags.None);
 
2003
                                                                                                        }
 
2004
                                                                                                }
 
2005
                                                                                                else if (code[j - 1].pseudo == CodeType.MonitorExit
 
2006
                                                                                                        && code[j - 2].Match(code[i + 1]))
 
2007
                                                                                                {
 
2008
                                                                                                        if (pass == 1)
 
2009
                                                                                                        {
 
2010
                                                                                                                // move the leave to the top of the sequence we're removing
 
2011
                                                                                                                code[j - 2] = code[j];
 
2012
                                                                                                                code[j - 1] = new OpCodeWrapper(CodeType.Unreachable, CodeTypeFlags.None);
 
2013
                                                                                                                code[j - 0] = new OpCodeWrapper(CodeType.Unreachable, CodeTypeFlags.None);
 
2014
                                                                                                        }
 
2015
                                                                                                }
 
2016
                                                                                                else
 
2017
                                                                                                {
 
2018
                                                                                                        goto fail;
 
2019
                                                                                                }
 
2020
                                                                                        }
 
2021
                                                                                }
 
2022
                                                                        }
 
2023
                                                                }
 
2024
                                                                // if we end up here, all leaves have been successfully patched,
 
2025
                                                                // so now we turn the BeginFaultBlock into a BeginFinallyBlock
 
2026
                                                                code[beginFault] = new OpCodeWrapper(CodeType.BeginFinallyBlock, CodeTypeFlags.None);
 
2027
                                                        fail: ;
 
2028
                                                        }
 
2029
                                                        goto case CodeType.BeginFinallyBlock;
 
2030
                                                }
 
2031
                                                break;
 
2032
                                        case CodeType.EndExceptionBlock:
 
2033
                                                nest--;
 
2034
                                                break;
 
2035
                                }
 
2036
                        }
 
2037
                }
 
2038
 
 
2039
                private void RemoveRedundantMemoryBarriers()
 
2040
                {
 
2041
                        int lastMemoryBarrier = -1;
 
2042
                        for (int i = 0; i < code.Count; i++)
 
2043
                        {
 
2044
                                switch (code[i].pseudo)
 
2045
                                {
 
2046
                                        case CodeType.MemoryBarrier:
 
2047
                                                if (lastMemoryBarrier != -1)
 
2048
                                                {
 
2049
                                                        code.RemoveAt(lastMemoryBarrier);
 
2050
                                                        i--;
 
2051
                                                }
 
2052
                                                lastMemoryBarrier = i;
 
2053
                                                break;
 
2054
                                        case CodeType.OpCode:
 
2055
                                                if (code[i].opcode == OpCodes.Volatile)
 
2056
                                                {
 
2057
                                                        if (code[i + 1].opcode != OpCodes.Stfld && code[i + 1].opcode != OpCodes.Stsfld)
 
2058
                                                        {
 
2059
                                                                lastMemoryBarrier = -1;
 
2060
                                                        }
 
2061
                                                }
 
2062
                                                else if (code[i].opcode.FlowControl != FlowControl.Next)
 
2063
                                                {
 
2064
                                                        lastMemoryBarrier = -1;
 
2065
                                                }
 
2066
                                                break;
 
2067
                                }
 
2068
                        }
 
2069
                }
 
2070
 
 
2071
                private static bool MatchLdarg(OpCodeWrapper opc, out short arg)
 
2072
                {
 
2073
                        if (opc.opcode == OpCodes.Ldarg)
 
2074
                        {
 
2075
                                arg = opc.ValueInt16;
 
2076
                                return true;
 
2077
                        }
 
2078
                        else if (opc.opcode == OpCodes.Ldarg_S)
 
2079
                        {
 
2080
                                arg = opc.ValueByte;
 
2081
                                return true;
 
2082
                        }
 
2083
                        else if (opc.opcode == OpCodes.Ldarg_0)
 
2084
                        {
 
2085
                                arg = 0;
 
2086
                                return true;
 
2087
                        }
 
2088
                        else if (opc.opcode == OpCodes.Ldarg_1)
 
2089
                        {
 
2090
                                arg = 1;
 
2091
                                return true;
 
2092
                        }
 
2093
                        else if (opc.opcode == OpCodes.Ldarg_2)
 
2094
                        {
 
2095
                                arg = 2;
 
2096
                                return true;
 
2097
                        }
 
2098
                        else if (opc.opcode == OpCodes.Ldarg_3)
 
2099
                        {
 
2100
                                arg = 3;
 
2101
                                return true;
 
2102
                        }
 
2103
                        else
 
2104
                        {
 
2105
                                arg = -1;
 
2106
                                return false;
 
2107
                        }
 
2108
                }
 
2109
 
 
2110
                private bool IsBranchEqNe(OpCode opcode)
 
2111
                {
 
2112
                        return opcode == OpCodes.Beq
 
2113
                                || opcode == OpCodes.Bne_Un;
 
2114
                }
 
2115
 
 
2116
                private void CLRv4_x64_JIT_Workaround()
 
2117
                {
 
2118
                        for (int i = 0; i < code.Count - 2; i++)
 
2119
                        {
 
2120
                                // This is a workaround for https://connect.microsoft.com/VisualStudio/feedback/details/566946/x64-jit-optimization-bug
 
2121
                                // 
 
2122
                                // Testing shows that the bug appears to be very specific and requires a comparison of a method argument with zero.
 
2123
                                // For example, the problem goes away when the method argument is first assigned to a local variable and then
 
2124
                                // the comparison (and subsequent use) is done against the local variable.
 
2125
                                //
 
2126
                                // This means we only have to detect these specific patterns:
 
2127
                                //
 
2128
                                //   ldc.i8 0x0        ldarg
 
2129
                                //   ldarg             ldc.i8 0x0
 
2130
                                //   beq/bne           beq/bne
 
2131
                                //
 
2132
                                // The workaround is to replace ldarg with ldarga/ldind.i8. Looking at the generated code by the x86 and x64 JITs
 
2133
                                // this appears to be as efficient as the ldarg and it avoids the x64 bug.
 
2134
                                if (code[i].opcode == OpCodes.Ldc_I8 && code[i].ValueInt64 == 0)
 
2135
                                {
 
2136
                                        short arg;
 
2137
                                        int m;
 
2138
                                        if (i > 0 && MatchLdarg(code[i - 1], out arg) && IsBranchEqNe(code[i + 1].opcode))
 
2139
                                        {
 
2140
                                                m = i - 1;
 
2141
                                        }
 
2142
                                        else if (MatchLdarg(code[i + 1], out arg) && IsBranchEqNe(code[i + 2].opcode))
 
2143
                                        {
 
2144
                                                m = i + 1;
 
2145
                                        }
 
2146
                                        else
 
2147
                                        {
 
2148
                                                continue;
 
2149
                                        }
 
2150
                                        code[m] = new OpCodeWrapper(OpCodes.Ldarga, arg);
 
2151
                                        code.Insert(m + 1, new OpCodeWrapper(OpCodes.Ldind_I8, null));
 
2152
                                }
 
2153
                        }
 
2154
                }
 
2155
 
 
2156
                [Conditional("CHECK_INVARIANTS")]
 
2157
                private void CheckInvariants()
 
2158
                {
 
2159
                        CheckInvariantBranchInOrOutOfBlocks();
 
2160
                        CheckInvariantOpCodeUsage();
 
2161
                        CheckInvariantLocalVariables();
 
2162
                }
 
2163
 
 
2164
                private void CheckInvariantBranchInOrOutOfBlocks()
 
2165
                {
 
2166
                        /*
 
2167
                         * We maintain an invariant that a branch (other than an explicit leave)
 
2168
                         * can never branch out or into an exception block (try or handler).
 
2169
                         * This is a stronger invariant than requirement by MSIL, because
 
2170
                         * we also disallow the following sequence:
 
2171
                         * 
 
2172
                         *    Br Label0
 
2173
                         *    ...
 
2174
                         *    BeginExceptionBlock
 
2175
                         *    Label0:
 
2176
                         *    ...
 
2177
                         *    Br Label0
 
2178
                         *    
 
2179
                         * This should be rewritten as:
 
2180
                         * 
 
2181
                         *    Br Label0
 
2182
                         *    ...
 
2183
                         *    Label0:
 
2184
                         *    BeginExceptionBlock
 
2185
                         *    Label1:
 
2186
                         *    ...
 
2187
                         *    Br Label1
 
2188
                         */
 
2189
                        int blockId = 0;
 
2190
                        int nextBlockId = 1;
 
2191
                        Stack<int> blocks = new Stack<int>();
 
2192
                        for (int i = 0; i < code.Count; i++)
 
2193
                        {
 
2194
                                switch (code[i].pseudo)
 
2195
                                {
 
2196
                                        case CodeType.Label:
 
2197
                                                code[i].Label.Temp = blockId;
 
2198
                                                break;
 
2199
                                        case CodeType.BeginExceptionBlock:
 
2200
                                                blocks.Push(blockId);
 
2201
                                                goto case CodeType.BeginFinallyBlock;
 
2202
                                        case CodeType.BeginFinallyBlock:
 
2203
                                        case CodeType.BeginFaultBlock:
 
2204
                                        case CodeType.BeginCatchBlock:
 
2205
                                                blockId = nextBlockId++;
 
2206
                                                break;
 
2207
                                        case CodeType.EndExceptionBlock:
 
2208
                                                blockId = blocks.Pop();
 
2209
                                                break;
 
2210
                                }
 
2211
                        }
 
2212
                        if (blocks.Count != 0)
 
2213
                        {
 
2214
                                throw new InvalidOperationException("Unbalanced exception blocks");
 
2215
                        }
 
2216
                        blockId = 0;
 
2217
                        nextBlockId = 1;
 
2218
                        for (int i = 0; i < code.Count; i++)
 
2219
                        {
 
2220
                                switch (code[i].pseudo)
 
2221
                                {
 
2222
                                        case CodeType.OpCode:
 
2223
                                                if (code[i].HasLabel
 
2224
                                                        && code[i].opcode != OpCodes.Leave
 
2225
                                                        && code[i].Label.Temp != blockId)
 
2226
                                                {
 
2227
                                                        DumpMethod();
 
2228
                                                        throw new InvalidOperationException("Invalid branch " + code[i].opcode.Name + " at offset " + i + " from block " + blockId + " to " + code[i].Label.Temp);
 
2229
                                                }
 
2230
                                                break;
 
2231
                                        case CodeType.BeginExceptionBlock:
 
2232
                                                blocks.Push(blockId);
 
2233
                                                goto case CodeType.BeginFinallyBlock;
 
2234
                                        case CodeType.BeginFinallyBlock:
 
2235
                                        case CodeType.BeginFaultBlock:
 
2236
                                        case CodeType.BeginCatchBlock:
 
2237
                                                blockId = nextBlockId++;
 
2238
                                                break;
 
2239
                                        case CodeType.EndExceptionBlock:
 
2240
                                                blockId = blocks.Pop();
 
2241
                                                break;
 
2242
                                }
 
2243
                        }
 
2244
                }
 
2245
 
 
2246
                private void CheckInvariantOpCodeUsage()
 
2247
                {
 
2248
                        for (int i = 0; i < code.Count; i++)
 
2249
                        {
 
2250
                                switch (code[i].opcode.FlowControl)
 
2251
                                {
 
2252
                                        case FlowControl.Branch:
 
2253
                                        case FlowControl.Cond_Branch:
 
2254
                                                if (!code[i].HasLabel && code[i].opcode != OpCodes.Switch)
 
2255
                                                {
 
2256
                                                        throw new InvalidOperationException();
 
2257
                                                }
 
2258
                                                break;
 
2259
                                }
 
2260
                        }
 
2261
                }
 
2262
 
 
2263
                private void CheckInvariantLocalVariables()
 
2264
                {
 
2265
                        List<CodeEmitterLocal> locals = new List<CodeEmitterLocal>();
 
2266
                        for (int i = 0; i < code.Count; i++)
 
2267
                        {
 
2268
                                if (code[i].pseudo == CodeType.DeclareLocal)
 
2269
                                {
 
2270
                                        if (locals.Contains(code[i].Local))
 
2271
                                        {
 
2272
                                                throw new InvalidOperationException("Local variable used before declaration");
 
2273
                                        }
 
2274
                                }
 
2275
                                else if (code[i].HasLocal)
 
2276
                                {
 
2277
                                        locals.Add(code[i].Local);
 
2278
                                }
 
2279
                        }
 
2280
                }
 
2281
 
 
2282
                private void MoveLocalDeclarationToBeginScope()
 
2283
                {
 
2284
                        int pos = 0;
 
2285
                        for (int i = 0; i < code.Count; i++)
 
2286
                        {
 
2287
                                switch (code[i].pseudo)
 
2288
                                {
 
2289
                                        case CodeType.BeginScope:
 
2290
                                                pos = i + 1;
 
2291
                                                break;
 
2292
                                        case CodeType.DeclareLocal:
 
2293
                                                OpCodeWrapper decl = code[i];
 
2294
                                                code.RemoveAt(i);
 
2295
                                                code.Insert(pos++, decl);
 
2296
                                                break;
 
2297
                                }
 
2298
                        }
 
2299
                }
 
2300
 
 
2301
                internal void DoEmit()
 
2302
                {
 
2303
                        OptimizePatterns();
 
2304
                        CLRv4_x64_JIT_Workaround();
 
2305
                        RemoveRedundantMemoryBarriers();
 
2306
 
 
2307
                        if (experimentalOptimizations)
 
2308
                        {
 
2309
                                CheckInvariants();
 
2310
                                MoveLocalDeclarationToBeginScope();
 
2311
 
 
2312
                                for (int i = 0; i < 4; i++)
 
2313
                                {
 
2314
                                        RemoveJumpNext();
 
2315
                                        CheckInvariants();
 
2316
                                        ChaseBranches();
 
2317
                                        CheckInvariants();
 
2318
                                        RemoveSingletonBranches();
 
2319
                                        CheckInvariants();
 
2320
                                        RemoveUnusedLabels();
 
2321
                                        CheckInvariants();
 
2322
                                        SortPseudoOpCodes();
 
2323
                                        CheckInvariants();
 
2324
                                        AnnihilatePops();
 
2325
                                        CheckInvariants();
 
2326
                                        AnnihilateStoreReleaseTempLocals();
 
2327
                                        CheckInvariants();
 
2328
                                        DeduplicateBranchSourceTargetCode();
 
2329
                                        CheckInvariants();
 
2330
                                        OptimizeStackTransfer();
 
2331
                                        CheckInvariants();
 
2332
                                        MergeExceptionBlocks();
 
2333
                                        CheckInvariants();
 
2334
                                        ConvertSynchronizedFaultToFinally();
 
2335
                                        CheckInvariants();
 
2336
                                        RemoveDeadCode();
 
2337
                                        CheckInvariants();
 
2338
                                }
 
2339
                        }
 
2340
 
 
2341
#if STATIC_COMPILER
 
2342
                        OptimizeEncodings();
 
2343
                        OptimizeBranchSizes();
 
2344
#endif
 
2345
 
 
2346
                        int ilOffset = 0;
 
2347
                        int lineNumber = -1;
 
2348
                        for (int i = 0; i < code.Count; i++)
 
2349
                        {
 
2350
                                code[i].RealEmit(ilOffset, this, ref lineNumber);
 
2351
#if STATIC_COMPILER || NET_4_0
 
2352
                                ilOffset = ilgen_real.ILOffset;
 
2353
#else
 
2354
                                ilOffset += code[i].Size;
 
2355
#endif
 
2356
                        }
 
2357
                }
 
2358
 
 
2359
                internal void DumpMethod()
 
2360
                {
 
2361
                        Dictionary<CodeEmitterLabel, int> labelIndexes = new Dictionary<CodeEmitterLabel, int>();
 
2362
                        for (int i = 0; i < code.Count; i++)
 
2363
                        {
 
2364
                                if (code[i].pseudo == CodeType.Label)
 
2365
                                {
 
2366
                                        labelIndexes.Add(code[i].Label, i);
 
2367
                                }
 
2368
                        }
 
2369
                        Console.WriteLine("======================");
 
2370
                        for (int i = 0; i < code.Count; i++)
 
2371
                        {
 
2372
                                if (code[i].pseudo == CodeType.OpCode)
 
2373
                                {
 
2374
                                        Console.Write("  " + code[i].opcode.Name);
 
2375
                                        if (code[i].HasLabel)
 
2376
                                        {
 
2377
                                                Console.Write(" label" + labelIndexes[code[i].Label]);
 
2378
                                        }
 
2379
                                        else if (code[i].opcode == OpCodes.Ldarg)
 
2380
                                        {
 
2381
                                                Console.Write(" " + code[i].ValueInt16);
 
2382
                                        }
 
2383
                                        else if (code[i].opcode == OpCodes.Isinst)
 
2384
                                        {
 
2385
                                                Console.Write(" " + code[i].Type);
 
2386
                                        }
 
2387
                                        else if (code[i].opcode == OpCodes.Call || code[i].opcode == OpCodes.Callvirt)
 
2388
                                        {
 
2389
                                                Console.Write(" " + code[i].MethodBase);
 
2390
                                        }
 
2391
                                        Console.WriteLine();
 
2392
                                }
 
2393
                                else if (code[i].pseudo == CodeType.Label)
 
2394
                                {
 
2395
                                        Console.WriteLine("label{0}:  // temp = {1}", i, code[i].Label.Temp);
 
2396
                                }
 
2397
                                else
 
2398
                                {
 
2399
                                        Console.WriteLine(code[i]);
 
2400
                                }
 
2401
                        }
 
2402
                }
 
2403
 
 
2404
                internal void DefineSymbolDocument(ModuleBuilder module, string url, Guid language, Guid languageVendor, Guid documentType)
 
2405
                {
 
2406
                        symbols = module.DefineDocument(url, language, languageVendor, documentType);
 
2407
                }
 
2408
 
 
2409
                internal CodeEmitterLocal UnsafeAllocTempLocal(Type type)
 
2410
                {
 
2411
                        int free = -1;
 
2412
                        for (int i = 0; i < tempLocals.Length; i++)
 
2413
                        {
 
2414
                                CodeEmitterLocal lb = tempLocals[i];
 
2415
                                if (lb == null)
 
2416
                                {
 
2417
                                        if (free == -1)
 
2418
                                        {
 
2419
                                                free = i;
 
2420
                                        }
 
2421
                                }
 
2422
                                else if (lb.LocalType == type)
 
2423
                                {
 
2424
                                        return lb;
 
2425
                                }
 
2426
                        }
 
2427
                        CodeEmitterLocal lb1 = DeclareLocal(type);
 
2428
                        if (free != -1)
 
2429
                        {
 
2430
                                tempLocals[free] = lb1;
 
2431
                        }
 
2432
                        return lb1;
 
2433
                }
 
2434
 
 
2435
                internal CodeEmitterLocal AllocTempLocal(Type type)
 
2436
                {
 
2437
                        for (int i = 0; i < tempLocals.Length; i++)
 
2438
                        {
 
2439
                                CodeEmitterLocal lb = tempLocals[i];
 
2440
                                if (lb != null && lb.LocalType == type)
 
2441
                                {
 
2442
                                        tempLocals[i] = null;
 
2443
                                        return lb;
 
2444
                                }
 
2445
                        }
 
2446
                        return new CodeEmitterLocal(type);
 
2447
                }
 
2448
 
 
2449
                internal void ReleaseTempLocal(CodeEmitterLocal lb)
 
2450
                {
 
2451
                        EmitPseudoOpCode(CodeType.ReleaseTempLocal, lb);
 
2452
                        for (int i = 0; i < tempLocals.Length; i++)
 
2453
                        {
 
2454
                                if (tempLocals[i] == null)
 
2455
                                {
 
2456
                                        tempLocals[i] = lb;
 
2457
                                        break;
 
2458
                                }
 
2459
                        }
 
2460
                }
 
2461
 
 
2462
                internal void BeginCatchBlock(Type exceptionType)
 
2463
                {
 
2464
                        EmitPseudoOpCode(CodeType.BeginCatchBlock, exceptionType);
 
2465
                }
 
2466
 
 
2467
                internal void BeginExceptionBlock()
 
2468
                {
 
2469
#if !STATIC_COMPILER
 
2470
                        exceptionStack.Push(inFinally);
 
2471
                        inFinally = false;
 
2472
#endif
 
2473
                        EmitPseudoOpCode(CodeType.BeginExceptionBlock, null);
 
2474
                }
 
2475
 
 
2476
                internal void BeginFaultBlock()
 
2477
                {
 
2478
#if !STATIC_COMPILER
 
2479
                        inFinally = true;
 
2480
#endif
 
2481
                        EmitPseudoOpCode(CodeType.BeginFaultBlock, null);
 
2482
                }
 
2483
 
 
2484
                internal void BeginFinallyBlock()
 
2485
                {
 
2486
#if !STATIC_COMPILER
 
2487
                        inFinally = true;
 
2488
#endif
 
2489
                        EmitPseudoOpCode(CodeType.BeginFinallyBlock, null);
 
2490
                }
 
2491
 
 
2492
                internal void BeginScope()
 
2493
                {
 
2494
                        EmitPseudoOpCode(CodeType.BeginScope, null);
 
2495
                }
 
2496
 
 
2497
                internal CodeEmitterLocal DeclareLocal(Type localType)
 
2498
                {
 
2499
                        CodeEmitterLocal local = new CodeEmitterLocal(localType);
 
2500
                        EmitPseudoOpCode(CodeType.DeclareLocal, local);
 
2501
                        return local;
 
2502
                }
 
2503
 
 
2504
                internal CodeEmitterLabel DefineLabel()
 
2505
                {
 
2506
                        CodeEmitterLabel label = new CodeEmitterLabel(ilgen_real.DefineLabel());
 
2507
#if LABELCHECK
 
2508
                        labels.Add(label, new System.Diagnostics.StackFrame(1, true));
 
2509
#endif
 
2510
                        return label;
 
2511
                }
 
2512
 
 
2513
                internal void Emit(OpCode opcode)
 
2514
                {
 
2515
                        EmitOpCode(opcode, null);
 
2516
                }
 
2517
 
 
2518
                internal void EmitUnaligned(byte alignment)
 
2519
                {
 
2520
                        EmitOpCode(OpCodes.Unaligned, alignment);
 
2521
                }
 
2522
 
 
2523
                internal void Emit(OpCode opcode, MethodBase mb)
 
2524
                {
 
2525
                        EmitOpCode(opcode, mb);
 
2526
                }
 
2527
 
 
2528
                internal void EmitLdc_R8(double arg)
 
2529
                {
 
2530
                        EmitOpCode(OpCodes.Ldc_R8, arg);
 
2531
                }
 
2532
 
 
2533
                internal void Emit(OpCode opcode, FieldInfo field)
 
2534
                {
 
2535
                        EmitOpCode(opcode, field);
 
2536
                }
 
2537
 
 
2538
                internal void EmitLdarg(int arg)
 
2539
                {
 
2540
                        Debug.Assert(0 <= arg && arg < 65536);
 
2541
                        switch (arg)
 
2542
                        {
 
2543
                                case 0:
 
2544
                                        EmitOpCode(OpCodes.Ldarg_0, null);
 
2545
                                        break;
 
2546
                                case 1:
 
2547
                                        EmitOpCode(OpCodes.Ldarg_1, null);
 
2548
                                        break;
 
2549
                                case 2:
 
2550
                                        EmitOpCode(OpCodes.Ldarg_2, null);
 
2551
                                        break;
 
2552
                                case 3:
 
2553
                                        EmitOpCode(OpCodes.Ldarg_3, null);
 
2554
                                        break;
 
2555
                                default:
 
2556
                                        if (arg < 256)
 
2557
                                        {
 
2558
                                                EmitOpCode(OpCodes.Ldarg_S, (byte)arg);
 
2559
                                        }
 
2560
                                        else
 
2561
                                        {
 
2562
                                                EmitOpCode(OpCodes.Ldarg, (short)arg);
 
2563
                                        }
 
2564
                                        break;
 
2565
                        }
 
2566
                }
 
2567
 
 
2568
                internal void EmitLdarga(int arg)
 
2569
                {
 
2570
                        Debug.Assert(0 <= arg && arg < 65536);
 
2571
                        if (arg < 256)
 
2572
                        {
 
2573
                                EmitOpCode(OpCodes.Ldarga_S, (byte)arg);
 
2574
                        }
 
2575
                        else
 
2576
                        {
 
2577
                                EmitOpCode(OpCodes.Ldarga, (short)arg);
 
2578
                        }
 
2579
                }
 
2580
 
 
2581
                internal void EmitStarg(int arg)
 
2582
                {
 
2583
                        Debug.Assert(0 <= arg && arg < 65536);
 
2584
                        if (arg < 256)
 
2585
                        {
 
2586
                                EmitOpCode(OpCodes.Starg_S, (byte)arg);
 
2587
                        }
 
2588
                        else
 
2589
                        {
 
2590
                                EmitOpCode(OpCodes.Starg, (short)arg);
 
2591
                        }
 
2592
                }
 
2593
 
 
2594
                internal void EmitLdc_I8(long arg)
 
2595
                {
 
2596
                        EmitOpCode(OpCodes.Ldc_I8, arg);
 
2597
                }
 
2598
 
 
2599
                internal void EmitBr(CodeEmitterLabel label)
 
2600
                {
 
2601
                        EmitOpCode(OpCodes.Br, label);
 
2602
                }
 
2603
 
 
2604
                internal void EmitBeq(CodeEmitterLabel label)
 
2605
                {
 
2606
                        EmitOpCode(OpCodes.Beq, label);
 
2607
                }
 
2608
 
 
2609
                internal void EmitBne_Un(CodeEmitterLabel label)
 
2610
                {
 
2611
                        EmitOpCode(OpCodes.Bne_Un, label);
 
2612
                }
 
2613
 
 
2614
                internal void EmitBle_Un(CodeEmitterLabel label)
 
2615
                {
 
2616
                        EmitOpCode(OpCodes.Ble_Un, label);
 
2617
                }
 
2618
 
 
2619
                internal void EmitBlt_Un(CodeEmitterLabel label)
 
2620
                {
 
2621
                        EmitOpCode(OpCodes.Blt_Un, label);
 
2622
                }
 
2623
 
 
2624
                internal void EmitBge_Un(CodeEmitterLabel label)
 
2625
                {
 
2626
                        EmitOpCode(OpCodes.Bge_Un, label);
 
2627
                }
 
2628
 
 
2629
                internal void EmitBle(CodeEmitterLabel label)
 
2630
                {
 
2631
                        EmitOpCode(OpCodes.Ble, label);
 
2632
                }
 
2633
 
 
2634
                internal void EmitBlt(CodeEmitterLabel label)
 
2635
                {
 
2636
                        EmitOpCode(OpCodes.Blt, label);
 
2637
                }
 
2638
 
 
2639
                internal void EmitBge(CodeEmitterLabel label)
 
2640
                {
 
2641
                        EmitOpCode(OpCodes.Bge, label);
 
2642
                }
 
2643
 
 
2644
                internal void EmitBgt(CodeEmitterLabel label)
 
2645
                {
 
2646
                        EmitOpCode(OpCodes.Bgt, label);
 
2647
                }
 
2648
 
 
2649
                internal void EmitBrtrue(CodeEmitterLabel label)
 
2650
                {
 
2651
                        EmitOpCode(OpCodes.Brtrue, label);
 
2652
                }
 
2653
 
 
2654
                internal void EmitBrfalse(CodeEmitterLabel label)
 
2655
                {
 
2656
                        EmitOpCode(OpCodes.Brfalse, label);
 
2657
                }
 
2658
 
 
2659
                internal void EmitLeave(CodeEmitterLabel label)
 
2660
                {
 
2661
                        EmitOpCode(OpCodes.Leave, label);
 
2662
                }
 
2663
 
 
2664
                internal void EmitSwitch(CodeEmitterLabel[] labels)
 
2665
                {
 
2666
                        EmitOpCode(OpCodes.Switch, labels);
 
2667
                }
 
2668
 
 
2669
                internal void Emit(OpCode opcode, CodeEmitterLocal local)
 
2670
                {
 
2671
                        EmitOpCode(opcode, local);
 
2672
                }
 
2673
 
 
2674
                internal void EmitLdc_R4(float arg)
 
2675
                {
 
2676
                        EmitOpCode(OpCodes.Ldc_R4, arg);
 
2677
                }
 
2678
 
 
2679
                internal void Emit(OpCode opcode, string arg)
 
2680
                {
 
2681
                        EmitOpCode(opcode, arg);
 
2682
                }
 
2683
 
 
2684
                internal void Emit(OpCode opcode, Type cls)
 
2685
                {
 
2686
                        EmitOpCode(opcode, cls);
 
2687
                }
 
2688
 
 
2689
                internal void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
 
2690
                {
 
2691
                        EmitOpCode(opcode, new CalliWrapper(unmanagedCallConv, returnType, parameterTypes));
 
2692
                }
 
2693
 
 
2694
                internal void EndExceptionBlock()
 
2695
                {
 
2696
#if STATIC_COMPILER
 
2697
                        EmitPseudoOpCode(CodeType.EndExceptionBlock, null);
 
2698
#else
 
2699
                        EmitPseudoOpCode(CodeType.EndExceptionBlock, inFinally ? CodeTypeFlags.EndFaultOrFinally : CodeTypeFlags.None);
 
2700
                        inFinally = exceptionStack.Pop();
 
2701
#endif
 
2702
                }
 
2703
 
 
2704
                internal void EndScope()
 
2705
                {
 
2706
                        EmitPseudoOpCode(CodeType.EndScope, null);
 
2707
                }
 
2708
 
 
2709
                internal void MarkLabel(CodeEmitterLabel loc)
 
2710
                {
 
2711
#if LABELCHECK
 
2712
                        labels.Remove(loc);
 
2713
#endif
 
2714
                        EmitPseudoOpCode(CodeType.Label, loc);
 
2715
                }
 
2716
 
 
2717
                internal void ThrowException(Type excType)
 
2718
                {
 
2719
                        Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
 
2720
                        Emit(OpCodes.Throw);
 
2721
                }
 
2722
 
 
2723
                internal void SetLineNumber(ushort line)
 
2724
                {
 
2725
                        if (symbols != null)
 
2726
                        {
 
2727
                                EmitPseudoOpCode(CodeType.SequencePoint, (int)line);
 
2728
                        }
 
2729
                        EmitPseudoOpCode(CodeType.LineNumber, (int)line);
 
2730
                }
 
2731
 
 
2732
                internal byte[] GetLineNumberTable()
 
2733
                {
 
2734
                        return linenums == null ? null : linenums.ToArray();
 
2735
                }
 
2736
 
 
2737
#if STATIC_COMPILER
 
2738
                internal void EmitLineNumberTable(MethodBuilder mb)
 
2739
                {
 
2740
                        if(linenums != null)
 
2741
                        {
 
2742
                                AttributeHelper.SetLineNumberTable(mb, linenums);
 
2743
                        }
 
2744
                }
 
2745
#endif // STATIC_COMPILER
 
2746
 
 
2747
                internal void EmitThrow(string dottedClassName)
 
2748
                {
 
2749
                        TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dottedClassName);
 
2750
                        MethodWrapper mw = exception.GetMethodWrapper("<init>", "()V", false);
 
2751
                        mw.Link();
 
2752
                        mw.EmitNewobj(this);
 
2753
                        Emit(OpCodes.Throw);
 
2754
                }
 
2755
 
 
2756
                internal void EmitThrow(string dottedClassName, string message)
 
2757
                {
 
2758
                        TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dottedClassName);
 
2759
                        Emit(OpCodes.Ldstr, message);
 
2760
                        MethodWrapper mw = exception.GetMethodWrapper("<init>", "(Ljava.lang.String;)V", false);
 
2761
                        mw.Link();
 
2762
                        mw.EmitNewobj(this);
 
2763
                        Emit(OpCodes.Throw);
 
2764
                }
 
2765
 
 
2766
                internal void EmitNullCheck()
 
2767
                {
 
2768
                        // I think this is the most efficient way to generate a NullReferenceException if the reference is null
 
2769
                        Emit(OpCodes.Ldvirtftn, objectToString);
 
2770
                        Emit(OpCodes.Pop);
 
2771
                }
 
2772
 
 
2773
                internal void EmitCastclass(Type type)
 
2774
                {
 
2775
                        if (verboseCastFailure != null)
 
2776
                        {
 
2777
                                CodeEmitterLocal lb = DeclareLocal(Types.Object);
 
2778
                                Emit(OpCodes.Stloc, lb);
 
2779
                                Emit(OpCodes.Ldloc, lb);
 
2780
                                Emit(OpCodes.Isinst, type);
 
2781
                                Emit(OpCodes.Dup);
 
2782
                                CodeEmitterLabel ok = DefineLabel();
 
2783
                                EmitBrtrue(ok);
 
2784
                                Emit(OpCodes.Ldloc, lb);
 
2785
                                EmitBrfalse(ok);        // handle null
 
2786
                                Emit(OpCodes.Ldtoken, type);
 
2787
                                Emit(OpCodes.Ldloc, lb);
 
2788
                                Emit(OpCodes.Call, verboseCastFailure);
 
2789
                                MarkLabel(ok);
 
2790
                        }
 
2791
                        else
 
2792
                        {
 
2793
                                Emit(OpCodes.Castclass, type);
 
2794
                        }
 
2795
                }
 
2796
 
 
2797
                // This is basically the same as Castclass, except that it
 
2798
                // throws an IncompatibleClassChangeError on failure.
 
2799
                internal void EmitAssertType(Type type)
 
2800
                {
 
2801
                        CodeEmitterLabel isnull = DefineLabel();
 
2802
                        Emit(OpCodes.Dup);
 
2803
                        EmitBrfalse(isnull);
 
2804
                        Emit(OpCodes.Isinst, type);
 
2805
                        Emit(OpCodes.Dup);
 
2806
                        CodeEmitterLabel ok = DefineLabel();
 
2807
                        EmitBrtrue(ok);
 
2808
                        EmitThrow("java.lang.IncompatibleClassChangeError");
 
2809
                        MarkLabel(isnull);
 
2810
                        Emit(OpCodes.Pop);
 
2811
                        Emit(OpCodes.Ldnull);
 
2812
                        MarkLabel(ok);
 
2813
                }
 
2814
 
 
2815
                internal void EmitUnboxSpecial(Type type)
 
2816
                {
 
2817
                        // NOTE if the reference is null, we treat it as a default instance of the value type.
 
2818
                        Emit(OpCodes.Dup);
 
2819
                        CodeEmitterLabel label1 = DefineLabel();
 
2820
                        EmitBrtrue(label1);
 
2821
                        Emit(OpCodes.Pop);
 
2822
                        CodeEmitterLocal local = AllocTempLocal(type);
 
2823
                        Emit(OpCodes.Ldloca, local);
 
2824
                        Emit(OpCodes.Initobj, type);
 
2825
                        Emit(OpCodes.Ldloc, local);
 
2826
                        ReleaseTempLocal(local);
 
2827
                        CodeEmitterLabel label2 = DefineLabel();
 
2828
                        EmitBr(label2);
 
2829
                        MarkLabel(label1);
 
2830
                        Emit(OpCodes.Unbox, type);
 
2831
                        Emit(OpCodes.Ldobj, type);
 
2832
                        MarkLabel(label2);
 
2833
                }
 
2834
 
 
2835
                internal void EmitLdc_I4(int i)
 
2836
                {
 
2837
                        EmitOpCode(OpCodes.Ldc_I4, i);
 
2838
                }
 
2839
 
 
2840
                internal void Emit_idiv()
 
2841
                {
 
2842
                        // we need to special case dividing by -1, because the CLR div instruction
 
2843
                        // throws an OverflowException when dividing Int32.MinValue by -1, and
 
2844
                        // Java just silently overflows
 
2845
                        Emit(OpCodes.Dup);
 
2846
                        Emit(OpCodes.Ldc_I4_M1);
 
2847
                        CodeEmitterLabel label = DefineLabel();
 
2848
                        EmitBne_Un(label);
 
2849
                        Emit(OpCodes.Pop);
 
2850
                        Emit(OpCodes.Neg);
 
2851
                        CodeEmitterLabel label2 = DefineLabel();
 
2852
                        EmitBr(label2);
 
2853
                        MarkLabel(label);
 
2854
                        Emit(OpCodes.Div);
 
2855
                        MarkLabel(label2);
 
2856
                }
 
2857
 
 
2858
                internal void Emit_ldiv()
 
2859
                {
 
2860
                        // we need to special case dividing by -1, because the CLR div instruction
 
2861
                        // throws an OverflowException when dividing Int32.MinValue by -1, and
 
2862
                        // Java just silently overflows
 
2863
                        Emit(OpCodes.Dup);
 
2864
                        Emit(OpCodes.Ldc_I4_M1);
 
2865
                        Emit(OpCodes.Conv_I8);
 
2866
                        CodeEmitterLabel label = DefineLabel();
 
2867
                        EmitBne_Un(label);
 
2868
                        Emit(OpCodes.Pop);
 
2869
                        Emit(OpCodes.Neg);
 
2870
                        CodeEmitterLabel label2 = DefineLabel();
 
2871
                        EmitBr(label2);
 
2872
                        MarkLabel(label);
 
2873
                        Emit(OpCodes.Div);
 
2874
                        MarkLabel(label2);
 
2875
                }
 
2876
 
 
2877
                internal void Emit_instanceof(Type type)
 
2878
                {
 
2879
                        Emit(OpCodes.Isinst, type);
 
2880
                        Emit(OpCodes.Ldnull);
 
2881
                        Emit(OpCodes.Cgt_Un);
 
2882
                }
 
2883
 
 
2884
                internal enum Comparison
 
2885
                {
 
2886
                        LessOrEqual,
 
2887
                        LessThan,
 
2888
                        GreaterOrEqual,
 
2889
                        GreaterThan
 
2890
                }
 
2891
 
 
2892
                internal void Emit_if_le_lt_ge_gt(Comparison comp, CodeEmitterLabel label)
 
2893
                {
 
2894
                        // don't change this Ldc_I4_0 to Ldc_I4(0) because the optimizer recognizes
 
2895
                        // only this specific pattern
 
2896
                        Emit(OpCodes.Ldc_I4_0);
 
2897
                        switch (comp)
 
2898
                        {
 
2899
                                case Comparison.LessOrEqual:
 
2900
                                        EmitBle(label);
 
2901
                                        break;
 
2902
                                case Comparison.LessThan:
 
2903
                                        EmitBlt(label);
 
2904
                                        break;
 
2905
                                case Comparison.GreaterOrEqual:
 
2906
                                        EmitBge(label);
 
2907
                                        break;
 
2908
                                case Comparison.GreaterThan:
 
2909
                                        EmitBgt(label);
 
2910
                                        break;
 
2911
                        }
 
2912
                }
 
2913
 
 
2914
                private void EmitCmp(Type type, OpCode cmp1, OpCode cmp2)
 
2915
                {
 
2916
                        CodeEmitterLocal value1 = AllocTempLocal(type);
 
2917
                        CodeEmitterLocal value2 = AllocTempLocal(type);
 
2918
                        Emit(OpCodes.Stloc, value2);
 
2919
                        Emit(OpCodes.Stloc, value1);
 
2920
                        Emit(OpCodes.Ldloc, value1);
 
2921
                        Emit(OpCodes.Ldloc, value2);
 
2922
                        Emit(cmp1);
 
2923
                        Emit(OpCodes.Ldloc, value1);
 
2924
                        Emit(OpCodes.Ldloc, value2);
 
2925
                        Emit(cmp2);
 
2926
                        Emit(OpCodes.Sub);
 
2927
                        ReleaseTempLocal(value2);
 
2928
                        ReleaseTempLocal(value1);
 
2929
                }
 
2930
 
 
2931
                internal void Emit_lcmp()
 
2932
                {
 
2933
                        EmitCmp(Types.Int64, OpCodes.Cgt, OpCodes.Clt);
 
2934
                }
 
2935
 
 
2936
                internal void Emit_fcmpl()
 
2937
                {
 
2938
                        EmitCmp(Types.Single, OpCodes.Cgt, OpCodes.Clt_Un);
 
2939
                }
 
2940
 
 
2941
                internal void Emit_fcmpg()
 
2942
                {
 
2943
                        EmitCmp(Types.Single, OpCodes.Cgt_Un, OpCodes.Clt);
 
2944
                }
 
2945
 
 
2946
                internal void Emit_dcmpl()
 
2947
                {
 
2948
                        EmitCmp(Types.Double, OpCodes.Cgt, OpCodes.Clt_Un);
 
2949
                }
 
2950
 
 
2951
                internal void Emit_dcmpg()
 
2952
                {
 
2953
                        EmitCmp(Types.Double, OpCodes.Cgt_Un, OpCodes.Clt);
 
2954
                }
 
2955
 
 
2956
                internal void Emit_And_I4(int v)
 
2957
                {
 
2958
                        EmitLdc_I4(v);
 
2959
                        Emit(OpCodes.And);
 
2960
                }
 
2961
 
 
2962
                internal void CheckLabels()
 
2963
                {
 
2964
#if LABELCHECK
 
2965
                        foreach(System.Diagnostics.StackFrame frame in labels.Values)
 
2966
                        {
 
2967
                                string name = frame.GetFileName() + ":" + frame.GetFileLineNumber();
 
2968
                                IKVM.Internal.JVM.CriticalFailure("Label failure: " + name, null);
 
2969
                        }
 
2970
#endif
 
2971
                }
 
2972
 
 
2973
                internal void EmitMemoryBarrier()
 
2974
                {
 
2975
                        EmitPseudoOpCode(CodeType.MemoryBarrier, null);
 
2976
                }
 
2977
 
 
2978
                internal void EmitTailCallPrevention()
 
2979
                {
 
2980
                        EmitPseudoOpCode(CodeType.TailCallPrevention, null);
 
2981
                }
 
2982
 
 
2983
                internal void EmitClearStack()
 
2984
                {
 
2985
                        EmitPseudoOpCode(CodeType.ClearStack, null);
 
2986
                }
 
2987
 
 
2988
                internal void EmitMonitorEnter()
 
2989
                {
 
2990
                        EmitPseudoOpCode(CodeType.MonitorEnter, null);
 
2991
                }
 
2992
 
 
2993
                internal void EmitMonitorExit()
 
2994
                {
 
2995
                        EmitPseudoOpCode(CodeType.MonitorExit, null);
 
2996
                }
 
2997
        }
 
2998
}