2
Copyright (C) 2002-2012 Jeroen Frijters
4
This software is provided 'as-is', without any express or implied
5
warranty. In no event will the authors be held liable for any damages
6
arising from the use of this software.
8
Permission is granted to anyone to use this software for any purpose,
9
including commercial applications, and to alter it and redistribute it
10
freely, subject to the following restrictions:
12
1. The origin of this software must not be misrepresented; you must not
13
claim that you wrote the original software. If you use this software
14
in a product, an acknowledgment in the product documentation would be
15
appreciated but is not required.
16
2. Altered source versions must be plainly marked as such, and must not be
17
misrepresented as being the original software.
18
3. This notice may not be removed or altered from any source distribution.
25
#define CHECK_INVARIANTS
27
using System.Collections.Generic;
29
using IKVM.Reflection;
30
using IKVM.Reflection.Emit;
31
using Type = IKVM.Reflection.Type;
33
using System.Reflection;
34
using System.Reflection.Emit;
36
using System.Runtime.InteropServices;
37
using System.Diagnostics.SymbolStore;
38
using System.Diagnostics;
40
namespace IKVM.Internal
42
sealed class CodeEmitterLabel
44
internal readonly Label Label;
47
internal CodeEmitterLabel(Label label)
53
sealed class CodeEmitterLocal
57
private LocalBuilder local;
59
internal CodeEmitterLocal(Type type)
64
internal Type LocalType
69
internal void SetLocalSymInfo(string name)
74
internal int __LocalIndex
76
get { return local == null ? 0xFFFF : local.LocalIndex; }
79
internal void Emit(ILGenerator ilgen, OpCode opcode)
83
// it's a temporary local that is only allocated on-demand
84
local = ilgen.DeclareLocal(type);
86
ilgen.Emit(opcode, local);
89
internal void Declare(ILGenerator ilgen)
91
local = ilgen.DeclareLocal(type);
94
local.SetLocalSymInfo(name);
99
sealed class CodeEmitter
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;
109
private bool inFinally;
110
private Stack<bool> exceptionStack = new Stack<bool>();
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;
118
private Dictionary<CodeEmitterLabel, System.Diagnostics.StackFrame> labels = new Dictionary<CodeEmitterLabel, System.Diagnostics.StackFrame>();
123
if (experimentalOptimizations)
125
Console.Error.WriteLine("IKVM.NET experimental optimizations enabled.");
129
enum CodeType : short
152
enum CodeTypeFlags : short
155
EndFaultOrFinally = 1,
160
internal readonly CodeType pseudo;
161
private readonly CodeTypeFlags flags;
162
internal readonly OpCode opcode;
163
private readonly object data;
165
internal OpCodeWrapper(CodeType pseudo, object data)
167
this.pseudo = pseudo;
168
this.flags = CodeTypeFlags.None;
169
this.opcode = OpCodes.Nop;
173
internal OpCodeWrapper(CodeType pseudo, CodeTypeFlags flags)
175
this.pseudo = pseudo;
177
this.opcode = OpCodes.Nop;
181
internal OpCodeWrapper(OpCode opcode, object data)
183
this.pseudo = CodeType.OpCode;
184
this.flags = CodeTypeFlags.None;
185
this.opcode = opcode;
189
internal bool Match(OpCodeWrapper other)
191
return other.pseudo == pseudo
192
&& other.opcode == opcode
193
&& (other.data == data || (data != null && data.Equals(other.data)));
196
internal bool HasLabel
198
get { return data is CodeEmitterLabel; }
201
internal CodeEmitterLabel Label
203
get { return (CodeEmitterLabel)data; }
206
internal bool MatchLabel(OpCodeWrapper other)
208
return data == other.data;
211
internal CodeEmitterLabel[] Labels
213
get { return (CodeEmitterLabel[])data; }
216
internal bool HasLocal
218
get { return data is CodeEmitterLocal; }
221
internal CodeEmitterLocal Local
223
get { return (CodeEmitterLocal)data; }
226
internal bool MatchLocal(OpCodeWrapper other)
228
return data == other.data;
231
internal bool HasValueByte
233
get { return data is byte; }
236
internal byte ValueByte
238
get { return (byte)data; }
241
internal short ValueInt16
243
get { return (short)data; }
246
internal int ValueInt32
248
get { return (int)data; }
251
internal long ValueInt64
253
get { return (long)data; }
258
get { return (Type)data; }
261
internal FieldInfo FieldInfo
263
get { return (FieldInfo)data; }
266
internal MethodBase MethodBase
268
get { return (MethodBase)data; }
277
case CodeType.Unreachable:
278
case CodeType.BeginScope:
279
case CodeType.EndScope:
280
case CodeType.DeclareLocal:
281
case CodeType.ReleaseTempLocal:
282
case CodeType.LineNumber:
284
case CodeType.BeginExceptionBlock:
286
case CodeType.SequencePoint:
288
case CodeType.BeginCatchBlock:
289
case CodeType.BeginFaultBlock:
290
case CodeType.BeginFinallyBlock:
291
case CodeType.EndExceptionBlock:
295
if ((flags & CodeTypeFlags.EndFaultOrFinally) != 0)
301
case CodeType.MemoryBarrier:
302
case CodeType.MonitorEnter:
303
case CodeType.MonitorExit:
305
case CodeType.TailCallPrevention:
307
case CodeType.ClearStack:
309
case CodeType.OpCode:
314
else if (data is int)
316
return opcode.Size + 4;;
318
else if (data is long)
320
return opcode.Size + 8;
322
else if (data is MethodInfo)
324
return opcode.Size + 4;
326
else if (data is ConstructorInfo)
328
return opcode.Size + 4;
330
else if (data is FieldInfo)
332
return opcode.Size + 4;
334
else if (data is sbyte)
336
return opcode.Size + 1;
338
else if (data is byte)
340
return opcode.Size + 1;
342
else if (data is short)
344
return opcode.Size + 2;
346
else if (data is float)
348
return opcode.Size + 4;
350
else if (data is double)
352
return opcode.Size + 8;
354
else if (data is string)
356
return opcode.Size + 4;
358
else if (data is Type)
360
return opcode.Size + 4;
362
else if (data is CodeEmitterLocal)
364
int index = ((CodeEmitterLocal)data).__LocalIndex;
365
if(index < 4 && opcode.Value != OpCodes.Ldloca.Value && opcode.Value != OpCodes.Ldloca_S.Value)
378
else if (data is CodeEmitterLabel)
380
switch(opcode.OperandType)
382
case OperandType.InlineBrTarget:
383
return opcode.Size + 4;
384
case OperandType.ShortInlineBrTarget:
385
return opcode.Size + 1;
387
throw new InvalidOperationException();
390
else if (data is CodeEmitterLabel[])
392
return 5 + ((CodeEmitterLabel[])data).Length * 4;
394
else if (data is CalliWrapper)
400
throw new InvalidOperationException();
403
throw new InvalidOperationException();
408
internal void RealEmit(int ilOffset, CodeEmitter codeEmitter, ref int lineNumber)
410
if (pseudo == CodeType.OpCode)
412
if (lineNumber != -1)
414
if (codeEmitter.linenums == null)
416
codeEmitter.linenums = new IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter(32);
418
codeEmitter.linenums.AddMapping(ilOffset, lineNumber);
421
codeEmitter.RealEmitOpCode(opcode, data);
423
else if (pseudo == CodeType.LineNumber)
425
lineNumber = (int)data;
429
codeEmitter.RealEmitPseudoOpCode(ilOffset, pseudo, data);
433
public override string ToString()
435
return pseudo.ToString() + " " + data;
439
sealed class CalliWrapper
441
internal readonly CallingConvention unmanagedCallConv;
442
internal readonly Type returnType;
443
internal readonly Type[] parameterTypes;
445
internal CalliWrapper(CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
447
this.unmanagedCallConv = unmanagedCallConv;
448
this.returnType = returnType;
449
this.parameterTypes = parameterTypes == null ? null : (Type[])parameterTypes.Clone();
453
internal static CodeEmitter Create(MethodBuilder mb)
455
return new CodeEmitter(mb.GetILGenerator(), mb.DeclaringType);
459
internal static CodeEmitter Create(DynamicMethod dm)
461
return new CodeEmitter(dm.GetILGenerator(), null);
465
private CodeEmitter(ILGenerator ilgen, Type declaringType)
468
ilgen.__DisableExceptionBlockAssistance();
470
this.ilgen_real = ilgen;
471
this.declaringType = declaringType;
474
private void EmitPseudoOpCode(CodeType type, object data)
476
code.Add(new OpCodeWrapper(type, data));
479
private void EmitOpCode(OpCode opcode, object arg)
481
code.Add(new OpCodeWrapper(opcode, arg));
484
private void RealEmitPseudoOpCode(int ilOffset, CodeType type, object data)
488
case CodeType.Unreachable:
490
case CodeType.BeginScope:
491
ilgen_real.BeginScope();
493
case CodeType.EndScope:
494
ilgen_real.EndScope();
496
case CodeType.DeclareLocal:
497
((CodeEmitterLocal)data).Declare(ilgen_real);
499
case CodeType.ReleaseTempLocal:
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);
507
ilgen_real.MarkLabel(((CodeEmitterLabel)data).Label);
509
case CodeType.BeginExceptionBlock:
510
ilgen_real.BeginExceptionBlock();
512
case CodeType.BeginCatchBlock:
513
ilgen_real.BeginCatchBlock((Type)data);
515
case CodeType.BeginFaultBlock:
516
ilgen_real.BeginFaultBlock();
518
case CodeType.BeginFinallyBlock:
519
ilgen_real.BeginFinallyBlock();
521
case CodeType.EndExceptionBlock:
522
ilgen_real.EndExceptionBlock();
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);
529
case CodeType.MemoryBarrier:
530
if (memoryBarrier == null)
532
memoryBarrier = JVM.Import(typeof(System.Threading.Thread)).GetMethod("MemoryBarrier", Type.EmptyTypes);
534
ilgen_real.Emit(OpCodes.Call, memoryBarrier);
536
case CodeType.MonitorEnter:
537
ilgen_real.Emit(OpCodes.Call, monitorEnter);
539
case CodeType.MonitorExit:
540
ilgen_real.Emit(OpCodes.Call, monitorExit);
542
case CodeType.TailCallPrevention:
543
ilgen_real.Emit(OpCodes.Ldnull);
544
ilgen_real.Emit(OpCodes.Pop);
546
case CodeType.ClearStack:
547
ilgen_real.Emit(OpCodes.Leave_S, (byte)0);
550
throw new InvalidOperationException();
554
private void RealEmitOpCode(OpCode opcode, object arg)
558
ilgen_real.Emit(opcode);
562
ilgen_real.Emit(opcode, (int)arg);
564
else if (arg is long)
566
ilgen_real.Emit(opcode, (long)arg);
568
else if (arg is MethodInfo)
570
ilgen_real.Emit(opcode, (MethodInfo)arg);
572
else if (arg is ConstructorInfo)
574
ilgen_real.Emit(opcode, (ConstructorInfo)arg);
576
else if (arg is FieldInfo)
578
ilgen_real.Emit(opcode, (FieldInfo)arg);
580
else if (arg is sbyte)
582
ilgen_real.Emit(opcode, (sbyte)arg);
584
else if (arg is byte)
586
ilgen_real.Emit(opcode, (byte)arg);
588
else if (arg is short)
590
ilgen_real.Emit(opcode, (short)arg);
592
else if (arg is float)
594
ilgen_real.Emit(opcode, (float)arg);
596
else if (arg is double)
598
ilgen_real.Emit(opcode, (double)arg);
600
else if (arg is string)
602
ilgen_real.Emit(opcode, (string)arg);
604
else if (arg is Type)
606
ilgen_real.Emit(opcode, (Type)arg);
608
else if (arg is CodeEmitterLocal)
610
CodeEmitterLocal local = (CodeEmitterLocal)arg;
611
local.Emit(ilgen_real, opcode);
613
else if (arg is CodeEmitterLabel)
615
CodeEmitterLabel label = (CodeEmitterLabel)arg;
616
ilgen_real.Emit(opcode, label.Label);
618
else if (arg is CodeEmitterLabel[])
620
CodeEmitterLabel[] labels = (CodeEmitterLabel[])arg;
621
Label[] real = new Label[labels.Length];
622
for (int i = 0; i < labels.Length; i++)
624
real[i] = labels[i].Label;
626
ilgen_real.Emit(opcode, real);
628
else if (arg is CalliWrapper)
630
CalliWrapper args = (CalliWrapper)arg;
631
ilgen_real.EmitCalli(opcode, args.unmanagedCallConv, args.returnType, args.parameterTypes);
635
throw new InvalidOperationException();
639
private void RemoveJumpNext()
641
for (int i = 1; i < code.Count; i++)
643
if (code[i].pseudo == CodeType.Label)
645
if (code[i - 1].opcode == OpCodes.Br
646
&& code[i - 1].MatchLabel(code[i]))
648
code.RemoveAt(i - 1);
652
&& code[i - 1].pseudo == CodeType.LineNumber
653
&& code[i - 2].opcode == OpCodes.Br
654
&& code[i - 2].MatchLabel(code[i]))
656
code.RemoveAt(i - 2);
663
private void AnnihilateStoreReleaseTempLocals()
665
for (int i = 1; i < code.Count; i++)
667
if (code[i].opcode == OpCodes.Stloc)
669
if (code[i + 1].pseudo == CodeType.ReleaseTempLocal
670
&& code[i].Local == code[i + 1].Local)
672
code[i] = new OpCodeWrapper(OpCodes.Pop, null);
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)
679
code.RemoveRange(i, 2);
685
private void AnnihilatePops()
687
for (int i = 1; i < code.Count; i++)
689
if (code[i].opcode == OpCodes.Pop)
691
// search backwards for a candidate push to annihilate
693
for (int j = i - 1; j >= 0; j--)
695
if (IsSideEffectFreePush(j))
706
else if (code[j].opcode == OpCodes.Stloc)
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)
721
else if (code[j].opcode == OpCodes.Conv_Ovf_I4
722
|| code[j].opcode == OpCodes.Conv_I8
723
|| code[j].opcode == OpCodes.Ldlen)
740
private bool IsSideEffectFreePush(int index)
742
if (code[index].opcode == OpCodes.Ldstr)
746
else if (code[index].opcode == OpCodes.Ldnull)
750
else if (code[index].opcode == OpCodes.Ldsfld)
752
FieldInfo field = code[index].FieldInfo;
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)
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)
772
else if (code[index].opcode == OpCodes.Ldc_I4)
776
else if (code[index].opcode == OpCodes.Ldc_I8)
780
else if (code[index].opcode == OpCodes.Ldc_R4)
784
else if (code[index].opcode == OpCodes.Ldc_R8)
788
else if (code[index].opcode == OpCodes.Ldloc)
792
else if (code[index].opcode == OpCodes.Ldarg)
796
else if (code[index].opcode == OpCodes.Ldarg_S)
800
else if (code[index].opcode == OpCodes.Ldarg_0)
804
else if (code[index].opcode == OpCodes.Ldarg_1)
808
else if (code[index].opcode == OpCodes.Ldarg_2)
812
else if (code[index].opcode == OpCodes.Ldarg_3)
822
private void OptimizeBranchSizes()
825
for (int i = 0; i < code.Count; i++)
827
if (code[i].pseudo == CodeType.Label)
829
code[i].Label.Temp = offset;
831
offset += code[i].Size;
834
for (int i = 0; i < code.Count; i++)
836
int prevOffset = offset;
837
offset += code[i].Size;
838
if (code[i].HasLabel && code[i].opcode.OperandType == OperandType.InlineBrTarget)
840
CodeEmitterLabel label = code[i].Label;
841
int diff = label.Temp - (prevOffset + code[i].opcode.Size + 1);
842
if (-128 <= diff && diff <= 127)
844
OpCode opcode = code[i].opcode;
845
if (opcode == OpCodes.Brtrue)
847
opcode = OpCodes.Brtrue_S;
849
else if (opcode == OpCodes.Brfalse)
851
opcode = OpCodes.Brfalse_S;
853
else if (opcode == OpCodes.Br)
855
opcode = OpCodes.Br_S;
857
else if (opcode == OpCodes.Beq)
859
opcode = OpCodes.Beq_S;
861
else if (opcode == OpCodes.Bne_Un)
863
opcode = OpCodes.Bne_Un_S;
865
else if (opcode == OpCodes.Ble)
867
opcode = OpCodes.Ble_S;
869
else if (opcode == OpCodes.Ble_Un)
871
opcode = OpCodes.Ble_Un_S;
873
else if (opcode == OpCodes.Blt)
875
opcode = OpCodes.Blt_S;
877
else if (opcode == OpCodes.Blt_Un)
879
opcode = OpCodes.Blt_Un_S;
881
else if (opcode == OpCodes.Bge)
883
opcode = OpCodes.Bge_S;
885
else if (opcode == OpCodes.Bge_Un)
887
opcode = OpCodes.Bge_Un_S;
889
else if (opcode == OpCodes.Bgt)
891
opcode = OpCodes.Bgt_S;
893
else if (opcode == OpCodes.Bgt_Un)
895
opcode = OpCodes.Bgt_Un_S;
897
else if (opcode == OpCodes.Leave)
899
opcode = OpCodes.Leave_S;
901
code[i] = new OpCodeWrapper(opcode, label);
907
private void OptimizePatterns()
910
for (int i = 1; i < code.Count; i++)
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))
917
code.RemoveRange(i + 1, 2);
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)
923
code[i] = new OpCodeWrapper(OpCodes.Ldelem_U1, null);
924
code.RemoveRange(i + 1, 2);
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)
931
code[i] = new OpCodeWrapper(OpCodes.Ldelem_U1, null);
932
code.RemoveRange(i + 2, 2);
934
else if (code[i].opcode == OpCodes.Ldc_I4
935
&& code[i + 1].opcode == OpCodes.Ldc_I4
936
&& code[i + 2].opcode == OpCodes.And)
938
code[i] = new OpCodeWrapper(OpCodes.Ldc_I4, code[i].ValueInt32 & code[i + 1].ValueInt32);
939
code.RemoveRange(i + 1, 2);
941
else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, Types.Double) // dcmpl
942
|| MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, Types.Single)) // fcmpl
944
PatchCompare(i, OpCodes.Ble_Un, OpCodes.Blt_Un, OpCodes.Bge, OpCodes.Bgt);
946
else if (MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, Types.Double) // dcmpg
947
|| MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, Types.Single)) // fcmpg
949
PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge_Un, OpCodes.Bgt_Un);
951
else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt, Types.Int64)) // lcmp
953
PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge, OpCodes.Bgt);
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)
967
int divisor = code[i].ValueInt32;
970
code[i] = code[i + 5];
971
code.RemoveRange(i + 1, 9);
975
code[i + 1] = code[i + 8];
976
code.RemoveRange(i + 2, 8);
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)
992
long divisor = code[i].ValueInt64;
995
code[i] = code[i + 6];
996
code.RemoveRange(i + 1, 10);
1000
code[i + 1] = code[i + 9];
1001
code.RemoveRange(i + 2, 9);
1004
else if (code[i].opcode == OpCodes.Box
1005
&& code[i + 1].opcode == OpCodes.Unbox && code[i + 1].Type == code[i].Type)
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);
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)
1026
code.RemoveRange(i, 13);
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)
1038
if (code[i].opcode == OpCodes.Bne_Un)
1040
code[i] = new OpCodeWrapper(OpCodes.Ceq, null);
1041
code.RemoveRange(i + 1, 5);
1043
else if (code[i].opcode == OpCodes.Beq)
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);
1050
else if (code[i].opcode == OpCodes.Ble || code[i].opcode == OpCodes.Ble_Un)
1052
code[i] = new OpCodeWrapper(OpCodes.Cgt, null);
1053
code.RemoveRange(i + 1, 5);
1055
else if (code[i].opcode == OpCodes.Blt)
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);
1062
else if (code[i].opcode == OpCodes.Blt_Un)
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);
1069
else if (code[i].opcode == OpCodes.Bge || code[i].opcode == OpCodes.Bge_Un)
1071
code[i] = new OpCodeWrapper(OpCodes.Clt, null);
1072
code.RemoveRange(i + 1, 5);
1074
else if (code[i].opcode == OpCodes.Bgt)
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);
1081
else if (code[i].opcode == OpCodes.Bgt_Un)
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);
1092
private bool MatchCompare(int index, OpCode cmp1, OpCode cmp2, Type type)
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)));
1110
private void PatchCompare(int index, OpCode ble, OpCode blt, OpCode bge, OpCode bgt)
1112
if (code[index + 11].opcode == OpCodes.Brtrue)
1114
code[index] = new OpCodeWrapper(OpCodes.Bne_Un, code[index + 11].Label);
1115
code.RemoveRange(index + 1, 11);
1117
else if (code[index + 11].opcode == OpCodes.Brfalse)
1119
code[index] = new OpCodeWrapper(OpCodes.Beq, code[index + 11].Label);
1120
code.RemoveRange(index + 1, 11);
1122
else if (code[index + 11].opcode == OpCodes.Ldc_I4_0)
1124
if (code[index + 12].opcode == OpCodes.Ble)
1126
code[index] = new OpCodeWrapper(ble, code[index + 12].Label);
1127
code.RemoveRange(index + 1, 12);
1129
else if (code[index + 12].opcode == OpCodes.Blt)
1131
code[index] = new OpCodeWrapper(blt, code[index + 12].Label);
1132
code.RemoveRange(index + 1, 12);
1134
else if (code[index + 12].opcode == OpCodes.Bge)
1136
code[index] = new OpCodeWrapper(bge, code[index + 12].Label);
1137
code.RemoveRange(index + 1, 12);
1139
else if (code[index + 12].opcode == OpCodes.Bgt)
1141
code[index] = new OpCodeWrapper(bgt, code[index + 12].Label);
1142
code.RemoveRange(index + 1, 12);
1147
private void OptimizeEncodings()
1149
for (int i = 0; i < code.Count; i++)
1151
if (code[i].opcode == OpCodes.Ldc_I4)
1153
code[i] = OptimizeLdcI4(code[i].ValueInt32);
1155
else if (code[i].opcode == OpCodes.Ldc_I8)
1162
private OpCodeWrapper OptimizeLdcI4(int value)
1167
return new OpCodeWrapper(OpCodes.Ldc_I4_M1, null);
1169
return new OpCodeWrapper(OpCodes.Ldc_I4_0, null);
1171
return new OpCodeWrapper(OpCodes.Ldc_I4_1, null);
1173
return new OpCodeWrapper(OpCodes.Ldc_I4_2, null);
1175
return new OpCodeWrapper(OpCodes.Ldc_I4_3, null);
1177
return new OpCodeWrapper(OpCodes.Ldc_I4_4, null);
1179
return new OpCodeWrapper(OpCodes.Ldc_I4_5, null);
1181
return new OpCodeWrapper(OpCodes.Ldc_I4_6, null);
1183
return new OpCodeWrapper(OpCodes.Ldc_I4_7, null);
1185
return new OpCodeWrapper(OpCodes.Ldc_I4_8, null);
1187
if (value >= -128 && value <= 127)
1189
return new OpCodeWrapper(OpCodes.Ldc_I4_S, (sbyte)value);
1193
return new OpCodeWrapper(OpCodes.Ldc_I4, value);
1198
private void OptimizeLdcI8(int index)
1200
long value = code[index].ValueInt64;
1201
OpCode opc = OpCodes.Nop;
1205
opc = OpCodes.Ldc_I4_M1;
1208
opc = OpCodes.Ldc_I4_0;
1211
opc = OpCodes.Ldc_I4_1;
1214
opc = OpCodes.Ldc_I4_2;
1217
opc = OpCodes.Ldc_I4_3;
1220
opc = OpCodes.Ldc_I4_4;
1223
opc = OpCodes.Ldc_I4_5;
1226
opc = OpCodes.Ldc_I4_6;
1229
opc = OpCodes.Ldc_I4_7;
1232
opc = OpCodes.Ldc_I4_8;
1235
if (value >= -2147483648L && value <= 4294967295L)
1237
if (value >= -128 && value <= 127)
1239
code[index] = new OpCodeWrapper(OpCodes.Ldc_I4_S, (sbyte)value);
1243
code[index] = new OpCodeWrapper(OpCodes.Ldc_I4, (int)value);
1247
code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_I8, null));
1251
code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_U8, null));
1256
if (opc != OpCodes.Nop)
1258
code[index] = new OpCodeWrapper(opc, null);
1259
code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_I8, null));
1263
private void ChaseBranches()
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
1273
for (int i = 0; i < code.Count; i++)
1275
if (code[i].opcode == OpCodes.Br)
1277
int target = code[i].Label.Temp + 1;
1278
if (code[target].pseudo == CodeType.LineNumber)
1280
// line number info on endfinally or ret is probably useless anyway
1283
if (code[target].opcode == OpCodes.Endfinally || code[target].opcode == OpCodes.Ret)
1285
code[i] = code[target];
1289
CodeEmitterLabel label = null;
1290
while (code[target].opcode == OpCodes.Br && target != i)
1292
label = code[target].Label;
1293
target = code[target].Label.Temp + 1;
1297
code[i] = new OpCodeWrapper(OpCodes.Br, label);
1301
else if (code[i].opcode == OpCodes.Leave)
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)
1307
label = code[target].Label;
1308
target = code[target].Label.Temp + 1;
1312
code[i] = new OpCodeWrapper(OpCodes.Leave, label);
1318
private void RemoveSingletonBranches()
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.
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++)
1331
switch (code[i].pseudo)
1333
case CodeType.Label:
1334
code[i].Label.Temp++;
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)
1344
case FlowControl.Branch:
1345
case FlowControl.Return:
1346
case FlowControl.Throw:
1355
switch (code[i].pseudo)
1357
case CodeType.Label:
1358
reachable = code[i].Label.Temp > 0;
1360
case CodeType.BeginCatchBlock:
1361
case CodeType.BeginFaultBlock:
1362
case CodeType.BeginFinallyBlock:
1369
// now remove the unconditional branches to labels with a refcount of one
1370
for (int i = 0; i < code.Count; i++)
1372
if (code[i].opcode == OpCodes.Br && code[i].Label.Temp == 1)
1374
int target = FindLabel(code[i].Label) + 1;
1375
for (int j = target; j < code.Count; j++)
1377
switch (code[j].pseudo)
1379
case CodeType.OpCode:
1380
if (code[j].HasLocal && FindLocal(code[j].Local) > i)
1382
// we cannot local variable usage before the declaration
1385
switch (code[j].opcode.FlowControl)
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);
1395
code.InsertRange(i, range);
1396
code.RemoveRange(target - 1, range.Count + 1);
1397
i -= range.Count + 1;
1401
code.RemoveRange(target - 1, range.Count + 1);
1403
code.InsertRange(i, range);
1408
case CodeType.Label:
1409
case CodeType.BeginExceptionBlock:
1410
case CodeType.DeclareLocal:
1419
private int FindLabel(CodeEmitterLabel label)
1421
for (int i = 0; i < code.Count; i++)
1423
if (code[i].pseudo == CodeType.Label && code[i].Label == label)
1428
throw new InvalidOperationException();
1431
private int FindLocal(CodeEmitterLocal local)
1433
for (int i = 0; i < code.Count; i++)
1435
if (code[i].pseudo == CodeType.DeclareLocal && code[i].Local == local)
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)
1445
private void SortPseudoOpCodes()
1447
for (int i = 0; i < code.Count - 1; i++)
1449
switch (code[i].pseudo)
1451
case CodeType.ReleaseTempLocal:
1452
for (int j = i - 1; ; j--)
1459
if (code[j].HasLocal && code[j].Local == code[i].Local)
1461
MoveInstruction(i, j + 1);
1470
private void MoveInstruction(int i, int j)
1472
if (i == j - 1 || i == j + 1)
1474
OpCodeWrapper temp = code[i];
1480
code.Insert(j, code[i]);
1485
OpCodeWrapper temp = code[i];
1487
code.Insert(j, temp);
1491
private void ClearLabelTemp()
1493
for (int i = 0; i < code.Count; i++)
1495
if (code[i].pseudo == CodeType.Label)
1497
code[i].Label.Temp = 0;
1502
private void SetLabelIndexes()
1504
for (int i = 0; i < code.Count; i++)
1506
if (code[i].pseudo == CodeType.Label)
1508
code[i].Label.Temp = i;
1513
private void SetLabelRefCounts()
1516
for (int i = 0; i < code.Count; i++)
1518
if (code[i].pseudo == CodeType.OpCode)
1520
if (code[i].HasLabel)
1522
code[i].Label.Temp++;
1524
else if (code[i].opcode == OpCodes.Switch)
1526
foreach (CodeEmitterLabel label in code[i].Labels)
1535
private void RemoveUnusedLabels()
1537
SetLabelRefCounts();
1538
for (int i = 0; i < code.Count; i++)
1540
while (code[i].pseudo == CodeType.Label && code[i].Label.Temp == 0)
1547
private void RemoveDeadCode()
1550
const int ReachableFlag = 1;
1551
const int ProcessedFlag = 2;
1552
bool reachable = true;
1557
for (int i = 0; i < code.Count; i++)
1561
if (code[i].pseudo == CodeType.Label)
1563
if (code[i].Label.Temp == ProcessedFlag)
1567
code[i].Label.Temp |= ReachableFlag;
1569
else if (code[i].pseudo == CodeType.OpCode)
1571
if (code[i].HasLabel)
1573
if (code[i].Label.Temp == ProcessedFlag)
1577
code[i].Label.Temp |= ReachableFlag;
1579
else if (code[i].opcode == OpCodes.Switch)
1581
foreach (CodeEmitterLabel label in code[i].Labels)
1583
if (label.Temp == ProcessedFlag)
1587
label.Temp |= ReachableFlag;
1590
switch (code[i].opcode.FlowControl)
1592
case FlowControl.Cond_Branch:
1593
if (!code[i].HasLabel && code[i].opcode != OpCodes.Switch)
1595
throw new NotSupportedException();
1598
case FlowControl.Branch:
1599
case FlowControl.Return:
1600
case FlowControl.Throw:
1606
else if (code[i].pseudo == CodeType.BeginCatchBlock)
1610
else if (code[i].pseudo == CodeType.BeginFaultBlock)
1614
else if (code[i].pseudo == CodeType.BeginFinallyBlock)
1618
else if (code[i].pseudo == CodeType.Label && (code[i].Label.Temp & ReachableFlag) != 0)
1622
if (code[i].pseudo == CodeType.Label)
1624
code[i].Label.Temp |= ProcessedFlag;
1629
int firstUnreachable = -1;
1630
for (int i = 0; i < code.Count; i++)
1634
if (code[i].pseudo == CodeType.OpCode)
1636
switch (code[i].opcode.FlowControl)
1638
case FlowControl.Branch:
1639
case FlowControl.Return:
1640
case FlowControl.Throw:
1642
firstUnreachable = i + 1;
1649
switch (code[i].pseudo)
1651
case CodeType.OpCode:
1653
case CodeType.Label:
1654
if ((code[i].Label.Temp & ReachableFlag) != 0)
1656
goto case CodeType.BeginCatchBlock;
1659
case CodeType.BeginCatchBlock:
1660
case CodeType.BeginFaultBlock:
1661
case CodeType.BeginFinallyBlock:
1662
code.RemoveRange(firstUnreachable, i - firstUnreachable);
1663
i = firstUnreachable;
1664
firstUnreachable = -1;
1668
code.RemoveRange(firstUnreachable, i - firstUnreachable);
1669
i = firstUnreachable;
1677
code.RemoveRange(firstUnreachable, code.Count - firstUnreachable);
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++)
1686
if (code[i].pseudo == CodeType.BeginExceptionBlock)
1688
for (int k = 0; ; k++)
1690
switch (code[i + k].pseudo)
1692
case CodeType.BeginCatchBlock:
1693
case CodeType.BeginFaultBlock:
1694
case CodeType.BeginFinallyBlock:
1696
for (int j = i + 1; ; j++)
1698
switch (code[j].pseudo)
1700
case CodeType.BeginExceptionBlock:
1703
case CodeType.EndExceptionBlock:
1706
code.RemoveRange(i, (j - i) + 1);
1713
case CodeType.OpCode:
1722
private void DeduplicateBranchSourceTargetCode()
1725
for (int i = 0; i < code.Count; i++)
1727
if (code[i].opcode == OpCodes.Br && code[i].HasLabel)
1730
int target = code[i].Label.Temp - 1;
1731
while (source >= 0 && target >= 0)
1733
switch (code[source].pseudo)
1735
case CodeType.LineNumber:
1736
case CodeType.OpCode:
1741
if (!code[source].Match(code[target]))
1745
switch (code[source].opcode.FlowControl)
1747
case FlowControl.Branch:
1748
case FlowControl.Cond_Branch:
1757
if (source != i && target > 0 && source != target - 1)
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)
1762
code[source] = new OpCodeWrapper(OpCodes.Br, code[target - 1].Label);
1763
for (int j = source + 1; j <= i; j++)
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);
1775
private void OptimizeStackTransfer()
1777
for (int i = 0; i < code.Count; i++)
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]))
1785
code[i + 1] = code[i];
1786
code[i] = code[i + 2];
1787
code.RemoveRange(i + 2, 3);
1792
private void MergeExceptionBlocks()
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++)
1803
switch (code[i].pseudo)
1805
case CodeType.BeginExceptionBlock:
1806
stack.Push(currentBeginExceptionBlock);
1807
currentBeginExceptionBlock = i;
1810
case CodeType.EndExceptionBlock:
1811
extra[currentLast] = i;
1812
extra[i] = currentBeginExceptionBlock;
1813
currentBeginExceptionBlock = stack.Pop();
1814
currentLast = currentBeginExceptionBlock;
1815
if (currentLast != -1)
1817
while (extra[currentLast] != 0)
1819
currentLast = extra[currentLast];
1823
case CodeType.BeginCatchBlock:
1824
case CodeType.BeginFaultBlock:
1825
case CodeType.BeginFinallyBlock:
1826
extra[currentLast] = i;
1832
// Now we look for consecutive exception blocks that have the same fault handler
1833
for (int i = 0; i < code.Count - 1; i++)
1835
if (code[i].pseudo == CodeType.EndExceptionBlock
1836
&& code[i + 1].pseudo == CodeType.BeginExceptionBlock)
1838
if (IsFaultOnlyBlock(extra, extra[i]) && IsFaultOnlyBlock(extra, i + 1))
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))
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++)
1850
if (code[j].pseudo == CodeType.OpCode)
1854
else if (code[j].pseudo == CodeType.Label)
1856
if (HasBranchTo(0, extra[i], code[j].Label)
1857
|| HasBranchTo(beginFault2 + length2, code.Count, code[j].Label))
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++)
1867
code[j] = new OpCodeWrapper(OpCodes.Nop, null);
1869
// Repair the linking structure.
1870
extra[extra[i]] = beginFault2;
1871
extra[extra[beginFault2]] = extra[i];
1879
private bool HasBranchTo(int start, int end, CodeEmitterLabel label)
1881
for (int i = start; i < end; i++)
1883
if (code[i].HasLabel)
1885
if (code[i].Label == label)
1890
else if (code[i].opcode == OpCodes.Switch)
1892
foreach (CodeEmitterLabel swlbl in code[i].Labels)
1904
private bool MatchHandlers(int beginFault1, int beginFault2, int length)
1906
for (int i = 0; i < length; i++)
1908
if (!code[beginFault1 + i].Match(code[beginFault2 + i]))
1916
private bool IsFaultOnlyBlock(int[] extra, int begin)
1918
return code[extra[begin]].pseudo == CodeType.BeginFaultBlock
1919
&& code[extra[extra[begin]]].pseudo == CodeType.EndExceptionBlock;
1922
private void ConvertSynchronizedFaultToFinally()
1924
bool labelIndexSet = false;
1928
for (int i = 0; i < code.Count; i++)
1930
switch (code[i].pseudo)
1932
case CodeType.BeginExceptionBlock:
1937
else if (nest == 1 && next <= start)
1943
case CodeType.BeginCatchBlock:
1944
case CodeType.BeginFinallyBlock:
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
1961
case CodeType.BeginFaultBlock:
1965
if (code[i + 1].pseudo == CodeType.LineNumber)
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)
1976
labelIndexSet = true;
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++)
1984
for (int j = start; j < i; j++)
1986
if (code[j].opcode == OpCodes.Leave)
1988
int target = code[j].Label.Temp;
1989
if (target < start || target > i)
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]))
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);
2005
else if (code[j - 1].pseudo == CodeType.MonitorExit
2006
&& code[j - 2].Match(code[i + 1]))
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);
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);
2029
goto case CodeType.BeginFinallyBlock;
2032
case CodeType.EndExceptionBlock:
2039
private void RemoveRedundantMemoryBarriers()
2041
int lastMemoryBarrier = -1;
2042
for (int i = 0; i < code.Count; i++)
2044
switch (code[i].pseudo)
2046
case CodeType.MemoryBarrier:
2047
if (lastMemoryBarrier != -1)
2049
code.RemoveAt(lastMemoryBarrier);
2052
lastMemoryBarrier = i;
2054
case CodeType.OpCode:
2055
if (code[i].opcode == OpCodes.Volatile)
2057
if (code[i + 1].opcode != OpCodes.Stfld && code[i + 1].opcode != OpCodes.Stsfld)
2059
lastMemoryBarrier = -1;
2062
else if (code[i].opcode.FlowControl != FlowControl.Next)
2064
lastMemoryBarrier = -1;
2071
private static bool MatchLdarg(OpCodeWrapper opc, out short arg)
2073
if (opc.opcode == OpCodes.Ldarg)
2075
arg = opc.ValueInt16;
2078
else if (opc.opcode == OpCodes.Ldarg_S)
2080
arg = opc.ValueByte;
2083
else if (opc.opcode == OpCodes.Ldarg_0)
2088
else if (opc.opcode == OpCodes.Ldarg_1)
2093
else if (opc.opcode == OpCodes.Ldarg_2)
2098
else if (opc.opcode == OpCodes.Ldarg_3)
2110
private bool IsBranchEqNe(OpCode opcode)
2112
return opcode == OpCodes.Beq
2113
|| opcode == OpCodes.Bne_Un;
2116
private void CLRv4_x64_JIT_Workaround()
2118
for (int i = 0; i < code.Count - 2; i++)
2120
// This is a workaround for https://connect.microsoft.com/VisualStudio/feedback/details/566946/x64-jit-optimization-bug
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.
2126
// This means we only have to detect these specific patterns:
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)
2138
if (i > 0 && MatchLdarg(code[i - 1], out arg) && IsBranchEqNe(code[i + 1].opcode))
2142
else if (MatchLdarg(code[i + 1], out arg) && IsBranchEqNe(code[i + 2].opcode))
2150
code[m] = new OpCodeWrapper(OpCodes.Ldarga, arg);
2151
code.Insert(m + 1, new OpCodeWrapper(OpCodes.Ldind_I8, null));
2156
[Conditional("CHECK_INVARIANTS")]
2157
private void CheckInvariants()
2159
CheckInvariantBranchInOrOutOfBlocks();
2160
CheckInvariantOpCodeUsage();
2161
CheckInvariantLocalVariables();
2164
private void CheckInvariantBranchInOrOutOfBlocks()
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:
2174
* BeginExceptionBlock
2179
* This should be rewritten as:
2184
* BeginExceptionBlock
2190
int nextBlockId = 1;
2191
Stack<int> blocks = new Stack<int>();
2192
for (int i = 0; i < code.Count; i++)
2194
switch (code[i].pseudo)
2196
case CodeType.Label:
2197
code[i].Label.Temp = blockId;
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++;
2207
case CodeType.EndExceptionBlock:
2208
blockId = blocks.Pop();
2212
if (blocks.Count != 0)
2214
throw new InvalidOperationException("Unbalanced exception blocks");
2218
for (int i = 0; i < code.Count; i++)
2220
switch (code[i].pseudo)
2222
case CodeType.OpCode:
2223
if (code[i].HasLabel
2224
&& code[i].opcode != OpCodes.Leave
2225
&& code[i].Label.Temp != blockId)
2228
throw new InvalidOperationException("Invalid branch " + code[i].opcode.Name + " at offset " + i + " from block " + blockId + " to " + code[i].Label.Temp);
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++;
2239
case CodeType.EndExceptionBlock:
2240
blockId = blocks.Pop();
2246
private void CheckInvariantOpCodeUsage()
2248
for (int i = 0; i < code.Count; i++)
2250
switch (code[i].opcode.FlowControl)
2252
case FlowControl.Branch:
2253
case FlowControl.Cond_Branch:
2254
if (!code[i].HasLabel && code[i].opcode != OpCodes.Switch)
2256
throw new InvalidOperationException();
2263
private void CheckInvariantLocalVariables()
2265
List<CodeEmitterLocal> locals = new List<CodeEmitterLocal>();
2266
for (int i = 0; i < code.Count; i++)
2268
if (code[i].pseudo == CodeType.DeclareLocal)
2270
if (locals.Contains(code[i].Local))
2272
throw new InvalidOperationException("Local variable used before declaration");
2275
else if (code[i].HasLocal)
2277
locals.Add(code[i].Local);
2282
private void MoveLocalDeclarationToBeginScope()
2285
for (int i = 0; i < code.Count; i++)
2287
switch (code[i].pseudo)
2289
case CodeType.BeginScope:
2292
case CodeType.DeclareLocal:
2293
OpCodeWrapper decl = code[i];
2295
code.Insert(pos++, decl);
2301
internal void DoEmit()
2304
CLRv4_x64_JIT_Workaround();
2305
RemoveRedundantMemoryBarriers();
2307
if (experimentalOptimizations)
2310
MoveLocalDeclarationToBeginScope();
2312
for (int i = 0; i < 4; i++)
2318
RemoveSingletonBranches();
2320
RemoveUnusedLabels();
2322
SortPseudoOpCodes();
2326
AnnihilateStoreReleaseTempLocals();
2328
DeduplicateBranchSourceTargetCode();
2330
OptimizeStackTransfer();
2332
MergeExceptionBlocks();
2334
ConvertSynchronizedFaultToFinally();
2342
OptimizeEncodings();
2343
OptimizeBranchSizes();
2347
int lineNumber = -1;
2348
for (int i = 0; i < code.Count; i++)
2350
code[i].RealEmit(ilOffset, this, ref lineNumber);
2351
#if STATIC_COMPILER || NET_4_0
2352
ilOffset = ilgen_real.ILOffset;
2354
ilOffset += code[i].Size;
2359
internal void DumpMethod()
2361
Dictionary<CodeEmitterLabel, int> labelIndexes = new Dictionary<CodeEmitterLabel, int>();
2362
for (int i = 0; i < code.Count; i++)
2364
if (code[i].pseudo == CodeType.Label)
2366
labelIndexes.Add(code[i].Label, i);
2369
Console.WriteLine("======================");
2370
for (int i = 0; i < code.Count; i++)
2372
if (code[i].pseudo == CodeType.OpCode)
2374
Console.Write(" " + code[i].opcode.Name);
2375
if (code[i].HasLabel)
2377
Console.Write(" label" + labelIndexes[code[i].Label]);
2379
else if (code[i].opcode == OpCodes.Ldarg)
2381
Console.Write(" " + code[i].ValueInt16);
2383
else if (code[i].opcode == OpCodes.Isinst)
2385
Console.Write(" " + code[i].Type);
2387
else if (code[i].opcode == OpCodes.Call || code[i].opcode == OpCodes.Callvirt)
2389
Console.Write(" " + code[i].MethodBase);
2391
Console.WriteLine();
2393
else if (code[i].pseudo == CodeType.Label)
2395
Console.WriteLine("label{0}: // temp = {1}", i, code[i].Label.Temp);
2399
Console.WriteLine(code[i]);
2404
internal void DefineSymbolDocument(ModuleBuilder module, string url, Guid language, Guid languageVendor, Guid documentType)
2406
symbols = module.DefineDocument(url, language, languageVendor, documentType);
2409
internal CodeEmitterLocal UnsafeAllocTempLocal(Type type)
2412
for (int i = 0; i < tempLocals.Length; i++)
2414
CodeEmitterLocal lb = tempLocals[i];
2422
else if (lb.LocalType == type)
2427
CodeEmitterLocal lb1 = DeclareLocal(type);
2430
tempLocals[free] = lb1;
2435
internal CodeEmitterLocal AllocTempLocal(Type type)
2437
for (int i = 0; i < tempLocals.Length; i++)
2439
CodeEmitterLocal lb = tempLocals[i];
2440
if (lb != null && lb.LocalType == type)
2442
tempLocals[i] = null;
2446
return new CodeEmitterLocal(type);
2449
internal void ReleaseTempLocal(CodeEmitterLocal lb)
2451
EmitPseudoOpCode(CodeType.ReleaseTempLocal, lb);
2452
for (int i = 0; i < tempLocals.Length; i++)
2454
if (tempLocals[i] == null)
2462
internal void BeginCatchBlock(Type exceptionType)
2464
EmitPseudoOpCode(CodeType.BeginCatchBlock, exceptionType);
2467
internal void BeginExceptionBlock()
2469
#if !STATIC_COMPILER
2470
exceptionStack.Push(inFinally);
2473
EmitPseudoOpCode(CodeType.BeginExceptionBlock, null);
2476
internal void BeginFaultBlock()
2478
#if !STATIC_COMPILER
2481
EmitPseudoOpCode(CodeType.BeginFaultBlock, null);
2484
internal void BeginFinallyBlock()
2486
#if !STATIC_COMPILER
2489
EmitPseudoOpCode(CodeType.BeginFinallyBlock, null);
2492
internal void BeginScope()
2494
EmitPseudoOpCode(CodeType.BeginScope, null);
2497
internal CodeEmitterLocal DeclareLocal(Type localType)
2499
CodeEmitterLocal local = new CodeEmitterLocal(localType);
2500
EmitPseudoOpCode(CodeType.DeclareLocal, local);
2504
internal CodeEmitterLabel DefineLabel()
2506
CodeEmitterLabel label = new CodeEmitterLabel(ilgen_real.DefineLabel());
2508
labels.Add(label, new System.Diagnostics.StackFrame(1, true));
2513
internal void Emit(OpCode opcode)
2515
EmitOpCode(opcode, null);
2518
internal void EmitUnaligned(byte alignment)
2520
EmitOpCode(OpCodes.Unaligned, alignment);
2523
internal void Emit(OpCode opcode, MethodBase mb)
2525
EmitOpCode(opcode, mb);
2528
internal void EmitLdc_R8(double arg)
2530
EmitOpCode(OpCodes.Ldc_R8, arg);
2533
internal void Emit(OpCode opcode, FieldInfo field)
2535
EmitOpCode(opcode, field);
2538
internal void EmitLdarg(int arg)
2540
Debug.Assert(0 <= arg && arg < 65536);
2544
EmitOpCode(OpCodes.Ldarg_0, null);
2547
EmitOpCode(OpCodes.Ldarg_1, null);
2550
EmitOpCode(OpCodes.Ldarg_2, null);
2553
EmitOpCode(OpCodes.Ldarg_3, null);
2558
EmitOpCode(OpCodes.Ldarg_S, (byte)arg);
2562
EmitOpCode(OpCodes.Ldarg, (short)arg);
2568
internal void EmitLdarga(int arg)
2570
Debug.Assert(0 <= arg && arg < 65536);
2573
EmitOpCode(OpCodes.Ldarga_S, (byte)arg);
2577
EmitOpCode(OpCodes.Ldarga, (short)arg);
2581
internal void EmitStarg(int arg)
2583
Debug.Assert(0 <= arg && arg < 65536);
2586
EmitOpCode(OpCodes.Starg_S, (byte)arg);
2590
EmitOpCode(OpCodes.Starg, (short)arg);
2594
internal void EmitLdc_I8(long arg)
2596
EmitOpCode(OpCodes.Ldc_I8, arg);
2599
internal void EmitBr(CodeEmitterLabel label)
2601
EmitOpCode(OpCodes.Br, label);
2604
internal void EmitBeq(CodeEmitterLabel label)
2606
EmitOpCode(OpCodes.Beq, label);
2609
internal void EmitBne_Un(CodeEmitterLabel label)
2611
EmitOpCode(OpCodes.Bne_Un, label);
2614
internal void EmitBle_Un(CodeEmitterLabel label)
2616
EmitOpCode(OpCodes.Ble_Un, label);
2619
internal void EmitBlt_Un(CodeEmitterLabel label)
2621
EmitOpCode(OpCodes.Blt_Un, label);
2624
internal void EmitBge_Un(CodeEmitterLabel label)
2626
EmitOpCode(OpCodes.Bge_Un, label);
2629
internal void EmitBle(CodeEmitterLabel label)
2631
EmitOpCode(OpCodes.Ble, label);
2634
internal void EmitBlt(CodeEmitterLabel label)
2636
EmitOpCode(OpCodes.Blt, label);
2639
internal void EmitBge(CodeEmitterLabel label)
2641
EmitOpCode(OpCodes.Bge, label);
2644
internal void EmitBgt(CodeEmitterLabel label)
2646
EmitOpCode(OpCodes.Bgt, label);
2649
internal void EmitBrtrue(CodeEmitterLabel label)
2651
EmitOpCode(OpCodes.Brtrue, label);
2654
internal void EmitBrfalse(CodeEmitterLabel label)
2656
EmitOpCode(OpCodes.Brfalse, label);
2659
internal void EmitLeave(CodeEmitterLabel label)
2661
EmitOpCode(OpCodes.Leave, label);
2664
internal void EmitSwitch(CodeEmitterLabel[] labels)
2666
EmitOpCode(OpCodes.Switch, labels);
2669
internal void Emit(OpCode opcode, CodeEmitterLocal local)
2671
EmitOpCode(opcode, local);
2674
internal void EmitLdc_R4(float arg)
2676
EmitOpCode(OpCodes.Ldc_R4, arg);
2679
internal void Emit(OpCode opcode, string arg)
2681
EmitOpCode(opcode, arg);
2684
internal void Emit(OpCode opcode, Type cls)
2686
EmitOpCode(opcode, cls);
2689
internal void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
2691
EmitOpCode(opcode, new CalliWrapper(unmanagedCallConv, returnType, parameterTypes));
2694
internal void EndExceptionBlock()
2697
EmitPseudoOpCode(CodeType.EndExceptionBlock, null);
2699
EmitPseudoOpCode(CodeType.EndExceptionBlock, inFinally ? CodeTypeFlags.EndFaultOrFinally : CodeTypeFlags.None);
2700
inFinally = exceptionStack.Pop();
2704
internal void EndScope()
2706
EmitPseudoOpCode(CodeType.EndScope, null);
2709
internal void MarkLabel(CodeEmitterLabel loc)
2714
EmitPseudoOpCode(CodeType.Label, loc);
2717
internal void ThrowException(Type excType)
2719
Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
2720
Emit(OpCodes.Throw);
2723
internal void SetLineNumber(ushort line)
2725
if (symbols != null)
2727
EmitPseudoOpCode(CodeType.SequencePoint, (int)line);
2729
EmitPseudoOpCode(CodeType.LineNumber, (int)line);
2732
internal byte[] GetLineNumberTable()
2734
return linenums == null ? null : linenums.ToArray();
2738
internal void EmitLineNumberTable(MethodBuilder mb)
2740
if(linenums != null)
2742
AttributeHelper.SetLineNumberTable(mb, linenums);
2745
#endif // STATIC_COMPILER
2747
internal void EmitThrow(string dottedClassName)
2749
TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dottedClassName);
2750
MethodWrapper mw = exception.GetMethodWrapper("<init>", "()V", false);
2752
mw.EmitNewobj(this);
2753
Emit(OpCodes.Throw);
2756
internal void EmitThrow(string dottedClassName, string message)
2758
TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dottedClassName);
2759
Emit(OpCodes.Ldstr, message);
2760
MethodWrapper mw = exception.GetMethodWrapper("<init>", "(Ljava.lang.String;)V", false);
2762
mw.EmitNewobj(this);
2763
Emit(OpCodes.Throw);
2766
internal void EmitNullCheck()
2768
// I think this is the most efficient way to generate a NullReferenceException if the reference is null
2769
Emit(OpCodes.Ldvirtftn, objectToString);
2773
internal void EmitCastclass(Type type)
2775
if (verboseCastFailure != null)
2777
CodeEmitterLocal lb = DeclareLocal(Types.Object);
2778
Emit(OpCodes.Stloc, lb);
2779
Emit(OpCodes.Ldloc, lb);
2780
Emit(OpCodes.Isinst, type);
2782
CodeEmitterLabel ok = DefineLabel();
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);
2793
Emit(OpCodes.Castclass, type);
2797
// This is basically the same as Castclass, except that it
2798
// throws an IncompatibleClassChangeError on failure.
2799
internal void EmitAssertType(Type type)
2801
CodeEmitterLabel isnull = DefineLabel();
2803
EmitBrfalse(isnull);
2804
Emit(OpCodes.Isinst, type);
2806
CodeEmitterLabel ok = DefineLabel();
2808
EmitThrow("java.lang.IncompatibleClassChangeError");
2811
Emit(OpCodes.Ldnull);
2815
internal void EmitUnboxSpecial(Type type)
2817
// NOTE if the reference is null, we treat it as a default instance of the value type.
2819
CodeEmitterLabel label1 = DefineLabel();
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();
2830
Emit(OpCodes.Unbox, type);
2831
Emit(OpCodes.Ldobj, type);
2835
internal void EmitLdc_I4(int i)
2837
EmitOpCode(OpCodes.Ldc_I4, i);
2840
internal void Emit_idiv()
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
2846
Emit(OpCodes.Ldc_I4_M1);
2847
CodeEmitterLabel label = DefineLabel();
2851
CodeEmitterLabel label2 = DefineLabel();
2858
internal void Emit_ldiv()
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
2864
Emit(OpCodes.Ldc_I4_M1);
2865
Emit(OpCodes.Conv_I8);
2866
CodeEmitterLabel label = DefineLabel();
2870
CodeEmitterLabel label2 = DefineLabel();
2877
internal void Emit_instanceof(Type type)
2879
Emit(OpCodes.Isinst, type);
2880
Emit(OpCodes.Ldnull);
2881
Emit(OpCodes.Cgt_Un);
2884
internal enum Comparison
2892
internal void Emit_if_le_lt_ge_gt(Comparison comp, CodeEmitterLabel label)
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);
2899
case Comparison.LessOrEqual:
2902
case Comparison.LessThan:
2905
case Comparison.GreaterOrEqual:
2908
case Comparison.GreaterThan:
2914
private void EmitCmp(Type type, OpCode cmp1, OpCode cmp2)
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);
2923
Emit(OpCodes.Ldloc, value1);
2924
Emit(OpCodes.Ldloc, value2);
2927
ReleaseTempLocal(value2);
2928
ReleaseTempLocal(value1);
2931
internal void Emit_lcmp()
2933
EmitCmp(Types.Int64, OpCodes.Cgt, OpCodes.Clt);
2936
internal void Emit_fcmpl()
2938
EmitCmp(Types.Single, OpCodes.Cgt, OpCodes.Clt_Un);
2941
internal void Emit_fcmpg()
2943
EmitCmp(Types.Single, OpCodes.Cgt_Un, OpCodes.Clt);
2946
internal void Emit_dcmpl()
2948
EmitCmp(Types.Double, OpCodes.Cgt, OpCodes.Clt_Un);
2951
internal void Emit_dcmpg()
2953
EmitCmp(Types.Double, OpCodes.Cgt_Un, OpCodes.Clt);
2956
internal void Emit_And_I4(int v)
2962
internal void CheckLabels()
2965
foreach(System.Diagnostics.StackFrame frame in labels.Values)
2967
string name = frame.GetFileName() + ":" + frame.GetFileLineNumber();
2968
IKVM.Internal.JVM.CriticalFailure("Label failure: " + name, null);
2973
internal void EmitMemoryBarrier()
2975
EmitPseudoOpCode(CodeType.MemoryBarrier, null);
2978
internal void EmitTailCallPrevention()
2980
EmitPseudoOpCode(CodeType.TailCallPrevention, null);
2983
internal void EmitClearStack()
2985
EmitPseudoOpCode(CodeType.ClearStack, null);
2988
internal void EmitMonitorEnter()
2990
EmitPseudoOpCode(CodeType.MonitorEnter, null);
2993
internal void EmitMonitorExit()
2995
EmitPseudoOpCode(CodeType.MonitorExit, null);