106 ILGenerator ilgen_real;
108 Stack<bool> exceptionStack =
new Stack<bool>();
111 ISymbolDocumentWriter symbols;
112 List<OpCodeWrapper> code =
new List<OpCodeWrapper>(10);
113 readonly
Type declaringType;
115 enum CodeType :
short
140 enum CodeTypeFlags :
short
143 EndFaultOrFinally = 1,
149 internal readonly CodeType pseudo;
150 readonly CodeTypeFlags flags;
151 internal readonly OpCode opcode;
152 readonly
object data;
159 internal OpCodeWrapper(CodeType pseudo,
object data)
161 this.pseudo = pseudo;
162 this.flags = CodeTypeFlags.None;
163 this.opcode = OpCodes.Nop;
172 internal OpCodeWrapper(CodeType pseudo, CodeTypeFlags flags)
174 this.pseudo = pseudo;
176 this.opcode = OpCodes.Nop;
185 internal OpCodeWrapper(OpCode opcode,
object data)
187 this.pseudo = CodeType.OpCode;
188 this.flags = CodeTypeFlags.None;
189 this.opcode = opcode;
193 internal bool Match(OpCodeWrapper other) => other.pseudo == pseudo && other.opcode == opcode && (other.data == data || (data !=
null && data.Equals(other.data)));
199 internal bool MatchLabel(OpCodeWrapper other) => data == other.data;
207 internal bool MatchLocal(OpCodeWrapper other) => data == other.data;
209 internal bool HasValueByte => data is byte;
211 internal byte ValueByte => (byte)data;
213 internal short ValueInt16 => (short)data;
215 internal int ValueInt32 => (int)data;
217 internal long ValueInt64 => (long)data;
225 internal void RealEmit(
int ilOffset,
CodeEmitter codeEmitter,
ref int lineNumber)
227 if (pseudo == CodeType.OpCode)
229 if (lineNumber != -1)
232 codeEmitter.linenums.AddMapping(ilOffset, lineNumber);
236 codeEmitter.RealEmitOpCode(opcode, data);
238 else if (pseudo == CodeType.LineNumber)
240 lineNumber = (int)data;
244 codeEmitter.RealEmitPseudoOpCode(ilOffset, pseudo, data);
249 public override readonly
string ToString() => pseudo == CodeType.OpCode ? opcode.ToString() +
" " + data : pseudo.ToString() +
" " + data;
253 sealed class CalliWrapper
257 internal readonly
Type returnType;
258 internal readonly
Type[] parameterTypes;
262 this.unmanagedCallConv = unmanagedCallConv;
263 this.returnType = returnType;
264 this.parameterTypes = parameterTypes ==
null ? null : (
Type[])parameterTypes.Clone();
269 sealed class ManagedCalliWrapper
272 internal readonly CallingConventions callConv;
273 internal readonly
Type returnType;
274 internal readonly
Type[] parameterTypes;
275 internal readonly
Type[] optionalParameterTypes;
277 internal ManagedCalliWrapper(CallingConventions callConv,
Type returnType,
Type[] parameterTypes,
Type[] optionalParameterTypes)
279 this.callConv = callConv;
280 this.returnType = returnType;
281 this.parameterTypes = parameterTypes ==
null ? null : (
Type[])parameterTypes.Clone();
282 this.optionalParameterTypes = optionalParameterTypes ==
null ? null : (
Type[])optionalParameterTypes.Clone();
295 this.context = context;
296 this.ilgen_real = ilgen;
297 this.declaringType = declaringType;
305 private void EmitPseudoOpCode(CodeType type,
object data)
307 code.Add(
new OpCodeWrapper(type, data));
310 private void EmitOpCode(OpCode opcode,
object arg)
312 code.Add(
new OpCodeWrapper(opcode, arg));
315 private void RealEmitPseudoOpCode(
int ilOffset, CodeType type,
object data)
319 case CodeType.Unreachable:
321 case CodeType.BeginScope:
322 ilgen_real.BeginScope();
324 case CodeType.EndScope:
325 ilgen_real.EndScope();
327 case CodeType.DeclareLocal:
328 ((CodeEmitterLocal)data).Declare(ilgen_real);
330 case CodeType.ReleaseTempLocal:
332 case CodeType.SequencePoint:
334#if NETFRAMEWORK || IMPORTER
336 ilgen_real.MarkSequencePoint(symbols, (
int)data, 0, (
int)data + 1, 0);
339 ilgen_real.Emit(OpCodes.Nop);
342 ilgen_real.MarkLabel(((CodeEmitterLabel)data).Label);
344 case CodeType.BeginExceptionBlock:
345 ilgen_real.BeginExceptionBlock();
347 case CodeType.BeginCatchBlock:
348 ilgen_real.BeginCatchBlock((
Type)data);
350 case CodeType.BeginFaultBlock:
351 ilgen_real.BeginFaultBlock();
353 case CodeType.BeginFinallyBlock:
354 ilgen_real.BeginFinallyBlock();
356 case CodeType.EndExceptionBlock:
357 ilgen_real.EndExceptionBlock();
358 ilgen_real.Emit(OpCodes.Br_S, (sbyte)-2);
360 case CodeType.MemoryBarrier:
361 ilgen_real.Emit(OpCodes.Call, context.CodeEmitterFactory.MemoryBarrierMethod);
363 case CodeType.MonitorEnter:
364 ilgen_real.Emit(OpCodes.Call, context.CodeEmitterFactory.MonitorEnterMethod);
366 case CodeType.MonitorExit:
367 ilgen_real.Emit(OpCodes.Call, context.CodeEmitterFactory.MonitorExitMethod);
369 case CodeType.TailCallPrevention:
370 ilgen_real.Emit(OpCodes.Ldnull);
371 ilgen_real.Emit(OpCodes.Pop);
373 case CodeType.ClearStack:
374 ilgen_real.Emit(OpCodes.Leave_S, (
byte)0);
377 throw new InvalidOperationException();
387 void RealEmitOpCode(OpCode opcode,
object arg)
391 ilgen_real.Emit(opcode);
393 else if (arg is
int ina)
395 ilgen_real.Emit(opcode, ina);
397 else if (arg is
long l)
399 ilgen_real.Emit(opcode, l);
403 ilgen_real.Emit(opcode, mi);
407 ilgen_real.Emit(opcode, ci);
411 ilgen_real.Emit(opcode, fi);
413 else if (arg is sbyte sby)
415 ilgen_real.Emit(opcode, sby);
417 else if (arg is
byte by)
419 ilgen_real.Emit(opcode, by);
421 else if (arg is
short sh)
423 ilgen_real.Emit(opcode, sh);
425 else if (arg is
float f)
427 ilgen_real.Emit(opcode, f);
429 else if (arg is
double d)
431 ilgen_real.Emit(opcode, d);
433 else if (arg is
string s)
435 ilgen_real.Emit(opcode, s);
437 else if (arg is
Type type)
439 ilgen_real.Emit(opcode, type);
441 else if (arg is CodeEmitterLocal local)
443 local.Emit(ilgen_real, opcode);
445 else if (arg is CodeEmitterLabel label)
447 ilgen_real.Emit(opcode, label.Label);
449 else if (arg is CodeEmitterLabel[] labels)
451 var real =
new Label[labels.Length];
452 for (
int i = 0; i < labels.Length; i++)
453 real[i] = labels[i].Label;
455 ilgen_real.Emit(opcode, real);
457 else if (arg is ManagedCalliWrapper margs)
459 ilgen_real.EmitCalli(opcode, margs.callConv, margs.returnType, margs.parameterTypes, margs.optionalParameterTypes);
461 else if (arg is CalliWrapper args)
463 ilgen_real.EmitCalli(opcode, args.unmanagedCallConv, args.returnType, args.parameterTypes);
467 throw new InvalidOperationException();
471 void RemoveJumpNext()
473 for (
int i = 1; i < code.Count; i++)
475 if (code[i].pseudo == CodeType.Label)
477 if (code[i - 1].opcode == OpCodes.Br
478 && code[i - 1].MatchLabel(code[i]))
480 code.RemoveAt(i - 1);
484 && code[i - 1].pseudo == CodeType.LineNumber
485 && code[i - 2].opcode == OpCodes.Br
486 && code[i - 2].MatchLabel(code[i]))
488 code.RemoveAt(i - 2);
495 void AnnihilateStoreReleaseTempLocals()
497 for (
int i = 1; i < code.Count; i++)
499 if (code[i].opcode == OpCodes.Stloc)
501 if (code[i + 1].pseudo == CodeType.ReleaseTempLocal && code[i].Local == code[i + 1].Local)
503 code[i] =
new OpCodeWrapper(OpCodes.Pop,
null);
505 else if (code[i + 1].opcode == OpCodes.Ldloc && code[i + 1].Local == code[i].Local && code[i + 2].pseudo == CodeType.ReleaseTempLocal && code[i + 2].Local == code[i].Local)
507 code.RemoveRange(i, 2);
513 void AnnihilatePops()
515 for (
int i = 1; i < code.Count; i++)
517 if (code[i].opcode == OpCodes.Pop)
521 for (
int j = i - 1; j >= 0; j--)
523 if (IsSideEffectFreePush(j))
534 else if (code[j].opcode == OpCodes.Stloc)
538 else if (code[j].opcode == OpCodes.Shl || code[j].opcode == OpCodes.And || code[j].opcode == OpCodes.Add || code[j].opcode == OpCodes.Sub)
545 else if (code[j].opcode == OpCodes.Conv_Ovf_I4
546 || code[j].opcode == OpCodes.Conv_I8
547 || code[j].opcode == OpCodes.Ldlen)
569 bool IsSideEffectFreePush(
int index)
571 if (code[index].opcode == OpCodes.Ldstr)
575 else if (code[index].opcode == OpCodes.Ldnull)
579 else if (code[index].opcode == OpCodes.Ldsfld)
581 var field = code[index].FieldInfo;
588 if ((field.DeclaringType.Attributes & TypeAttributes.BeforeFieldInit) != 0)
594 if (field.DeclaringType == declaringType)
601 else if (code[index].opcode == OpCodes.Ldc_I4)
605 else if (code[index].opcode == OpCodes.Ldc_I8)
609 else if (code[index].opcode == OpCodes.Ldc_R4)
613 else if (code[index].opcode == OpCodes.Ldc_R8)
617 else if (code[index].opcode == OpCodes.Ldloc)
621 else if (code[index].opcode == OpCodes.Ldarg)
625 else if (code[index].opcode == OpCodes.Ldarg_S)
629 else if (code[index].opcode == OpCodes.Ldarg_0)
633 else if (code[index].opcode == OpCodes.Ldarg_1)
637 else if (code[index].opcode == OpCodes.Ldarg_2)
641 else if (code[index].opcode == OpCodes.Ldarg_3)
651 void OptimizePatterns()
654 for (
int i = 1; i < code.Count; i++)
656 if (code[i].opcode == OpCodes.Isinst
657 && code[i + 1].opcode == OpCodes.Ldnull
658 && code[i + 2].opcode == OpCodes.Cgt_Un
659 && (code[i + 3].opcode == OpCodes.Brfalse || code[i + 3].opcode == OpCodes.Brtrue))
661 code.RemoveRange(i + 1, 2);
663 else if (code[i].opcode == OpCodes.Ldelem_I1
664 && code[i + 1].opcode == OpCodes.Ldc_I4 && code[i + 1].ValueInt32 == 255
665 && code[i + 2].opcode == OpCodes.And)
667 code[i] =
new OpCodeWrapper(OpCodes.Ldelem_U1,
null);
668 code.RemoveRange(i + 1, 2);
670 else if (code[i].opcode == OpCodes.Ldelem_I1
671 && code[i + 1].opcode == OpCodes.Conv_I8
672 && code[i + 2].opcode == OpCodes.Ldc_I8 && code[i + 2].ValueInt64 == 255
673 && code[i + 3].opcode == OpCodes.And)
675 code[i] =
new OpCodeWrapper(OpCodes.Ldelem_U1,
null);
676 code.RemoveRange(i + 2, 2);
678 else if (code[i].opcode == OpCodes.Ldc_I4
679 && code[i + 1].opcode == OpCodes.Ldc_I4
680 && code[i + 2].opcode == OpCodes.And)
682 code[i] =
new OpCodeWrapper(OpCodes.Ldc_I4, code[i].ValueInt32 & code[i + 1].ValueInt32);
683 code.RemoveRange(i + 1, 2);
685 else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, context.Types.Double)
686 || MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, context.Types.Single))
688 PatchCompare(i, OpCodes.Ble_Un, OpCodes.Blt_Un, OpCodes.Bge, OpCodes.Bgt);
690 else if (MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, context.Types.Double)
691 || MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, context.Types.Single))
693 PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge_Un, OpCodes.Bgt_Un);
695 else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt, context.Types.Int64))
697 PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge, OpCodes.Bgt);
699 else if (i < code.Count - 10
700 && code[i].opcode == OpCodes.Ldc_I4
701 && code[i + 1].opcode == OpCodes.Dup
702 && code[i + 2].opcode == OpCodes.Ldc_I4_M1
703 && code[i + 3].opcode == OpCodes.Bne_Un
704 && code[i + 4].opcode == OpCodes.Pop
705 && code[i + 5].opcode == OpCodes.Neg
706 && code[i + 6].opcode == OpCodes.Br
707 && code[i + 7].pseudo == CodeType.Label && code[i + 7].MatchLabel(code[i + 3]) && code[i + 7].Label.Temp == 1
708 && code[i + 8].opcode == OpCodes.Div
709 && code[i + 9].pseudo == CodeType.Label && code[i + 9].Label == code[i + 6].Label && code[i + 9].Label.Temp == 1)
711 int divisor = code[i].ValueInt32;
714 code[i] = code[i + 5];
715 code.RemoveRange(i + 1, 9);
719 code[i + 1] = code[i + 8];
720 code.RemoveRange(i + 2, 8);
723 else if (i < code.Count - 11
724 && code[i].opcode == OpCodes.Ldc_I8
725 && code[i + 1].opcode == OpCodes.Dup
726 && code[i + 2].opcode == OpCodes.Ldc_I4_M1
727 && code[i + 3].opcode == OpCodes.Conv_I8
728 && code[i + 4].opcode == OpCodes.Bne_Un
729 && code[i + 5].opcode == OpCodes.Pop
730 && code[i + 6].opcode == OpCodes.Neg
731 && code[i + 7].opcode == OpCodes.Br
732 && code[i + 8].pseudo == CodeType.Label && code[i + 8].MatchLabel(code[i + 4]) && code[i + 8].Label.Temp == 1
733 && code[i + 9].opcode == OpCodes.Div
734 && code[i + 10].pseudo == CodeType.Label && code[i + 10].MatchLabel(code[i + 7]) && code[i + 10].Label.Temp == 1)
736 long divisor = code[i].ValueInt64;
739 code[i] = code[i + 6];
740 code.RemoveRange(i + 1, 10);
744 code[i + 1] = code[i + 9];
745 code.RemoveRange(i + 2, 9);
748 else if (code[i].opcode == OpCodes.Box
749 && code[i + 1].opcode == OpCodes.Unbox && code[i + 1].Type == code[i].Type)
751 CodeEmitterLocal local =
new CodeEmitterLocal(code[i].
Type);
752 code[i] =
new OpCodeWrapper(OpCodes.Stloc, local);
753 code[i + 1] =
new OpCodeWrapper(OpCodes.Ldloca, local);
755 else if (i < code.Count - 13
756 && code[i + 0].opcode == OpCodes.Box
757 && code[i + 1].opcode == OpCodes.Dup
758 && code[i + 2].opcode == OpCodes.Brtrue
759 && code[i + 3].opcode == OpCodes.Pop
760 && code[i + 4].opcode == OpCodes.Ldloca && code[i + 4].Local.LocalType == code[i + 0].Type
761 && code[i + 5].opcode == OpCodes.Initobj && code[i + 5].Type == code[i + 0].Type
762 && code[i + 6].opcode == OpCodes.Ldloc && code[i + 6].Local == code[i + 4].Local
763 && code[i + 7].pseudo == CodeType.ReleaseTempLocal && code[i + 7].Local == code[i + 6].Local
764 && code[i + 8].opcode == OpCodes.Br
765 && code[i + 9].pseudo == CodeType.Label && code[i + 9].MatchLabel(code[i + 2]) && code[i + 9].Label.Temp == 1
766 && code[i + 10].opcode == OpCodes.Unbox && code[i + 10].Type == code[i + 0].Type
767 && code[i + 11].opcode == OpCodes.Ldobj && code[i + 11].Type == code[i + 0].Type
768 && code[i + 12].pseudo == CodeType.Label && code[i + 12].MatchLabel(code[i + 8]) && code[i + 12].Label.Temp == 1)
770 code.RemoveRange(i, 13);
774 if (i < code.Count - 6
775 && code[i].opcode.FlowControl == FlowControl.Cond_Branch
776 && code[i + 1].opcode == OpCodes.Ldc_I4 && code[i + 1].ValueInt32 == 1
777 && code[i + 2].opcode == OpCodes.Br
778 && code[i + 3].pseudo == CodeType.Label && code[i + 3].MatchLabel(code[i]) && code[i + 3].Label.Temp == 1
779 && code[i + 4].opcode == OpCodes.Ldc_I4 && code[i + 4].ValueInt32 == 0
780 && code[i + 5].pseudo == CodeType.Label && code[i + 5].MatchLabel(code[i + 2]) && code[i + 5].Label.Temp == 1)
782 if (code[i].opcode == OpCodes.Bne_Un)
784 code[i] =
new OpCodeWrapper(OpCodes.Ceq,
null);
785 code.RemoveRange(i + 1, 5);
787 else if (code[i].opcode == OpCodes.Beq)
789 code[i + 0] =
new OpCodeWrapper(OpCodes.Ceq,
null);
790 code[i + 1] =
new OpCodeWrapper(OpCodes.Ldc_I4, 0);
791 code[i + 2] =
new OpCodeWrapper(OpCodes.Ceq,
null);
792 code.RemoveRange(i + 3, 3);
794 else if (code[i].opcode == OpCodes.Ble || code[i].opcode == OpCodes.Ble_Un)
796 code[i] =
new OpCodeWrapper(OpCodes.Cgt,
null);
797 code.RemoveRange(i + 1, 5);
799 else if (code[i].opcode == OpCodes.Blt)
801 code[i] =
new OpCodeWrapper(OpCodes.Clt,
null);
802 code[i + 1] =
new OpCodeWrapper(OpCodes.Ldc_I4, 0);
803 code[i + 2] =
new OpCodeWrapper(OpCodes.Ceq,
null);
804 code.RemoveRange(i + 3, 3);
806 else if (code[i].opcode == OpCodes.Blt_Un)
808 code[i] =
new OpCodeWrapper(OpCodes.Clt_Un,
null);
809 code[i + 1] =
new OpCodeWrapper(OpCodes.Ldc_I4, 0);
810 code[i + 2] =
new OpCodeWrapper(OpCodes.Ceq,
null);
811 code.RemoveRange(i + 3, 3);
813 else if (code[i].opcode == OpCodes.Bge || code[i].opcode == OpCodes.Bge_Un)
815 code[i] =
new OpCodeWrapper(OpCodes.Clt,
null);
816 code.RemoveRange(i + 1, 5);
818 else if (code[i].opcode == OpCodes.Bgt)
820 code[i] =
new OpCodeWrapper(OpCodes.Cgt,
null);
821 code[i + 1] =
new OpCodeWrapper(OpCodes.Ldc_I4, 0);
822 code[i + 2] =
new OpCodeWrapper(OpCodes.Ceq,
null);
823 code.RemoveRange(i + 3, 3);
825 else if (code[i].opcode == OpCodes.Bgt_Un)
827 code[i] =
new OpCodeWrapper(OpCodes.Cgt_Un,
null);
828 code[i + 1] =
new OpCodeWrapper(OpCodes.Ldc_I4, 0);
829 code[i + 2] =
new OpCodeWrapper(OpCodes.Ceq,
null);
830 code.RemoveRange(i + 3, 3);
836 bool MatchCompare(
int index, OpCode cmp1, OpCode cmp2,
Type type)
838 return code[index].opcode == OpCodes.Stloc && code[index].Local.LocalType == type
839 && code[index + 1].opcode == OpCodes.Stloc && code[index + 1].Local.LocalType == type
840 && code[index + 2].opcode == OpCodes.Ldloc && code[index + 2].MatchLocal(code[index + 1])
841 && code[index + 3].opcode == OpCodes.Ldloc && code[index + 3].MatchLocal(code[index])
842 && code[index + 4].opcode == cmp1
843 && code[index + 5].opcode == OpCodes.Ldloc && code[index + 5].MatchLocal(code[index + 1])
844 && code[index + 6].opcode == OpCodes.Ldloc && code[index + 6].MatchLocal(code[index])
845 && code[index + 7].opcode == cmp2
846 && code[index + 8].opcode == OpCodes.Sub
847 && code[index + 9].pseudo == CodeType.ReleaseTempLocal && code[index + 9].Local == code[index].Local
848 && code[index + 10].pseudo == CodeType.ReleaseTempLocal && code[index + 10].Local == code[index + 1].Local
849 && ((code[index + 11].opcode.FlowControl == FlowControl.Cond_Branch && code[index + 11].HasLabel) ||
850 (code[index + 11].opcode == OpCodes.Ldc_I4_0
851 && (code[index + 12].opcode.FlowControl == FlowControl.Cond_Branch && code[index + 12].HasLabel)));
854 void PatchCompare(
int index, OpCode ble, OpCode blt, OpCode bge, OpCode bgt)
856 if (code[index + 11].opcode == OpCodes.Brtrue)
858 code[index] =
new OpCodeWrapper(OpCodes.Bne_Un, code[index + 11].Label);
859 code.RemoveRange(index + 1, 11);
861 else if (code[index + 11].opcode == OpCodes.Brfalse)
863 code[index] =
new OpCodeWrapper(OpCodes.Beq, code[index + 11].Label);
864 code.RemoveRange(index + 1, 11);
866 else if (code[index + 11].opcode == OpCodes.Ldc_I4_0)
868 if (code[index + 12].opcode == OpCodes.Ble)
870 code[index] =
new OpCodeWrapper(ble, code[index + 12].Label);
871 code.RemoveRange(index + 1, 12);
873 else if (code[index + 12].opcode == OpCodes.Blt)
875 code[index] =
new OpCodeWrapper(blt, code[index + 12].Label);
876 code.RemoveRange(index + 1, 12);
878 else if (code[index + 12].opcode == OpCodes.Bge)
880 code[index] =
new OpCodeWrapper(bge, code[index + 12].Label);
881 code.RemoveRange(index + 1, 12);
883 else if (code[index + 12].opcode == OpCodes.Bgt)
885 code[index] =
new OpCodeWrapper(bgt, code[index + 12].Label);
886 code.RemoveRange(index + 1, 12);
894 void OptimizeEncodings()
896 for (
int i = 0; i < code.Count; i++)
898 if (code[i].opcode == OpCodes.Ldc_I4)
899 code[i] = OptimizeLdcI4(code[i].ValueInt32);
900 else if (code[i].opcode == OpCodes.Ldc_I8)
910 OpCodeWrapper OptimizeLdcI4(
int value)
915 return new OpCodeWrapper(OpCodes.Ldc_I4_M1,
null);
917 return new OpCodeWrapper(OpCodes.Ldc_I4_0,
null);
919 return new OpCodeWrapper(OpCodes.Ldc_I4_1,
null);
921 return new OpCodeWrapper(OpCodes.Ldc_I4_2,
null);
923 return new OpCodeWrapper(OpCodes.Ldc_I4_3,
null);
925 return new OpCodeWrapper(OpCodes.Ldc_I4_4,
null);
927 return new OpCodeWrapper(OpCodes.Ldc_I4_5,
null);
929 return new OpCodeWrapper(OpCodes.Ldc_I4_6,
null);
931 return new OpCodeWrapper(OpCodes.Ldc_I4_7,
null);
933 return new OpCodeWrapper(OpCodes.Ldc_I4_8,
null);
935 if (value >= -128 && value <= 127)
936 return new OpCodeWrapper(OpCodes.Ldc_I4_S, (sbyte)value);
938 return new OpCodeWrapper(OpCodes.Ldc_I4, value);
946 void OptimizeLdcI8(
int index)
948 var value = code[index].ValueInt64;
949 if (value >=
int.MinValue && value <= uint.MaxValue)
951 code[index] = OptimizeLdcI4((
int)value);
952 code.Insert(index + 1,
new OpCodeWrapper(value < 0 ? OpCodes.Conv_I8 : OpCodes.Conv_U8,
null));
956 private void ChaseBranches()
966 for (
int i = 0; i < code.Count; i++)
968 if (code[i].opcode == OpCodes.Br)
970 int target = code[i].Label.Temp + 1;
971 if (code[target].pseudo == CodeType.LineNumber)
976 if (code[target].opcode == OpCodes.Endfinally || code[target].opcode == OpCodes.Ret)
978 code[i] = code[target];
982 CodeEmitterLabel label =
null;
983 while (code[target].opcode == OpCodes.Br && target != i)
985 label = code[target].Label;
986 target = code[target].Label.Temp + 1;
990 code[i] =
new OpCodeWrapper(OpCodes.Br, label);
994 else if (code[i].opcode == OpCodes.Leave)
996 int target = code[i].Label.Temp + 1;
997 CodeEmitterLabel label =
null;
998 while ((code[target].opcode == OpCodes.Br || code[target].opcode == OpCodes.Leave) && target != i)
1000 label = code[target].Label;
1001 target = code[target].Label.Temp + 1;
1005 code[i] =
new OpCodeWrapper(OpCodes.Leave, label);
1011 private void RemoveSingletonBranches()
1017 SetLabelRefCounts();
1019 bool reachable =
true;
1020 for (
int i = 0; i < code.Count; i++)
1024 switch (code[i].pseudo)
1026 case CodeType.Label:
1027 code[i].Label.Temp++;
1029 case CodeType.BeginCatchBlock:
1030 case CodeType.BeginFaultBlock:
1031 case CodeType.BeginFinallyBlock:
1032 case CodeType.EndExceptionBlock:
1033 throw new InvalidOperationException();
1034 case CodeType.OpCode:
1035 switch (code[i].opcode.FlowControl)
1037 case FlowControl.Branch:
1038 case FlowControl.Return:
1039 case FlowControl.Throw:
1048 switch (code[i].pseudo)
1050 case CodeType.Label:
1051 reachable = code[i].Label.Temp > 0;
1053 case CodeType.BeginCatchBlock:
1054 case CodeType.BeginFaultBlock:
1055 case CodeType.BeginFinallyBlock:
1063 for (
int i = 0; i < code.Count; i++)
1065 if (code[i].opcode == OpCodes.Br && code[i].Label.Temp == 1)
1067 int target = FindLabel(code[i].Label) + 1;
1068 for (
int j = target; j < code.Count; j++)
1070 switch (code[j].pseudo)
1072 case CodeType.OpCode:
1073 if (code[j].HasLocal && FindLocal(code[j].Local) > i)
1078 switch (code[j].opcode.FlowControl)
1080 case FlowControl.Branch:
1081 case FlowControl.Return:
1082 case FlowControl.Throw:
1084 List<OpCodeWrapper> range = code.GetRange(target, j - target + 1);
1088 code.InsertRange(i, range);
1089 code.RemoveRange(target - 1, range.Count + 1);
1090 i -= range.Count + 1;
1094 code.RemoveRange(target - 1, range.Count + 1);
1096 code.InsertRange(i, range);
1101 case CodeType.Label:
1102 case CodeType.BeginExceptionBlock:
1103 case CodeType.DeclareLocal:
1112 private int FindLabel(CodeEmitterLabel label)
1114 for (
int i = 0; i < code.Count; i++)
1116 if (code[i].pseudo == CodeType.Label && code[i].Label == label)
1121 throw new InvalidOperationException();
1124 private int FindLocal(CodeEmitterLocal local)
1126 for (
int i = 0; i < code.Count; i++)
1128 if (code[i].pseudo == CodeType.DeclareLocal && code[i].Local == local)
1138 private void SortPseudoOpCodes()
1140 for (
int i = 0; i < code.Count - 1; i++)
1142 switch (code[i].pseudo)
1144 case CodeType.ReleaseTempLocal:
1145 for (
int j = i - 1; ; j--)
1152 if (code[j].HasLocal && code[j].Local == code[i].Local)
1154 MoveInstruction(i, j + 1);
1163 private void MoveInstruction(
int i,
int j)
1165 if (i == j - 1 || i == j + 1)
1167 OpCodeWrapper temp = code[i];
1173 code.Insert(j, code[i]);
1178 OpCodeWrapper temp = code[i];
1180 code.Insert(j, temp);
1184 private void ClearLabelTemp()
1186 for (
int i = 0; i < code.Count; i++)
1188 if (code[i].pseudo == CodeType.Label)
1190 code[i].Label.Temp = 0;
1195 private void SetLabelIndexes()
1197 for (
int i = 0; i < code.Count; i++)
1199 if (code[i].pseudo == CodeType.Label)
1201 code[i].Label.Temp = i;
1206 private void SetLabelRefCounts()
1209 for (
int i = 0; i < code.Count; i++)
1211 if (code[i].pseudo == CodeType.OpCode)
1213 if (code[i].HasLabel)
1215 code[i].Label.Temp++;
1217 else if (code[i].opcode == OpCodes.Switch)
1219 foreach (CodeEmitterLabel label
in code[i].Labels)
1228 private void RemoveUnusedLabels()
1230 SetLabelRefCounts();
1231 for (
int i = 0; i < code.Count; i++)
1233 while (code[i].pseudo == CodeType.Label && code[i].Label.Temp == 0)
1240 private void RemoveDeadCode()
1243 const int ReachableFlag = 1;
1244 const int ProcessedFlag = 2;
1245 bool reachable =
true;
1250 for (
int i = 0; i < code.Count; i++)
1254 if (code[i].pseudo == CodeType.Label)
1256 if (code[i].Label.Temp == ProcessedFlag)
1260 code[i].Label.Temp |= ReachableFlag;
1262 else if (code[i].pseudo == CodeType.OpCode)
1264 if (code[i].HasLabel)
1266 if (code[i].Label.Temp == ProcessedFlag)
1270 code[i].Label.Temp |= ReachableFlag;
1272 else if (code[i].opcode == OpCodes.Switch)
1274 foreach (CodeEmitterLabel label
in code[i].Labels)
1276 if (label.Temp == ProcessedFlag)
1280 label.Temp |= ReachableFlag;
1283 switch (code[i].opcode.FlowControl)
1285 case FlowControl.Cond_Branch:
1286 if (!code[i].HasLabel && code[i].opcode != OpCodes.Switch)
1288 throw new NotSupportedException();
1291 case FlowControl.Branch:
1292 case FlowControl.Return:
1293 case FlowControl.Throw:
1299 else if (code[i].pseudo == CodeType.BeginCatchBlock)
1303 else if (code[i].pseudo == CodeType.BeginFaultBlock)
1307 else if (code[i].pseudo == CodeType.BeginFinallyBlock)
1311 else if (code[i].pseudo == CodeType.Label && (code[i].Label.Temp & ReachableFlag) != 0)
1315 if (code[i].pseudo == CodeType.Label)
1317 code[i].Label.Temp |= ProcessedFlag;
1322 int firstUnreachable = -1;
1323 for (
int i = 0; i < code.Count; i++)
1327 if (code[i].pseudo == CodeType.OpCode)
1329 switch (code[i].opcode.FlowControl)
1331 case FlowControl.Branch:
1332 case FlowControl.Return:
1333 case FlowControl.Throw:
1335 firstUnreachable = i + 1;
1342 switch (code[i].pseudo)
1344 case CodeType.OpCode:
1346 case CodeType.Label:
1347 if ((code[i].Label.Temp & ReachableFlag) != 0)
1349 goto case CodeType.BeginCatchBlock;
1352 case CodeType.BeginCatchBlock:
1353 case CodeType.BeginFaultBlock:
1354 case CodeType.BeginFinallyBlock:
1355 code.RemoveRange(firstUnreachable, i - firstUnreachable);
1356 i = firstUnreachable;
1357 firstUnreachable = -1;
1361 code.RemoveRange(firstUnreachable, i - firstUnreachable);
1362 i = firstUnreachable;
1370 code.RemoveRange(firstUnreachable, code.Count - firstUnreachable);
1376 for (
int i = 0; i < code.Count; i++)
1379 if (code[i].pseudo == CodeType.BeginExceptionBlock)
1381 for (
int k = 0; ; k++)
1383 switch (code[i + k].pseudo)
1385 case CodeType.BeginCatchBlock:
1386 case CodeType.BeginFaultBlock:
1387 case CodeType.BeginFinallyBlock:
1389 for (
int j = i + 1; ; j++)
1391 switch (code[j].pseudo)
1393 case CodeType.BeginExceptionBlock:
1396 case CodeType.EndExceptionBlock:
1399 code.RemoveRange(i, (j - i) + 1);
1406 case CodeType.OpCode:
1415 private void DeduplicateBranchSourceTargetCode()
1418 for (
int i = 0; i < code.Count; i++)
1420 if (code[i].opcode == OpCodes.Br && code[i].HasLabel)
1423 int target = code[i].Label.Temp - 1;
1424 while (source >= 0 && target >= 0)
1426 switch (code[source].pseudo)
1428 case CodeType.LineNumber:
1429 case CodeType.OpCode:
1434 if (!code[source].Match(code[target]))
1438 switch (code[source].opcode.FlowControl)
1440 case FlowControl.Branch:
1441 case FlowControl.Cond_Branch:
1450 if (source != i && target > 0 && source != target - 1)
1453 if (code[target - 1].pseudo == CodeType.Label)
1455 code[source] =
new OpCodeWrapper(OpCodes.Br, code[target - 1].Label);
1456 for (
int j = source + 1; j <= i; j++)
1460 code[j] =
new OpCodeWrapper(CodeType.Unreachable,
null);
1468 private void OptimizeStackTransfer()
1470 for (
int i = 0; i < code.Count; i++)
1472 if (code[i].opcode == OpCodes.Ldloc &&
1473 code[i + 1].opcode == OpCodes.Stloc &&
1474 code[i + 2].pseudo == CodeType.BeginExceptionBlock &&
1475 code[i + 3].opcode == OpCodes.Ldloc &&
1476 code[i + 3].MatchLocal(code[i + 1]) &&
1477 code[i + 4].pseudo == CodeType.ReleaseTempLocal &&
1478 code[i + 4].MatchLocal(code[i + 3]))
1480 code[i + 1] = code[i];
1481 code[i] = code[i + 2];
1482 code.RemoveRange(i + 2, 3);
1487 private void MergeExceptionBlocks()
1492 int[] extra =
new int[code.Count];
1493 Stack<int> stack =
new Stack<int>();
1494 int currentBeginExceptionBlock = -1;
1495 int currentLast = -1;
1496 for (
int i = 0; i < code.Count; i++)
1498 switch (code[i].pseudo)
1500 case CodeType.BeginExceptionBlock:
1501 stack.Push(currentBeginExceptionBlock);
1502 currentBeginExceptionBlock = i;
1505 case CodeType.EndExceptionBlock:
1506 extra[currentLast] = i;
1507 extra[i] = currentBeginExceptionBlock;
1508 currentBeginExceptionBlock = stack.Pop();
1509 currentLast = currentBeginExceptionBlock;
1510 if (currentLast != -1)
1512 while (extra[currentLast] != 0)
1514 currentLast = extra[currentLast];
1518 case CodeType.BeginCatchBlock:
1519 case CodeType.BeginFaultBlock:
1520 case CodeType.BeginFinallyBlock:
1521 extra[currentLast] = i;
1528 for (
int i = 0; i < code.Count - 1; i++)
1530 if (code[i].pseudo == CodeType.EndExceptionBlock
1531 && code[i + 1].pseudo == CodeType.BeginExceptionBlock)
1533 if (IsFaultOnlyBlock(extra, extra[i]) && IsFaultOnlyBlock(extra, i + 1))
1535 int beginFault1 = extra[extra[i]];
1536 int beginFault2 = extra[i + 1];
1537 int length1 = extra[beginFault1] - beginFault1;
1538 int length2 = extra[beginFault2] - beginFault2;
1539 if (length1 == length2 && MatchHandlers(beginFault1, beginFault2, length1))
1543 for (
int j = i + 2; j < beginFault2; j++)
1545 if (code[j].pseudo == CodeType.OpCode)
1549 else if (code[j].pseudo == CodeType.Label)
1551 if (HasBranchTo(0, extra[i], code[j].Label)
1552 || HasBranchTo(beginFault2 + length2, code.Count, code[j].Label))
1560 for (
int j = beginFault1; j < i + 2; j++)
1562 code[j] =
new OpCodeWrapper(OpCodes.Nop,
null);
1565 extra[extra[i]] = beginFault2;
1566 extra[extra[beginFault2]] = extra[i];
1581 bool HasBranchTo(
int start,
int end, CodeEmitterLabel label)
1583 for (
int i = start; i < end; i++)
1585 if (code[i].HasLabel)
1587 if (code[i].Label == label)
1590 else if (code[i].opcode == OpCodes.Switch)
1592 foreach (CodeEmitterLabel swlbl
in code[i].Labels)
1601 private bool MatchHandlers(
int beginFault1,
int beginFault2,
int length)
1603 for (
int i = 0; i < length; i++)
1604 if (!code[beginFault1 + i].Match(code[beginFault2 + i]))
1610 private bool IsFaultOnlyBlock(
int[] extra,
int begin)
1612 return code[extra[begin]].pseudo == CodeType.BeginFaultBlock && code[extra[extra[begin]]].pseudo == CodeType.EndExceptionBlock;
1615 private void ConvertSynchronizedFaultToFinally()
1617 bool labelIndexSet =
false;
1621 for (
int i = 0; i < code.Count; i++)
1623 switch (code[i].pseudo)
1625 case CodeType.BeginExceptionBlock:
1630 else if (nest == 1 && next <= start)
1636 case CodeType.BeginCatchBlock:
1637 case CodeType.BeginFinallyBlock:
1654 case CodeType.BeginFaultBlock:
1658 if (code[i + 1].pseudo == CodeType.LineNumber)
1663 if (code[i + 1].opcode == OpCodes.Ldloc
1664 && code[i + 2].pseudo == CodeType.MonitorExit
1665 && code[i + 3].opcode == OpCodes.Endfinally)
1669 labelIndexSet =
true;
1675 for (
int pass = 0; pass < 2; pass++)
1677 for (
int j = start; j < i; j++)
1679 if (code[j].opcode == OpCodes.Leave)
1681 int target = code[j].Label.Temp;
1682 if (target < start || target > i)
1685 if ((code[j - 1].opcode == OpCodes.Pop || code[j - 1].opcode == OpCodes.Stloc)
1686 && code[j - 2].pseudo == CodeType.MonitorExit
1687 && code[j - 3].Match(code[i + 1]))
1692 code[j - 3] = code[j - 1];
1693 code[j - 2] = code[j - 0];
1694 code[j - 1] =
new OpCodeWrapper(CodeType.Unreachable, CodeTypeFlags.None);
1695 code[j - 0] =
new OpCodeWrapper(CodeType.Unreachable, CodeTypeFlags.None);
1698 else if (code[j - 1].pseudo == CodeType.MonitorExit
1699 && code[j - 2].Match(code[i + 1]))
1704 code[j - 2] = code[j];
1705 code[j - 1] =
new OpCodeWrapper(CodeType.Unreachable, CodeTypeFlags.None);
1706 code[j - 0] =
new OpCodeWrapper(CodeType.Unreachable, CodeTypeFlags.None);
1719 code[beginFault] =
new OpCodeWrapper(CodeType.BeginFinallyBlock, CodeTypeFlags.None);
1722 goto case CodeType.BeginFinallyBlock;
1725 case CodeType.EndExceptionBlock:
1732 private void RemoveRedundantMemoryBarriers()
1734 int lastMemoryBarrier = -1;
1735 for (
int i = 0; i < code.Count; i++)
1737 switch (code[i].pseudo)
1739 case CodeType.MemoryBarrier:
1740 if (lastMemoryBarrier != -1)
1742 code.RemoveAt(lastMemoryBarrier);
1745 lastMemoryBarrier = i;
1747 case CodeType.OpCode:
1748 if (code[i].opcode == OpCodes.Volatile)
1750 if (code[i + 1].opcode != OpCodes.Stfld && code[i + 1].opcode != OpCodes.Stsfld)
1752 lastMemoryBarrier = -1;
1755 else if (code[i].opcode.FlowControl != FlowControl.Next)
1757 lastMemoryBarrier = -1;
1764 private static bool MatchLdarg(OpCodeWrapper opc, out
short arg)
1766 if (opc.opcode == OpCodes.Ldarg)
1768 arg = opc.ValueInt16;
1771 else if (opc.opcode == OpCodes.Ldarg_S)
1773 arg = opc.ValueByte;
1776 else if (opc.opcode == OpCodes.Ldarg_0)
1781 else if (opc.opcode == OpCodes.Ldarg_1)
1786 else if (opc.opcode == OpCodes.Ldarg_2)
1791 else if (opc.opcode == OpCodes.Ldarg_3)
1803 private bool IsBranchEqNe(OpCode opcode)
1805 return opcode == OpCodes.Beq
1806 || opcode == OpCodes.Bne_Un;
1809 private void CLRv4_x64_JIT_Workaround()
1811 for (
int i = 0; i < code.Count - 2; i++)
1827 if (code[i].opcode == OpCodes.Ldc_I8 && code[i].ValueInt64 == 0)
1831 if (i > 0 && MatchLdarg(code[i - 1], out arg) && IsBranchEqNe(code[i + 1].opcode))
1835 else if (MatchLdarg(code[i + 1], out arg) && IsBranchEqNe(code[i + 2].opcode))
1843 code[m] =
new OpCodeWrapper(OpCodes.Ldarga, arg);
1844 code.Insert(m + 1,
new OpCodeWrapper(OpCodes.Ldind_I8,
null));
1849 void CheckInvariants()
1851 CheckInvariantBranchInOrOutOfBlocks();
1852 CheckInvariantOpCodeUsage();
1853 CheckInvariantLocalVariables();
1856 void CheckInvariantBranchInOrOutOfBlocks()
1882 int nextBlockId = 1;
1883 Stack<int> blocks =
new Stack<int>();
1884 for (
int i = 0; i < code.Count; i++)
1886 switch (code[i].pseudo)
1888 case CodeType.Label:
1889 code[i].Label.Temp = blockId;
1891 case CodeType.BeginExceptionBlock:
1892 blocks.Push(blockId);
1893 goto case CodeType.BeginFinallyBlock;
1894 case CodeType.BeginFinallyBlock:
1895 case CodeType.BeginFaultBlock:
1896 case CodeType.BeginCatchBlock:
1897 blockId = nextBlockId++;
1899 case CodeType.EndExceptionBlock:
1900 blockId = blocks.Pop();
1904 if (blocks.Count != 0)
1906 throw new InvalidOperationException(
"Unbalanced exception blocks");
1910 for (
int i = 0; i < code.Count; i++)
1912 switch (code[i].pseudo)
1914 case CodeType.OpCode:
1915 if (code[i].HasLabel
1916 && code[i].opcode != OpCodes.Leave
1917 && code[i].Label.Temp != blockId)
1920 throw new InvalidOperationException(
"Invalid branch " + code[i].opcode.Name +
" at offset " + i +
" from block " + blockId +
" to " + code[i].Label.Temp);
1923 case CodeType.BeginExceptionBlock:
1924 blocks.Push(blockId);
1925 goto case CodeType.BeginFinallyBlock;
1926 case CodeType.BeginFinallyBlock:
1927 case CodeType.BeginFaultBlock:
1928 case CodeType.BeginCatchBlock:
1929 blockId = nextBlockId++;
1931 case CodeType.EndExceptionBlock:
1932 blockId = blocks.Pop();
1938 private void CheckInvariantOpCodeUsage()
1940 for (
int i = 0; i < code.Count; i++)
1942 switch (code[i].opcode.FlowControl)
1944 case FlowControl.Branch:
1945 case FlowControl.Cond_Branch:
1946 if (!code[i].HasLabel && code[i].opcode != OpCodes.Switch)
1948 throw new InvalidOperationException();
1955 private void CheckInvariantLocalVariables()
1957 List<CodeEmitterLocal> locals =
new List<CodeEmitterLocal>();
1958 for (
int i = 0; i < code.Count; i++)
1960 if (code[i].pseudo == CodeType.DeclareLocal)
1962 if (locals.Contains(code[i].Local))
1964 throw new InvalidOperationException(
"Local variable used before declaration");
1967 else if (code[i].HasLocal)
1969 locals.Add(code[i].Local);
1974 private void MoveLocalDeclarationToBeginScope()
1977 for (
int i = 0; i < code.Count; i++)
1979 switch (code[i].pseudo)
1981 case CodeType.BeginScope:
1984 case CodeType.DeclareLocal:
1985 OpCodeWrapper decl = code[i];
1987 code.Insert(pos++, decl);
1993 internal void DoEmit()
1996 CLRv4_x64_JIT_Workaround();
1997 RemoveRedundantMemoryBarriers();
2002 MoveLocalDeclarationToBeginScope();
2004 for (
int i = 0; i < 4; i++)
2010 RemoveSingletonBranches();
2012 RemoveUnusedLabels();
2014 SortPseudoOpCodes();
2018 AnnihilateStoreReleaseTempLocals();
2020 DeduplicateBranchSourceTargetCode();
2022 OptimizeStackTransfer();
2024 MergeExceptionBlocks();
2026 ConvertSynchronizedFaultToFinally();
2034 OptimizeEncodings();
2038 int lineNumber = -1;
2039 for (
int i = 0; i < code.Count; i++)
2041 code[i].RealEmit(ilOffset,
this,
ref lineNumber);
2042 ilOffset = ilgen_real.ILOffset;
2046 internal void DumpMethod()
2048 var labelIndexes =
new Dictionary<CodeEmitterLabel, int>();
2049 for (
int i = 0; i < code.Count; i++)
2051 if (code[i].pseudo == CodeType.Label)
2053 labelIndexes.Add(code[i].Label, i);
2056 Console.WriteLine(
"======================");
2057 for (
int i = 0; i < code.Count; i++)
2059 if (code[i].pseudo == CodeType.OpCode)
2061 Console.Write(
" " + code[i].opcode.Name);
2062 if (code[i].HasLabel)
2064 Console.Write(
" label" + labelIndexes[code[i].Label]);
2066 else if (code[i].opcode == OpCodes.Ldarg_S || code[i].opcode == OpCodes.Ldarga_S)
2068 Console.Write(
" " + code[i].ValueByte);
2070 else if (code[i].opcode == OpCodes.Ldarg || code[i].opcode == OpCodes.Ldarga)
2072 Console.Write(
" " + code[i].ValueInt16);
2074 else if (code[i].opcode == OpCodes.Isinst || code[i].opcode == OpCodes.Castclass || code[i].opcode == OpCodes.Box || code[i].opcode == OpCodes.Unbox || code[i].opcode == OpCodes.Ldobj || code[i].opcode == OpCodes.Newarr)
2076 Console.Write(
" " + code[i].
Type);
2078 else if (code[i].opcode == OpCodes.Call || code[i].opcode == OpCodes.Callvirt)
2082 else if (code[i].opcode == OpCodes.Ldfld || code[i].opcode == OpCodes.Ldsfld || code[i].opcode == OpCodes.Stfld || code[i].opcode == OpCodes.Stsfld)
2086 else if (code[i].opcode == OpCodes.Ldc_I4)
2088 Console.Write(
" " + code[i].ValueInt32);
2090 else if (code[i].opcode == OpCodes.Ldloc || code[i].opcode == OpCodes.Stloc)
2092 Console.Write(
" " + code[i].Local.__LocalIndex);
2094 Console.WriteLine();
2096 else if (code[i].pseudo == CodeType.Label)
2098 Console.WriteLine(
"label{0}: // temp = {1}", i, code[i].Label.Temp);
2100 else if (code[i].pseudo == CodeType.DeclareLocal)
2102 Console.WriteLine(
"local #{0} = {1}", code[i].Local.__LocalIndex, code[i].Local.LocalType);
2106 Console.WriteLine(code[i]);
2111 internal void DefineSymbolDocument(ModuleBuilder module,
string url, Guid language, Guid languageVendor, Guid documentType)
2113#if NETFRAMEWORK || IMPORTER
2114 symbols = module.DefineDocument(url, language, languageVendor, documentType);
2118 internal CodeEmitterLocal UnsafeAllocTempLocal(
Type type)
2121 for (
int i = 0; i < tempLocals.Length; i++)
2123 CodeEmitterLocal lb = tempLocals[i];
2131 else if (lb.LocalType == type)
2136 CodeEmitterLocal lb1 = DeclareLocal(type);
2139 tempLocals[free] = lb1;
2144 internal CodeEmitterLocal AllocTempLocal(
Type type)
2146 for (
int i = 0; i < tempLocals.Length; i++)
2148 var lb = tempLocals[i];
2149 if (lb !=
null && lb.LocalType == type)
2151 tempLocals[i] =
null;
2156 return new CodeEmitterLocal(type);
2159 internal void ReleaseTempLocal(CodeEmitterLocal lb)
2161 EmitPseudoOpCode(CodeType.ReleaseTempLocal, lb);
2163 for (
int i = 0; i < tempLocals.Length; i++)
2165 if (tempLocals[i] ==
null)
2173 internal void BeginCatchBlock(
Type exceptionType)
2175 EmitPseudoOpCode(CodeType.BeginCatchBlock, exceptionType);
2178 internal void BeginExceptionBlock()
2180 exceptionStack.Push(inFinally);
2182 EmitPseudoOpCode(CodeType.BeginExceptionBlock,
null);
2185 internal void BeginFaultBlock()
2188 EmitPseudoOpCode(CodeType.BeginFaultBlock,
null);
2191 internal void BeginFinallyBlock()
2194 EmitPseudoOpCode(CodeType.BeginFinallyBlock,
null);
2197 internal void BeginScope()
2199 EmitPseudoOpCode(CodeType.BeginScope,
null);
2202 internal CodeEmitterLocal DeclareLocal(
Type localType)
2204 var local =
new CodeEmitterLocal(localType);
2205 EmitPseudoOpCode(CodeType.DeclareLocal, local);
2209 internal CodeEmitterLabel DefineLabel()
2211 return new CodeEmitterLabel(ilgen_real.DefineLabel());
2214 internal void Emit(OpCode opcode)
2216 EmitOpCode(opcode,
null);
2219 internal void EmitUnaligned(
byte alignment)
2221 EmitOpCode(OpCodes.Unaligned, alignment);
2224 internal void Emit(OpCode opcode,
MethodBase mb)
2226 EmitOpCode(opcode, mb);
2229 internal void EmitLdc_R8(
double arg)
2231 EmitOpCode(OpCodes.Ldc_R8, arg);
2234 internal void Emit(OpCode opcode,
FieldInfo field)
2236 EmitOpCode(opcode, field);
2239 internal void EmitLdarg(
int arg)
2241 Debug.Assert(0 <= arg && arg < 65536);
2246 EmitOpCode(OpCodes.Ldarg_0,
null);
2249 EmitOpCode(OpCodes.Ldarg_1,
null);
2252 EmitOpCode(OpCodes.Ldarg_2,
null);
2255 EmitOpCode(OpCodes.Ldarg_3,
null);
2258 if ((uint)arg <=
byte.MaxValue)
2259 EmitOpCode(OpCodes.Ldarg_S, (
byte)arg);
2261 EmitOpCode(OpCodes.Ldarg, (
short)arg);
2267 internal void EmitLdarga(
int arg)
2269 Debug.Assert(0 <= arg && arg < 65536);
2272 EmitOpCode(OpCodes.Ldarga_S, (
byte)arg);
2274 EmitOpCode(OpCodes.Ldarga, (
short)arg);
2277 internal void EmitStarg(
int arg)
2279 Debug.Assert(0 <= arg && arg < 65536);
2282 EmitOpCode(OpCodes.Starg_S, (
byte)arg);
2284 EmitOpCode(OpCodes.Starg, (
short)arg);
2287 internal void EmitLdc_I8(
long arg)
2289 EmitOpCode(OpCodes.Ldc_I8, arg);
2292 internal void EmitBr(CodeEmitterLabel label)
2294 EmitOpCode(OpCodes.Br, label);
2297 internal void EmitBeq(CodeEmitterLabel label)
2299 EmitOpCode(OpCodes.Beq, label);
2302 internal void EmitBne_Un(CodeEmitterLabel label)
2304 EmitOpCode(OpCodes.Bne_Un, label);
2307 internal void EmitBle_Un(CodeEmitterLabel label)
2309 EmitOpCode(OpCodes.Ble_Un, label);
2312 internal void EmitBlt_Un(CodeEmitterLabel label)
2314 EmitOpCode(OpCodes.Blt_Un, label);
2317 internal void EmitBge_Un(CodeEmitterLabel label)
2319 EmitOpCode(OpCodes.Bge_Un, label);
2322 internal void EmitBle(CodeEmitterLabel label)
2324 EmitOpCode(OpCodes.Ble, label);
2327 internal void EmitBlt(CodeEmitterLabel label)
2329 EmitOpCode(OpCodes.Blt, label);
2332 internal void EmitBge(CodeEmitterLabel label)
2334 EmitOpCode(OpCodes.Bge, label);
2337 internal void EmitBgt(CodeEmitterLabel label)
2339 EmitOpCode(OpCodes.Bgt, label);
2342 internal void EmitBrtrue(CodeEmitterLabel label)
2344 EmitOpCode(OpCodes.Brtrue, label);
2347 internal void EmitBrfalse(CodeEmitterLabel label)
2349 EmitOpCode(OpCodes.Brfalse, label);
2352 internal void EmitLeave(CodeEmitterLabel label)
2354 EmitOpCode(OpCodes.Leave, label);
2357 internal void EmitSwitch(CodeEmitterLabel[] labels)
2359 EmitOpCode(OpCodes.Switch, labels);
2362 internal void Emit(OpCode opcode, CodeEmitterLocal local)
2364 EmitOpCode(opcode, local);
2367 internal void EmitLdc_R4(
float arg)
2369 EmitOpCode(OpCodes.Ldc_R4, arg);
2372 internal void Emit(OpCode opcode,
string arg)
2374 EmitOpCode(opcode, arg);
2377 internal void Emit(OpCode opcode,
Type cls)
2379 EmitOpCode(opcode, cls);
2384 EmitOpCode(opcode,
new CalliWrapper(unmanagedCallConv, returnType, parameterTypes));
2387 internal void EmitCalli(OpCode opcode, CallingConventions unmanagedCallConv,
Type returnType,
Type[] parameterTypes,
Type[] optionalParameterTypes)
2389 EmitOpCode(opcode,
new ManagedCalliWrapper(unmanagedCallConv, returnType, parameterTypes, optionalParameterTypes));
2392 internal void EndExceptionBlock()
2394 EmitPseudoOpCode(CodeType.EndExceptionBlock, inFinally ? CodeTypeFlags.EndFaultOrFinally : CodeTypeFlags.None);
2395 inFinally = exceptionStack.Pop();
2398 internal void EndScope()
2400 EmitPseudoOpCode(CodeType.EndScope,
null);
2403 internal void MarkLabel(CodeEmitterLabel loc)
2405 EmitPseudoOpCode(CodeType.Label, loc);
2408 internal void ThrowException(
Type excType)
2410 Emit(OpCodes.Newobj, excType.GetConstructor(
Type.EmptyTypes));
2411 Emit(OpCodes.Throw);
2414 internal void SetLineNumber(ushort line)
2416#if NETFRAMEWORK || IMPORTER
2417 if (symbols !=
null)
2418 EmitPseudoOpCode(CodeType.SequencePoint, (
int)line);
2421 EmitPseudoOpCode(CodeType.LineNumber, (
int)line);
2424 internal byte[] GetLineNumberTable()
2426 return linenums ==
null ? null : linenums.
ToArray();
2431 internal void EmitLineNumberTable(MethodBuilder mb)
2433 if (linenums !=
null)
2434 context.AttributeHelper.SetLineNumberTable(mb, linenums);
2439 internal void EmitThrow(
string dottedClassName)
2441 var exception = context.ClassLoaderFactory.GetBootstrapClassLoader().LoadClassByName(dottedClassName);
2442 var mw = exception.GetMethod(
"<init>",
"()V",
false);
2444 mw.EmitNewobj(
this);
2445 Emit(OpCodes.Throw);
2448 internal void EmitThrow(
string dottedClassName,
string message)
2450 var exception = context.ClassLoaderFactory.GetBootstrapClassLoader().LoadClassByName(dottedClassName);
2451 Emit(OpCodes.Ldstr, message);
2452 var mw = exception.GetMethod(
"<init>",
"(Ljava.lang.String;)V",
false);
2454 mw.EmitNewobj(
this);
2455 Emit(OpCodes.Throw);
2458 internal void EmitNullCheck()
2461 Emit(OpCodes.Ldvirtftn, context.CodeEmitterFactory.ObjectToStringMethod);
2465 internal void EmitCastclass(
Type type)
2467 if (context.CodeEmitterFactory.VerboseCastFailureMethod !=
null)
2469 var lb = DeclareLocal(context.Types.Object);
2470 Emit(OpCodes.Stloc, lb);
2471 Emit(OpCodes.Ldloc, lb);
2472 Emit(OpCodes.Isinst, type);
2474 var ok = DefineLabel();
2476 Emit(OpCodes.Ldloc, lb);
2478 Emit(OpCodes.Ldtoken, type);
2479 Emit(OpCodes.Ldloc, lb);
2480 Emit(OpCodes.Call, context.CodeEmitterFactory.VerboseCastFailureMethod);
2485 Emit(OpCodes.Castclass, type);
2491 internal void EmitAssertType(
Type type)
2493 var isnull = DefineLabel();
2495 EmitBrfalse(isnull);
2496 Emit(OpCodes.Isinst, type);
2498 var ok = DefineLabel();
2500 EmitThrow(
"java.lang.IncompatibleClassChangeError");
2503 Emit(OpCodes.Ldnull);
2507 internal void EmitUnboxSpecial(
Type type)
2510 var label1 = DefineLabel();
2511 var label2 = DefineLabel();
2516 var local = AllocTempLocal(type);
2517 Emit(OpCodes.Ldloca, local);
2518 Emit(OpCodes.Initobj, type);
2519 Emit(OpCodes.Ldloc, local);
2520 ReleaseTempLocal(local);
2523 Emit(OpCodes.Unbox, type);
2524 Emit(OpCodes.Ldobj, type);
2528 internal void EmitLdc_I4(
int i)
2530 EmitOpCode(OpCodes.Ldc_I4, i);
2533 internal void Emit_idiv()
2538 var label1 = DefineLabel();
2539 var label2 = DefineLabel();
2542 Emit(OpCodes.Ldc_I4_M1);
2552 internal void Emit_ldiv()
2557 var label1 = DefineLabel();
2558 var label2 = DefineLabel();
2561 Emit(OpCodes.Ldc_I4_M1);
2562 Emit(OpCodes.Conv_I8);
2572 internal void Emit_instanceof(
Type type)
2574 Emit(OpCodes.Isinst, type);
2575 Emit(OpCodes.Ldnull);
2576 Emit(OpCodes.Cgt_Un);
2579 internal enum Comparison
2587 internal void Emit_if_le_lt_ge_gt(Comparison comp, CodeEmitterLabel label)
2590 Emit(OpCodes.Ldc_I4_0);
2593 case Comparison.LessOrEqual:
2596 case Comparison.LessThan:
2599 case Comparison.GreaterOrEqual:
2602 case Comparison.GreaterThan:
2608 private void EmitCmp(
Type type, OpCode cmp1, OpCode cmp2)
2610 var value1 = AllocTempLocal(type);
2611 var value2 = AllocTempLocal(type);
2612 Emit(OpCodes.Stloc, value2);
2613 Emit(OpCodes.Stloc, value1);
2614 Emit(OpCodes.Ldloc, value1);
2615 Emit(OpCodes.Ldloc, value2);
2617 Emit(OpCodes.Ldloc, value1);
2618 Emit(OpCodes.Ldloc, value2);
2621 ReleaseTempLocal(value2);
2622 ReleaseTempLocal(value1);
2625 internal void Emit_lcmp()
2627 EmitCmp(context.Types.Int64, OpCodes.Cgt, OpCodes.Clt);
2630 internal void Emit_fcmpl()
2632 EmitCmp(context.Types.Single, OpCodes.Cgt, OpCodes.Clt_Un);
2635 internal void Emit_fcmpg()
2637 EmitCmp(context.Types.Single, OpCodes.Cgt_Un, OpCodes.Clt);
2640 internal void Emit_dcmpl()
2642 EmitCmp(context.Types.Double, OpCodes.Cgt, OpCodes.Clt_Un);
2645 internal void Emit_dcmpg()
2647 EmitCmp(context.Types.Double, OpCodes.Cgt_Un, OpCodes.Clt);
2650 internal void Emit_And_I4(
int v)
2656 internal void CheckLabels()
2659 foreach(
System.Diagnostics.StackFrame frame in labels.Values)
2661 string name = frame.GetFileName() +
":" + frame.GetFileLineNumber();
2662 IKVM.
Runtime.
JVM.CriticalFailure(
"Label failure: " + name,
null);
2667 internal void EmitMemoryBarrier()
2669 EmitPseudoOpCode(CodeType.MemoryBarrier,
null);
2672 internal void EmitTailCallPrevention()
2674 EmitPseudoOpCode(CodeType.TailCallPrevention,
null);
2677 internal void EmitClearStack()
2679 EmitPseudoOpCode(CodeType.ClearStack,
null);
2682 internal void EmitMonitorEnter()
2684 EmitPseudoOpCode(CodeType.MonitorEnter,
null);
2687 internal void EmitMonitorExit()
2689 EmitPseudoOpCode(CodeType.MonitorExit,
null);