2003-05-30 16:08:59 +04:00
|
|
|
/*
|
2010-10-01 12:11:49 +04:00
|
|
|
Copyright (C) 2002-2010 Jeroen Frijters
|
2003-05-30 16:08:59 +04:00
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely, subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
|
|
claim that you wrote the original software. If you use this software
|
|
|
|
in a product, an acknowledgment in the product documentation would be
|
|
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
|
|
|
|
Jeroen Frijters
|
|
|
|
jeroen@frijters.net
|
|
|
|
|
|
|
|
*/
|
|
|
|
using System;
|
2008-08-15 16:01:06 +04:00
|
|
|
using System.Collections.Generic;
|
2010-01-28 12:18:33 +03:00
|
|
|
#if STATIC_COMPILER
|
2010-01-25 10:52:27 +03:00
|
|
|
using IKVM.Reflection;
|
2008-11-14 11:42:07 +03:00
|
|
|
using IKVM.Reflection.Emit;
|
2010-01-25 10:52:27 +03:00
|
|
|
using Type = IKVM.Reflection.Type;
|
2008-11-14 11:42:07 +03:00
|
|
|
#else
|
2010-01-25 10:52:27 +03:00
|
|
|
using System.Reflection;
|
2003-05-30 16:08:59 +04:00
|
|
|
using System.Reflection.Emit;
|
2008-11-14 11:42:07 +03:00
|
|
|
#endif
|
2004-10-19 17:43:55 +04:00
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
using System.Diagnostics.SymbolStore;
|
2009-02-27 09:17:06 +03:00
|
|
|
using System.Diagnostics;
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
namespace IKVM.Internal
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
sealed class CodeEmitterLabel
|
2005-12-29 18:48:32 +03:00
|
|
|
{
|
|
|
|
private Label label;
|
|
|
|
private int offset = -1;
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal CodeEmitterLabel(Label label)
|
2005-12-29 18:48:32 +03:00
|
|
|
{
|
|
|
|
this.label = label;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Label Label
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return label;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int Offset
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return offset;
|
|
|
|
}
|
2010-09-30 10:00:40 +04:00
|
|
|
set
|
|
|
|
{
|
|
|
|
offset = value;
|
|
|
|
}
|
2010-09-30 08:03:32 +04:00
|
|
|
}
|
|
|
|
|
2010-09-30 10:00:40 +04:00
|
|
|
internal void Mark(ILGenerator ilgen)
|
2010-09-30 08:03:32 +04:00
|
|
|
{
|
|
|
|
ilgen.MarkLabel(label);
|
2005-12-29 18:48:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-29 11:21:51 +04:00
|
|
|
sealed class CodeEmitterLocal
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
private Type type;
|
|
|
|
private string name;
|
|
|
|
private LocalBuilder local;
|
2010-09-29 11:21:51 +04:00
|
|
|
|
2010-09-30 08:03:32 +04:00
|
|
|
internal CodeEmitterLocal(Type type)
|
2010-09-29 11:21:51 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
this.type = type;
|
2010-09-29 11:21:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal Type LocalType
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
get { return type; }
|
2010-09-29 11:21:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void SetLocalSymInfo(string name)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
this.name = name;
|
2010-09-29 11:21:51 +04:00
|
|
|
}
|
|
|
|
|
2010-09-30 08:03:32 +04:00
|
|
|
internal int __LocalIndex
|
|
|
|
{
|
2010-09-30 10:00:40 +04:00
|
|
|
get { return local == null ? 0xFFFF : local.LocalIndex; }
|
2010-09-30 08:03:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void Emit(ILGenerator ilgen, OpCode opcode)
|
2010-09-29 11:21:51 +04:00
|
|
|
{
|
2010-09-30 19:15:34 +04:00
|
|
|
if (local == null)
|
|
|
|
{
|
|
|
|
// it's a temporary local that is only allocated on-demand
|
|
|
|
local = ilgen.DeclareLocal(type);
|
|
|
|
}
|
2010-09-30 08:03:32 +04:00
|
|
|
ilgen.Emit(opcode, local);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void Declare(ILGenerator ilgen)
|
|
|
|
{
|
|
|
|
local = ilgen.DeclareLocal(type);
|
|
|
|
if (name != null)
|
|
|
|
{
|
|
|
|
local.SetLocalSymInfo(name);
|
|
|
|
}
|
2010-09-29 11:21:51 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-31 09:02:34 +04:00
|
|
|
sealed class CodeEmitter
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2009-10-14 18:58:41 +04:00
|
|
|
private static readonly MethodInfo objectToString = Types.Object.GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
|
2009-08-31 09:02:34 +04:00
|
|
|
private static readonly MethodInfo verboseCastFailure = JVM.SafeGetEnvironmentVariable("IKVM_VERBOSE_CAST") == null ? null : ByteCodeHelperMethods.VerboseCastFailure;
|
2008-02-15 18:32:51 +03:00
|
|
|
private ILGenerator ilgen_real;
|
2005-06-01 13:49:30 +04:00
|
|
|
private bool inFinally;
|
2010-09-30 08:03:32 +04:00
|
|
|
private Stack<bool> exceptionStack = new Stack<bool>();
|
2005-06-19 14:44:53 +04:00
|
|
|
private IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter linenums;
|
2010-09-29 11:21:51 +04:00
|
|
|
private CodeEmitterLocal[] tempLocals = new CodeEmitterLocal[32];
|
2010-09-28 12:02:07 +04:00
|
|
|
private ISymbolDocumentWriter symbols;
|
2010-09-30 08:03:32 +04:00
|
|
|
private List<OpCodeWrapper> code = new List<OpCodeWrapper>();
|
2004-11-04 15:50:28 +03:00
|
|
|
#if LABELCHECK
|
2009-04-06 14:14:47 +04:00
|
|
|
private Dictionary<CodeEmitterLabel, System.Diagnostics.StackFrame> labels = new Dictionary<CodeEmitterLabel, System.Diagnostics.StackFrame>();
|
2004-11-04 15:50:28 +03:00
|
|
|
#endif
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2010-09-30 08:03:32 +04:00
|
|
|
enum CodeType
|
|
|
|
{
|
|
|
|
OpCode,
|
|
|
|
Nop,
|
|
|
|
BeginScope,
|
|
|
|
EndScope,
|
|
|
|
DeclareLocal,
|
2010-10-01 10:40:49 +04:00
|
|
|
ReleaseTempLocal,
|
2010-09-30 08:03:32 +04:00
|
|
|
SequencePoint,
|
|
|
|
LineNumber,
|
|
|
|
Label,
|
|
|
|
ThrowException,
|
|
|
|
BeginExceptionBlock,
|
|
|
|
BeginCatchBlock,
|
|
|
|
BeginFaultBlock,
|
|
|
|
BeginFinallyBlock,
|
|
|
|
EndExceptionBlock,
|
|
|
|
EndExceptionBlockFinally,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct OpCodeWrapper
|
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
internal readonly CodeType pseudo;
|
2010-09-30 08:03:32 +04:00
|
|
|
internal readonly OpCode opcode;
|
2010-10-01 13:22:47 +04:00
|
|
|
private readonly object data;
|
2010-09-30 08:03:32 +04:00
|
|
|
|
2010-10-01 10:40:49 +04:00
|
|
|
internal OpCodeWrapper(CodeType pseudo, object data)
|
2010-09-30 08:03:32 +04:00
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
this.pseudo = pseudo;
|
2010-09-30 11:31:27 +04:00
|
|
|
this.opcode = OpCodes.Nop;
|
|
|
|
this.data = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal OpCodeWrapper(OpCode opcode, object data)
|
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
this.pseudo = CodeType.OpCode;
|
2010-09-30 08:03:32 +04:00
|
|
|
this.opcode = opcode;
|
|
|
|
this.data = data;
|
|
|
|
}
|
2010-09-30 10:00:40 +04:00
|
|
|
|
2010-10-01 13:22:47 +04:00
|
|
|
internal bool HasLabel
|
|
|
|
{
|
|
|
|
get { return data is CodeEmitterLabel; }
|
|
|
|
}
|
|
|
|
|
2010-10-01 08:41:06 +04:00
|
|
|
internal CodeEmitterLabel Label
|
|
|
|
{
|
|
|
|
get { return (CodeEmitterLabel)data; }
|
|
|
|
}
|
|
|
|
|
2010-10-01 13:22:47 +04:00
|
|
|
internal bool MatchLabel(OpCodeWrapper other)
|
|
|
|
{
|
|
|
|
return data == other.data;
|
|
|
|
}
|
|
|
|
|
2010-10-01 10:40:49 +04:00
|
|
|
internal CodeEmitterLocal Local
|
|
|
|
{
|
|
|
|
get { return (CodeEmitterLocal)data; }
|
|
|
|
}
|
|
|
|
|
2010-10-01 13:22:47 +04:00
|
|
|
internal bool MatchLocal(OpCodeWrapper other)
|
|
|
|
{
|
|
|
|
return data == other.data;
|
|
|
|
}
|
|
|
|
|
2010-10-01 08:41:06 +04:00
|
|
|
internal int ValueInt32
|
|
|
|
{
|
|
|
|
get { return (int)data; }
|
|
|
|
}
|
|
|
|
|
|
|
|
internal long ValueInt64
|
|
|
|
{
|
|
|
|
get { return (long)data; }
|
|
|
|
}
|
|
|
|
|
2010-10-01 10:40:49 +04:00
|
|
|
internal Type Type
|
|
|
|
{
|
|
|
|
get { return (Type)data; }
|
|
|
|
}
|
|
|
|
|
2010-10-01 13:22:47 +04:00
|
|
|
internal FieldInfo FieldInfo
|
|
|
|
{
|
|
|
|
get { return (FieldInfo)data; }
|
|
|
|
}
|
|
|
|
|
2010-09-30 10:00:40 +04:00
|
|
|
internal int Size
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
switch (pseudo)
|
2010-09-30 10:00:40 +04:00
|
|
|
{
|
|
|
|
case CodeType.Nop:
|
|
|
|
case CodeType.BeginScope:
|
|
|
|
case CodeType.EndScope:
|
|
|
|
case CodeType.DeclareLocal:
|
2010-10-01 10:40:49 +04:00
|
|
|
case CodeType.ReleaseTempLocal:
|
2010-09-30 10:00:40 +04:00
|
|
|
case CodeType.LineNumber:
|
|
|
|
case CodeType.Label:
|
|
|
|
case CodeType.BeginExceptionBlock:
|
|
|
|
return 0;
|
|
|
|
case CodeType.SequencePoint:
|
|
|
|
return 1;
|
|
|
|
case CodeType.ThrowException:
|
|
|
|
return 6;
|
|
|
|
case CodeType.BeginCatchBlock:
|
|
|
|
case CodeType.BeginFaultBlock:
|
|
|
|
case CodeType.BeginFinallyBlock:
|
|
|
|
case CodeType.EndExceptionBlock:
|
|
|
|
return 5;
|
|
|
|
case CodeType.EndExceptionBlockFinally:
|
|
|
|
return 1;
|
|
|
|
case CodeType.OpCode:
|
|
|
|
if (data == null)
|
|
|
|
{
|
|
|
|
return opcode.Size;
|
|
|
|
}
|
|
|
|
else if (data is int)
|
|
|
|
{
|
|
|
|
return opcode.Size + 4;;
|
|
|
|
}
|
|
|
|
else if (data is long)
|
|
|
|
{
|
|
|
|
return opcode.Size + 8;
|
|
|
|
}
|
|
|
|
else if (data is MethodInfo)
|
|
|
|
{
|
|
|
|
return opcode.Size + 4;
|
|
|
|
}
|
|
|
|
else if (data is ConstructorInfo)
|
|
|
|
{
|
|
|
|
return opcode.Size + 4;
|
|
|
|
}
|
|
|
|
else if (data is FieldInfo)
|
|
|
|
{
|
|
|
|
return opcode.Size + 4;
|
|
|
|
}
|
|
|
|
else if (data is sbyte)
|
|
|
|
{
|
|
|
|
return opcode.Size + 1;
|
|
|
|
}
|
|
|
|
else if (data is byte)
|
|
|
|
{
|
|
|
|
return opcode.Size + 1;
|
|
|
|
}
|
|
|
|
else if (data is short)
|
|
|
|
{
|
|
|
|
return opcode.Size + 2;
|
|
|
|
}
|
|
|
|
else if (data is float)
|
|
|
|
{
|
|
|
|
return opcode.Size + 4;
|
|
|
|
}
|
|
|
|
else if (data is double)
|
|
|
|
{
|
|
|
|
return opcode.Size + 8;
|
|
|
|
}
|
|
|
|
else if (data is string)
|
|
|
|
{
|
|
|
|
return opcode.Size + 4;
|
|
|
|
}
|
|
|
|
else if (data is Type)
|
|
|
|
{
|
|
|
|
return opcode.Size + 4;
|
|
|
|
}
|
|
|
|
else if (data is CodeEmitterLocal)
|
|
|
|
{
|
|
|
|
int index = ((CodeEmitterLocal)data).__LocalIndex;
|
|
|
|
if(index < 4 && opcode.Value != OpCodes.Ldloca.Value && opcode.Value != OpCodes.Ldloca_S.Value)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if(index < 256)
|
|
|
|
{
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (data is CodeEmitterLabel)
|
|
|
|
{
|
|
|
|
switch(opcode.OperandType)
|
|
|
|
{
|
|
|
|
case OperandType.InlineBrTarget:
|
|
|
|
return opcode.Size + 4;
|
|
|
|
case OperandType.ShortInlineBrTarget:
|
|
|
|
return opcode.Size + 1;
|
|
|
|
default:
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (data is CodeEmitterLabel[])
|
|
|
|
{
|
|
|
|
return 5 + ((CodeEmitterLabel[])data).Length * 4;
|
|
|
|
}
|
|
|
|
else if (data is CalliWrapper)
|
|
|
|
{
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-10-01 13:22:47 +04:00
|
|
|
|
|
|
|
internal void RealEmit(int ilOffset, CodeEmitter codeEmitter)
|
|
|
|
{
|
|
|
|
if (pseudo == CodeType.OpCode)
|
|
|
|
{
|
|
|
|
codeEmitter.RealEmitOpCode(opcode, data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
codeEmitter.RealEmitPseudoOpCode(ilOffset, pseudo, data);
|
|
|
|
}
|
|
|
|
}
|
2010-09-30 08:03:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
sealed class CalliWrapper
|
|
|
|
{
|
|
|
|
internal readonly CallingConvention unmanagedCallConv;
|
|
|
|
internal readonly Type returnType;
|
|
|
|
internal readonly Type[] parameterTypes;
|
|
|
|
|
|
|
|
internal CalliWrapper(CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
|
|
|
|
{
|
|
|
|
this.unmanagedCallConv = unmanagedCallConv;
|
|
|
|
this.returnType = returnType;
|
|
|
|
this.parameterTypes = parameterTypes == null ? null : (Type[])parameterTypes.Clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal static CodeEmitter Create(MethodBuilder mb)
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2008-06-03 16:10:07 +04:00
|
|
|
return new CodeEmitter(mb.GetILGenerator());
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal static CodeEmitter Create(ConstructorBuilder cb)
|
|
|
|
{
|
|
|
|
return new CodeEmitter(cb.GetILGenerator());
|
|
|
|
}
|
|
|
|
|
2008-08-12 18:57:04 +04:00
|
|
|
#if !STATIC_COMPILER
|
2008-06-03 16:10:07 +04:00
|
|
|
internal static CodeEmitter Create(DynamicMethod dm)
|
|
|
|
{
|
|
|
|
return new CodeEmitter(dm.GetILGenerator());
|
|
|
|
}
|
2008-08-12 18:57:04 +04:00
|
|
|
#endif
|
2008-06-03 16:10:07 +04:00
|
|
|
|
|
|
|
private CodeEmitter(ILGenerator ilgen)
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2010-01-28 12:18:33 +03:00
|
|
|
#if STATIC_COMPILER
|
2009-08-14 17:36:53 +04:00
|
|
|
ilgen.__CleverExceptionBlockAssistance();
|
|
|
|
#endif
|
2008-02-15 18:32:51 +03:00
|
|
|
this.ilgen_real = ilgen;
|
|
|
|
}
|
|
|
|
|
2010-09-30 08:03:32 +04:00
|
|
|
private void EmitPseudoOpCode(CodeType type, object data)
|
|
|
|
{
|
2010-09-30 11:31:27 +04:00
|
|
|
code.Add(new OpCodeWrapper(type, data));
|
2010-09-30 08:03:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
private void EmitOpCode(OpCode opcode, object arg)
|
|
|
|
{
|
2010-09-30 11:31:27 +04:00
|
|
|
code.Add(new OpCodeWrapper(opcode, arg));
|
2010-09-30 08:03:32 +04:00
|
|
|
}
|
|
|
|
|
2010-09-30 10:00:40 +04:00
|
|
|
private void RealEmitPseudoOpCode(int ilOffset, CodeType type, object data)
|
2010-09-30 08:03:32 +04:00
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case CodeType.Nop:
|
|
|
|
break;
|
|
|
|
case CodeType.BeginScope:
|
|
|
|
ilgen_real.BeginScope();
|
|
|
|
break;
|
|
|
|
case CodeType.EndScope:
|
|
|
|
ilgen_real.EndScope();
|
|
|
|
break;
|
|
|
|
case CodeType.DeclareLocal:
|
|
|
|
((CodeEmitterLocal)data).Declare(ilgen_real);
|
|
|
|
break;
|
2010-10-01 10:40:49 +04:00
|
|
|
case CodeType.ReleaseTempLocal:
|
|
|
|
break;
|
2010-09-30 08:03:32 +04:00
|
|
|
case CodeType.SequencePoint:
|
|
|
|
ilgen_real.MarkSequencePoint(symbols, (int)data, 0, (int)data + 1, 0);
|
|
|
|
// we emit a nop to make sure we always have an instruction associated with the sequence point
|
|
|
|
ilgen_real.Emit(OpCodes.Nop);
|
|
|
|
break;
|
|
|
|
case CodeType.LineNumber:
|
|
|
|
if (linenums == null)
|
|
|
|
{
|
|
|
|
linenums = new IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter(32);
|
|
|
|
}
|
2010-09-30 10:00:40 +04:00
|
|
|
linenums.AddMapping(ilOffset, (int)data);
|
2010-09-30 08:03:32 +04:00
|
|
|
break;
|
|
|
|
case CodeType.Label:
|
2010-09-30 10:00:40 +04:00
|
|
|
((CodeEmitterLabel)data).Mark(ilgen_real);
|
2010-09-30 08:03:32 +04:00
|
|
|
break;
|
|
|
|
case CodeType.ThrowException:
|
|
|
|
ilgen_real.ThrowException((Type)data);
|
|
|
|
break;
|
|
|
|
case CodeType.BeginExceptionBlock:
|
|
|
|
ilgen_real.BeginExceptionBlock();
|
|
|
|
break;
|
|
|
|
case CodeType.BeginCatchBlock:
|
|
|
|
ilgen_real.BeginCatchBlock((Type)data);
|
|
|
|
break;
|
|
|
|
case CodeType.BeginFaultBlock:
|
|
|
|
ilgen_real.BeginFaultBlock();
|
|
|
|
break;
|
|
|
|
case CodeType.BeginFinallyBlock:
|
|
|
|
ilgen_real.BeginFinallyBlock();
|
|
|
|
break;
|
|
|
|
case CodeType.EndExceptionBlockFinally:
|
|
|
|
ilgen_real.EndExceptionBlock();
|
|
|
|
break;
|
|
|
|
case CodeType.EndExceptionBlock:
|
|
|
|
ilgen_real.EndExceptionBlock();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-30 11:31:27 +04:00
|
|
|
private void RealEmitOpCode(OpCode opcode, object arg)
|
2010-09-30 08:03:32 +04:00
|
|
|
{
|
|
|
|
if (arg == null)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode);
|
|
|
|
}
|
|
|
|
else if (arg is int)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (int)arg);
|
|
|
|
}
|
|
|
|
else if (arg is long)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (long)arg);
|
|
|
|
}
|
|
|
|
else if (arg is MethodInfo)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (MethodInfo)arg);
|
|
|
|
}
|
|
|
|
else if (arg is ConstructorInfo)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (ConstructorInfo)arg);
|
|
|
|
}
|
|
|
|
else if (arg is FieldInfo)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (FieldInfo)arg);
|
|
|
|
}
|
|
|
|
else if (arg is sbyte)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (sbyte)arg);
|
|
|
|
}
|
|
|
|
else if (arg is byte)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (byte)arg);
|
|
|
|
}
|
|
|
|
else if (arg is short)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (short)arg);
|
|
|
|
}
|
|
|
|
else if (arg is float)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (float)arg);
|
|
|
|
}
|
|
|
|
else if (arg is double)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (double)arg);
|
|
|
|
}
|
|
|
|
else if (arg is string)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (string)arg);
|
|
|
|
}
|
|
|
|
else if (arg is Type)
|
|
|
|
{
|
|
|
|
ilgen_real.Emit(opcode, (Type)arg);
|
|
|
|
}
|
|
|
|
else if (arg is CodeEmitterLocal)
|
|
|
|
{
|
|
|
|
CodeEmitterLocal local = (CodeEmitterLocal)arg;
|
|
|
|
local.Emit(ilgen_real, opcode);
|
|
|
|
}
|
|
|
|
else if (arg is CodeEmitterLabel)
|
|
|
|
{
|
|
|
|
CodeEmitterLabel label = (CodeEmitterLabel)arg;
|
|
|
|
ilgen_real.Emit(opcode, label.Label);
|
|
|
|
}
|
|
|
|
else if (arg is CodeEmitterLabel[])
|
|
|
|
{
|
|
|
|
CodeEmitterLabel[] labels = (CodeEmitterLabel[])arg;
|
|
|
|
Label[] real = new Label[labels.Length];
|
|
|
|
for (int i = 0; i < labels.Length; i++)
|
|
|
|
{
|
|
|
|
real[i] = labels[i].Label;
|
|
|
|
}
|
|
|
|
ilgen_real.Emit(opcode, real);
|
|
|
|
}
|
|
|
|
else if (arg is CalliWrapper)
|
|
|
|
{
|
|
|
|
CalliWrapper args = (CalliWrapper)arg;
|
|
|
|
ilgen_real.EmitCalli(opcode, args.unmanagedCallConv, args.returnType, args.parameterTypes);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void RemoveJumpNext()
|
|
|
|
{
|
|
|
|
for (int i = 1; i < code.Count; i++)
|
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
if (code[i].pseudo == CodeType.Label
|
2010-09-30 08:03:32 +04:00
|
|
|
&& code[i - 1].opcode == OpCodes.Br
|
2010-10-01 13:22:47 +04:00
|
|
|
&& code[i - 1].MatchLabel(code[i]))
|
2010-09-30 08:03:32 +04:00
|
|
|
{
|
2010-09-30 11:31:27 +04:00
|
|
|
code.RemoveAt(i - 1);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void AnnihilatePops()
|
|
|
|
{
|
|
|
|
for (int i = 1; i < code.Count; i++)
|
|
|
|
{
|
|
|
|
if (code[i].opcode == OpCodes.Pop
|
|
|
|
&& IsSideEffectFreePush(i - 1))
|
|
|
|
{
|
|
|
|
code.RemoveRange(i - 1, 2);
|
|
|
|
i -= 2;
|
2010-09-30 08:03:32 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-30 11:31:27 +04:00
|
|
|
private bool IsSideEffectFreePush(int index)
|
|
|
|
{
|
|
|
|
if (code[index].opcode == OpCodes.Ldstr)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (code[index].opcode == OpCodes.Ldnull)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (code[index].opcode == OpCodes.Ldsfld)
|
|
|
|
{
|
|
|
|
// Here we are considering BeforeFieldInit to mean that we really don't care about
|
|
|
|
// when the type is initialized (which is what we mean in the rest of the IKVM code as well)
|
|
|
|
// but it is good to point it out here because strictly speaking we're violating the
|
|
|
|
// BeforeFieldInit contract here by considering dummy loads not to be field accesses.
|
2010-10-01 13:22:47 +04:00
|
|
|
FieldInfo field = code[index].FieldInfo;
|
2010-09-30 11:31:27 +04:00
|
|
|
if (field != null && (field.DeclaringType.Attributes & TypeAttributes.BeforeFieldInit) != 0)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2010-09-30 14:04:54 +04:00
|
|
|
else if (code[index].opcode == OpCodes.Ldc_I4)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (code[index].opcode == OpCodes.Ldc_I8)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (code[index].opcode == OpCodes.Ldc_R4)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (code[index].opcode == OpCodes.Ldc_R8)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (code[index].opcode == OpCodes.Ldloc)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (code[index].opcode == OpCodes.Ldarg)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2010-09-30 11:31:27 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-30 10:00:40 +04:00
|
|
|
private void OptimizeBranchSizes()
|
|
|
|
{
|
|
|
|
int offset = 0;
|
|
|
|
for (int i = 0; i < code.Count; i++)
|
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
if (code[i].pseudo == CodeType.Label)
|
2010-09-30 10:00:40 +04:00
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[i].Label.Offset = offset;
|
2010-09-30 10:00:40 +04:00
|
|
|
}
|
|
|
|
offset += code[i].Size;
|
|
|
|
}
|
|
|
|
offset = 0;
|
|
|
|
for (int i = 0; i < code.Count; i++)
|
|
|
|
{
|
|
|
|
int prevOffset = offset;
|
|
|
|
offset += code[i].Size;
|
2010-10-01 13:22:47 +04:00
|
|
|
if (code[i].HasLabel && code[i].opcode.OperandType == OperandType.InlineBrTarget)
|
2010-09-30 10:00:40 +04:00
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
CodeEmitterLabel label = code[i].Label;
|
2010-09-30 10:00:40 +04:00
|
|
|
int diff = label.Offset - (prevOffset + code[i].opcode.Size + 1);
|
|
|
|
if (-128 <= diff && diff <= 127)
|
|
|
|
{
|
|
|
|
OpCode opcode = code[i].opcode;
|
|
|
|
if (opcode == OpCodes.Brtrue)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Brtrue_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Brfalse)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Brfalse_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Br)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Br_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Beq)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Beq_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Bne_Un)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Bne_Un_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Ble)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Ble_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Ble_Un)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Ble_Un_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Blt)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Blt_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Blt_Un)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Blt_Un_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Bge)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Bge_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Bge_Un)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Bge_Un_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Bgt)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Bgt_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Bgt_Un)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Bgt_Un_S;
|
|
|
|
}
|
|
|
|
else if (opcode == OpCodes.Leave)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Leave_S;
|
|
|
|
}
|
2010-10-01 13:22:47 +04:00
|
|
|
code[i] = new OpCodeWrapper(opcode, label);
|
2010-09-30 10:00:40 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-30 12:56:59 +04:00
|
|
|
private void OptimizePatterns()
|
|
|
|
{
|
|
|
|
for (int i = 1; i < code.Count; i++)
|
|
|
|
{
|
|
|
|
if (code[i].opcode == OpCodes.Isinst
|
|
|
|
&& code[i + 1].opcode == OpCodes.Ldnull
|
|
|
|
&& code[i + 2].opcode == OpCodes.Cgt_Un
|
|
|
|
&& (code[i + 3].opcode == OpCodes.Brfalse || code[i + 3].opcode == OpCodes.Brtrue))
|
|
|
|
{
|
|
|
|
code.RemoveRange(i + 1, 2);
|
|
|
|
}
|
|
|
|
else if (code[i].opcode == OpCodes.Ldelem_I1
|
2010-10-01 13:22:47 +04:00
|
|
|
&& code[i + 1].opcode == OpCodes.Ldc_I4 && code[i + 1].ValueInt32 == 255
|
2010-09-30 12:56:59 +04:00
|
|
|
&& code[i + 2].opcode == OpCodes.And)
|
|
|
|
{
|
|
|
|
code[i] = new OpCodeWrapper(OpCodes.Ldelem_U1, null);
|
|
|
|
code.RemoveRange(i + 1, 2);
|
|
|
|
}
|
|
|
|
else if (code[i].opcode == OpCodes.Ldelem_I1
|
|
|
|
&& code[i + 1].opcode == OpCodes.Conv_I8
|
2010-10-01 13:22:47 +04:00
|
|
|
&& code[i + 2].opcode == OpCodes.Ldc_I8 && code[i + 2].ValueInt64 == 255
|
2010-09-30 14:04:54 +04:00
|
|
|
&& code[i + 3].opcode == OpCodes.And)
|
2010-09-30 12:56:59 +04:00
|
|
|
{
|
|
|
|
code[i] = new OpCodeWrapper(OpCodes.Ldelem_U1, null);
|
2010-09-30 14:04:54 +04:00
|
|
|
code.RemoveRange(i + 2, 2);
|
2010-09-30 12:56:59 +04:00
|
|
|
}
|
2010-09-30 14:04:54 +04:00
|
|
|
else if (code[i].opcode == OpCodes.Ldc_I4
|
|
|
|
&& code[i + 1].opcode == OpCodes.Ldc_I4
|
|
|
|
&& code[i + 2].opcode == OpCodes.And)
|
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[i] = new OpCodeWrapper(OpCodes.Ldc_I4, code[i].ValueInt32 & code[i + 1].ValueInt32);
|
2010-09-30 14:04:54 +04:00
|
|
|
code.RemoveRange(i + 1, 2);
|
|
|
|
}
|
2010-09-30 19:15:34 +04:00
|
|
|
else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, Types.Double) // dcmpl
|
|
|
|
|| MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, Types.Single)) // fcmpl
|
|
|
|
{
|
|
|
|
PatchCompare(i, OpCodes.Ble_Un, OpCodes.Blt_Un, OpCodes.Bge, OpCodes.Bgt);
|
|
|
|
}
|
|
|
|
else if (MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, Types.Double) // dcmpg
|
|
|
|
|| MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, Types.Single)) // fcmpg
|
|
|
|
{
|
|
|
|
PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge_Un, OpCodes.Bgt_Un);
|
|
|
|
}
|
|
|
|
else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt, Types.Int64)) // lcmp
|
|
|
|
{
|
|
|
|
PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge, OpCodes.Bgt);
|
|
|
|
}
|
2010-10-01 08:41:06 +04:00
|
|
|
else if (i < code.Count - 10
|
|
|
|
&& code[i].opcode == OpCodes.Ldc_I4
|
|
|
|
&& code[i + 1].opcode == OpCodes.Dup
|
|
|
|
&& code[i + 2].opcode == OpCodes.Ldc_I4_M1
|
|
|
|
&& code[i + 3].opcode == OpCodes.Bne_Un_S
|
|
|
|
&& code[i + 4].opcode == OpCodes.Pop
|
|
|
|
&& code[i + 5].opcode == OpCodes.Neg
|
|
|
|
&& code[i + 6].opcode == OpCodes.Br_S
|
2010-10-01 10:40:49 +04:00
|
|
|
&& code[i + 7].pseudo == CodeType.Label && code[i + 7].Label == code[i + 3].Label
|
2010-10-01 08:41:06 +04:00
|
|
|
&& code[i + 8].opcode == OpCodes.Div
|
2010-10-01 10:40:49 +04:00
|
|
|
&& code[i + 9].pseudo == CodeType.Label && code[i + 9].Label == code[i + 6].Label)
|
2010-10-01 08:41:06 +04:00
|
|
|
{
|
|
|
|
int divisor = code[i].ValueInt32;
|
|
|
|
if (divisor == -1)
|
|
|
|
{
|
|
|
|
code[i] = code[i + 5];
|
|
|
|
code.RemoveRange(i + 1, 9);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
code[i + 1] = code[i + 8];
|
|
|
|
code.RemoveRange(i + 2, 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (i < code.Count - 11
|
|
|
|
&& code[i].opcode == OpCodes.Ldc_I8
|
|
|
|
&& code[i + 1].opcode == OpCodes.Dup
|
|
|
|
&& code[i + 2].opcode == OpCodes.Ldc_I4_M1
|
|
|
|
&& code[i + 3].opcode == OpCodes.Conv_I8
|
|
|
|
&& code[i + 4].opcode == OpCodes.Bne_Un_S
|
|
|
|
&& code[i + 5].opcode == OpCodes.Pop
|
|
|
|
&& code[i + 6].opcode == OpCodes.Neg
|
|
|
|
&& code[i + 7].opcode == OpCodes.Br_S
|
2010-10-01 10:40:49 +04:00
|
|
|
&& code[i + 8].pseudo == CodeType.Label && code[i + 8].Label == code[i + 4].Label
|
2010-10-01 08:41:06 +04:00
|
|
|
&& code[i + 9].opcode == OpCodes.Div
|
2010-10-01 10:40:49 +04:00
|
|
|
&& code[i + 10].pseudo == CodeType.Label && code[i + 10].Label == code[i + 7].Label)
|
2010-10-01 08:41:06 +04:00
|
|
|
{
|
|
|
|
long divisor = code[i].ValueInt64;
|
|
|
|
if (divisor == -1)
|
|
|
|
{
|
|
|
|
code[i] = code[i + 6];
|
|
|
|
code.RemoveRange(i + 1, 10);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
code[i + 1] = code[i + 9];
|
|
|
|
code.RemoveRange(i + 2, 9);
|
|
|
|
}
|
|
|
|
}
|
2010-10-01 10:40:49 +04:00
|
|
|
else if (code[i].opcode == OpCodes.Box
|
|
|
|
&& code[i + 1].opcode == OpCodes.Unbox && code[i + 1].Type == code[i].Type)
|
|
|
|
{
|
|
|
|
CodeEmitterLocal local = new CodeEmitterLocal(code[i].Type);
|
|
|
|
code[i] = new OpCodeWrapper(OpCodes.Stloc, local);
|
|
|
|
code[i + 1] = new OpCodeWrapper(OpCodes.Ldloca, local);
|
|
|
|
}
|
|
|
|
else if (i < code.Count - 13
|
|
|
|
&& code[i + 0].opcode == OpCodes.Box
|
|
|
|
&& code[i + 1].opcode == OpCodes.Dup
|
|
|
|
&& code[i + 2].opcode == OpCodes.Brtrue_S
|
|
|
|
&& code[i + 3].opcode == OpCodes.Pop
|
|
|
|
&& code[i + 4].opcode == OpCodes.Ldloca && code[i + 4].Local.LocalType == code[i + 0].Type
|
|
|
|
&& code[i + 5].opcode == OpCodes.Initobj && code[i + 5].Type == code[i + 0].Type
|
|
|
|
&& code[i + 6].opcode == OpCodes.Ldloc && code[i + 6].Local == code[i + 4].Local
|
|
|
|
&& code[i + 7].pseudo == CodeType.ReleaseTempLocal && code[i + 7].Local == code[i + 6].Local
|
|
|
|
&& code[i + 8].opcode == OpCodes.Br_S
|
|
|
|
&& code[i + 9].pseudo == CodeType.Label && code[i + 9].Label == code[i + 2].Label
|
|
|
|
&& code[i + 10].opcode == OpCodes.Unbox && code[i + 10].Type == code[i + 0].Type
|
|
|
|
&& code[i + 11].opcode == OpCodes.Ldobj && code[i + 11].Type == code[i + 0].Type
|
|
|
|
&& code[i + 12].pseudo == CodeType.Label && code[i + 12].Label == code[i + 8].Label)
|
|
|
|
{
|
|
|
|
code.RemoveRange(i, 13);
|
|
|
|
}
|
2010-09-30 19:15:34 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool MatchCompare(int index, OpCode cmp1, OpCode cmp2, Type type)
|
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
return code[index].opcode == OpCodes.Stloc && code[index].Local.LocalType == type
|
|
|
|
&& code[index + 1].opcode == OpCodes.Stloc && code[index + 1].Local.LocalType == type
|
|
|
|
&& code[index + 2].opcode == OpCodes.Ldloc && code[index + 2].MatchLocal(code[index + 1])
|
|
|
|
&& code[index + 3].opcode == OpCodes.Ldloc && code[index + 3].MatchLocal(code[index])
|
2010-09-30 19:15:34 +04:00
|
|
|
&& code[index + 4].opcode == cmp1
|
2010-10-01 13:22:47 +04:00
|
|
|
&& code[index + 5].opcode == OpCodes.Ldloc && code[index + 5].MatchLocal(code[index + 1])
|
|
|
|
&& code[index + 6].opcode == OpCodes.Ldloc && code[index + 6].MatchLocal(code[index])
|
2010-09-30 19:15:34 +04:00
|
|
|
&& code[index + 7].opcode == cmp2
|
|
|
|
&& code[index + 8].opcode == OpCodes.Sub
|
2010-10-01 10:40:49 +04:00
|
|
|
&& code[index + 9].pseudo == CodeType.ReleaseTempLocal && code[index + 9].Local == code[index].Local
|
|
|
|
&& code[index + 10].pseudo == CodeType.ReleaseTempLocal && code[index + 10].Local == code[index + 1].Local
|
2010-10-01 13:22:47 +04:00
|
|
|
&& ((code[index + 11].opcode.FlowControl == FlowControl.Cond_Branch && code[index + 11].HasLabel) ||
|
2010-10-01 10:40:49 +04:00
|
|
|
(code[index + 11].opcode == OpCodes.Ldc_I4_0
|
2010-10-01 13:22:47 +04:00
|
|
|
&& (code[index + 12].opcode.FlowControl == FlowControl.Cond_Branch && code[index + 12].HasLabel)));
|
2010-09-30 19:15:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
private void PatchCompare(int index, OpCode ble, OpCode blt, OpCode bge, OpCode bgt)
|
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
if (code[index + 11].opcode == OpCodes.Brtrue)
|
2010-09-30 19:15:34 +04:00
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[index] = new OpCodeWrapper(OpCodes.Bne_Un, code[index + 11].Label);
|
2010-10-01 10:40:49 +04:00
|
|
|
code.RemoveRange(index + 1, 11);
|
2010-09-30 19:15:34 +04:00
|
|
|
}
|
2010-10-01 10:40:49 +04:00
|
|
|
else if (code[index + 11].opcode == OpCodes.Brfalse)
|
2010-09-30 19:15:34 +04:00
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[index] = new OpCodeWrapper(OpCodes.Beq, code[index + 11].Label);
|
2010-10-01 10:40:49 +04:00
|
|
|
code.RemoveRange(index + 1, 11);
|
2010-09-30 19:15:34 +04:00
|
|
|
}
|
2010-10-01 10:40:49 +04:00
|
|
|
else if (code[index + 11].opcode == OpCodes.Ldc_I4_0)
|
2010-09-30 19:15:34 +04:00
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
if (code[index + 12].opcode == OpCodes.Ble)
|
2010-09-30 19:15:34 +04:00
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[index] = new OpCodeWrapper(ble, code[index + 12].Label);
|
2010-10-01 10:40:49 +04:00
|
|
|
code.RemoveRange(index + 1, 12);
|
2010-09-30 19:15:34 +04:00
|
|
|
}
|
2010-10-01 10:40:49 +04:00
|
|
|
else if (code[index + 12].opcode == OpCodes.Blt)
|
2010-09-30 19:15:34 +04:00
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[index] = new OpCodeWrapper(blt, code[index + 12].Label);
|
2010-10-01 10:40:49 +04:00
|
|
|
code.RemoveRange(index + 1, 12);
|
2010-09-30 19:15:34 +04:00
|
|
|
}
|
2010-10-01 10:40:49 +04:00
|
|
|
else if (code[index + 12].opcode == OpCodes.Bge)
|
2010-09-30 19:15:34 +04:00
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[index] = new OpCodeWrapper(bge, code[index + 12].Label);
|
2010-10-01 10:40:49 +04:00
|
|
|
code.RemoveRange(index + 1, 12);
|
2010-09-30 19:15:34 +04:00
|
|
|
}
|
2010-10-01 10:40:49 +04:00
|
|
|
else if (code[index + 12].opcode == OpCodes.Bgt)
|
2010-09-30 19:15:34 +04:00
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[index] = new OpCodeWrapper(bgt, code[index + 12].Label);
|
2010-10-01 10:40:49 +04:00
|
|
|
code.RemoveRange(index + 1, 12);
|
2010-09-30 19:15:34 +04:00
|
|
|
}
|
2010-09-30 14:04:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OptimizeEncodings()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < code.Count; i++)
|
|
|
|
{
|
|
|
|
if (code[i].opcode == OpCodes.Ldc_I4)
|
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[i] = OptimizeLdcI4(code[i].ValueInt32);
|
2010-09-30 14:04:54 +04:00
|
|
|
}
|
|
|
|
else if (code[i].opcode == OpCodes.Ldc_I8)
|
|
|
|
{
|
|
|
|
OptimizeLdcI8(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private OpCodeWrapper OptimizeLdcI4(int value)
|
|
|
|
{
|
|
|
|
switch (value)
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_M1, null);
|
|
|
|
case 0:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_0, null);
|
|
|
|
case 1:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_1, null);
|
|
|
|
case 2:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_2, null);
|
|
|
|
case 3:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_3, null);
|
|
|
|
case 4:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_4, null);
|
|
|
|
case 5:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_5, null);
|
|
|
|
case 6:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_6, null);
|
|
|
|
case 7:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_7, null);
|
|
|
|
case 8:
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_8, null);
|
|
|
|
default:
|
|
|
|
if (value >= -128 && value <= 127)
|
|
|
|
{
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4_S, (sbyte)value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return new OpCodeWrapper(OpCodes.Ldc_I4, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OptimizeLdcI8(int index)
|
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
long value = code[index].ValueInt64;
|
2010-09-30 14:04:54 +04:00
|
|
|
OpCode opc = OpCodes.Nop;
|
|
|
|
switch (value)
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
opc = OpCodes.Ldc_I4_M1;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
opc = OpCodes.Ldc_I4_0;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
opc = OpCodes.Ldc_I4_1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
opc = OpCodes.Ldc_I4_2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
opc = OpCodes.Ldc_I4_3;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
opc = OpCodes.Ldc_I4_4;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
opc = OpCodes.Ldc_I4_5;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
opc = OpCodes.Ldc_I4_6;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
opc = OpCodes.Ldc_I4_7;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
opc = OpCodes.Ldc_I4_8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (value >= -2147483648L && value <= 4294967295L)
|
|
|
|
{
|
|
|
|
if (value >= -128 && value <= 127)
|
|
|
|
{
|
|
|
|
code[index] = new OpCodeWrapper(OpCodes.Ldc_I4_S, (sbyte)value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
code[index] = new OpCodeWrapper(OpCodes.Ldc_I4, (int)value);
|
|
|
|
}
|
|
|
|
if (value < 0)
|
|
|
|
{
|
|
|
|
code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_I8, null));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_U8, null));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (opc != OpCodes.Nop)
|
|
|
|
{
|
|
|
|
code[index] = new OpCodeWrapper(opc, null);
|
|
|
|
code.Insert(index + 1, new OpCodeWrapper(OpCodes.Conv_I8, null));
|
2010-09-30 12:56:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-30 08:03:32 +04:00
|
|
|
internal void DoEmit()
|
|
|
|
{
|
|
|
|
RemoveJumpNext();
|
2010-09-30 11:31:27 +04:00
|
|
|
AnnihilatePops();
|
2010-09-30 12:56:59 +04:00
|
|
|
OptimizePatterns();
|
2010-09-30 14:04:54 +04:00
|
|
|
OptimizeEncodings();
|
2010-09-30 10:00:40 +04:00
|
|
|
OptimizeBranchSizes();
|
|
|
|
int ilOffset = 0;
|
2010-09-30 08:03:32 +04:00
|
|
|
for (int i = 0; i < code.Count; i++)
|
|
|
|
{
|
2010-10-01 13:22:47 +04:00
|
|
|
code[i].RealEmit(ilOffset, this);
|
2010-09-30 10:00:40 +04:00
|
|
|
#if STATIC_COMPILER || NET_4_0
|
|
|
|
ilOffset = ilgen_real.ILOffset;
|
|
|
|
#else
|
|
|
|
ilOffset += code[i].Size;
|
|
|
|
#endif
|
2010-09-30 08:03:32 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-28 12:02:07 +04:00
|
|
|
internal void DefineSymbolDocument(ModuleBuilder module, string url, Guid language, Guid languageVendor, Guid documentType)
|
|
|
|
{
|
|
|
|
symbols = module.DefineDocument(url, language, languageVendor, documentType);
|
|
|
|
}
|
|
|
|
|
2010-09-29 11:21:51 +04:00
|
|
|
internal CodeEmitterLocal UnsafeAllocTempLocal(Type type)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
int free = -1;
|
|
|
|
for (int i = 0; i < tempLocals.Length; i++)
|
|
|
|
{
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal lb = tempLocals[i];
|
2008-02-15 18:32:51 +03:00
|
|
|
if (lb == null)
|
|
|
|
{
|
|
|
|
if (free == -1)
|
|
|
|
{
|
|
|
|
free = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (lb.LocalType == type)
|
|
|
|
{
|
|
|
|
return lb;
|
|
|
|
}
|
|
|
|
}
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal lb1 = DeclareLocal(type);
|
2008-02-15 18:32:51 +03:00
|
|
|
if (free != -1)
|
|
|
|
{
|
|
|
|
tempLocals[free] = lb1;
|
|
|
|
}
|
|
|
|
return lb1;
|
|
|
|
}
|
|
|
|
|
2010-09-29 11:21:51 +04:00
|
|
|
internal CodeEmitterLocal AllocTempLocal(Type type)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
for (int i = 0; i < tempLocals.Length; i++)
|
|
|
|
{
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal lb = tempLocals[i];
|
2008-02-15 18:32:51 +03:00
|
|
|
if (lb != null && lb.LocalType == type)
|
|
|
|
{
|
|
|
|
tempLocals[i] = null;
|
|
|
|
return lb;
|
|
|
|
}
|
|
|
|
}
|
2010-09-30 19:15:34 +04:00
|
|
|
return new CodeEmitterLocal(type);
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2010-09-29 11:21:51 +04:00
|
|
|
internal void ReleaseTempLocal(CodeEmitterLocal lb)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
EmitPseudoOpCode(CodeType.ReleaseTempLocal, lb);
|
2008-02-15 18:32:51 +03:00
|
|
|
for (int i = 0; i < tempLocals.Length; i++)
|
|
|
|
{
|
|
|
|
if (tempLocals[i] == null)
|
|
|
|
{
|
|
|
|
tempLocals[i] = lb;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginCatchBlock(Type exceptionType)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.BeginCatchBlock, exceptionType);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2010-09-30 08:03:32 +04:00
|
|
|
internal void BeginExceptionBlock()
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
|
|
|
exceptionStack.Push(inFinally);
|
|
|
|
inFinally = false;
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.BeginExceptionBlock, null);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginFaultBlock()
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
inFinally = true;
|
|
|
|
EmitPseudoOpCode(CodeType.BeginFaultBlock, null);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginFinallyBlock()
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
inFinally = true;
|
|
|
|
EmitPseudoOpCode(CodeType.BeginFinallyBlock, null);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginScope()
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.BeginScope, null);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2010-09-29 11:21:51 +04:00
|
|
|
internal CodeEmitterLocal DeclareLocal(Type localType)
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
CodeEmitterLocal local = new CodeEmitterLocal(localType);
|
|
|
|
EmitPseudoOpCode(CodeType.DeclareLocal, local);
|
|
|
|
return local;
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal CodeEmitterLabel DefineLabel()
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2009-04-06 14:14:47 +04:00
|
|
|
CodeEmitterLabel label = new CodeEmitterLabel(ilgen_real.DefineLabel());
|
2004-11-04 15:50:28 +03:00
|
|
|
#if LABELCHECK
|
2005-12-19 18:12:49 +03:00
|
|
|
labels.Add(label, new System.Diagnostics.StackFrame(1, true));
|
2004-11-04 15:50:28 +03:00
|
|
|
#endif
|
2009-04-06 14:14:47 +04:00
|
|
|
return label;
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, null);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, byte arg)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, arg);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, ConstructorInfo con)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, con);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, double arg)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, arg);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, FieldInfo field)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, field);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, short arg)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, arg);
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, int arg)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, arg);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, long arg)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, arg);
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2005-06-01 13:49:30 +04:00
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal void Emit(OpCode opcode, CodeEmitterLabel label)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, label);
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2005-06-01 13:49:30 +04:00
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal void Emit(OpCode opcode, CodeEmitterLabel[] labels)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, labels);
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
|
|
|
|
2010-09-29 11:21:51 +04:00
|
|
|
internal void Emit(OpCode opcode, CodeEmitterLocal local)
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, local);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, MethodInfo meth)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, meth);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, sbyte arg)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, arg);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, float arg)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, arg);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, string arg)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, arg);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, Type cls)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, cls);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitOpCode(opcode, new CalliWrapper(unmanagedCallConv, returnType, parameterTypes));
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2009-08-14 17:36:53 +04:00
|
|
|
internal void EndExceptionBlockNoFallThrough()
|
|
|
|
{
|
|
|
|
EndExceptionBlock();
|
2010-01-28 12:18:33 +03:00
|
|
|
#if !STATIC_COMPILER
|
2009-08-14 17:36:53 +04:00
|
|
|
// HACK to keep the verifier happy we need this bogus jump
|
|
|
|
// (because of the bogus Leave that Ref.Emit ends the try block with)
|
|
|
|
Emit(OpCodes.Br_S, (sbyte)-2);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EndExceptionBlock()
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2005-06-01 13:49:30 +04:00
|
|
|
if(inFinally)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.EndExceptionBlockFinally, null);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.EndExceptionBlock, null);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2008-08-15 16:01:06 +04:00
|
|
|
inFinally = exceptionStack.Pop();
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EndScope()
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.EndScope, null);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal void MarkLabel(CodeEmitterLabel loc)
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2004-11-04 15:50:28 +03:00
|
|
|
#if LABELCHECK
|
2009-04-06 14:14:47 +04:00
|
|
|
labels.Remove(loc);
|
2004-11-04 15:50:28 +03:00
|
|
|
#endif
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.Label, loc);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void ThrowException(Type excType)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.ThrowException, excType);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void SetLineNumber(ushort line)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2010-09-28 12:02:07 +04:00
|
|
|
if (symbols != null)
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.SequencePoint, (int)line);
|
2010-09-28 12:02:07 +04:00
|
|
|
}
|
2010-10-01 10:40:49 +04:00
|
|
|
EmitPseudoOpCode(CodeType.LineNumber, (int)line);
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
|
|
|
|
2010-09-28 12:02:07 +04:00
|
|
|
internal byte[] GetLineNumberTable()
|
|
|
|
{
|
|
|
|
return linenums == null ? null : linenums.ToArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if STATIC_COMPILER
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EmitLineNumberTable(MethodBase mb)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2006-08-29 10:28:34 +04:00
|
|
|
if(linenums != null)
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2005-08-22 16:42:02 +04:00
|
|
|
AttributeHelper.SetLineNumberTable(mb, linenums);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2006-05-04 12:09:56 +04:00
|
|
|
#endif // STATIC_COMPILER
|
2004-11-04 15:50:28 +03:00
|
|
|
|
2009-08-31 09:02:34 +04:00
|
|
|
internal void EmitThrow(string dottedClassName)
|
|
|
|
{
|
|
|
|
TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dottedClassName);
|
|
|
|
MethodWrapper mw = exception.GetMethodWrapper("<init>", "()V", false);
|
|
|
|
mw.Link();
|
|
|
|
mw.EmitNewobj(this);
|
|
|
|
Emit(OpCodes.Throw);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void EmitThrow(string dottedClassName, string message)
|
|
|
|
{
|
|
|
|
TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dottedClassName);
|
|
|
|
Emit(OpCodes.Ldstr, message);
|
|
|
|
MethodWrapper mw = exception.GetMethodWrapper("<init>", "(Ljava.lang.String;)V", false);
|
|
|
|
mw.Link();
|
|
|
|
mw.EmitNewobj(this);
|
|
|
|
Emit(OpCodes.Throw);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void EmitNullCheck()
|
|
|
|
{
|
|
|
|
// I think this is the most efficient way to generate a NullReferenceException if the reference is null
|
|
|
|
Emit(OpCodes.Ldvirtftn, objectToString);
|
|
|
|
Emit(OpCodes.Pop);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void EmitCastclass(Type type)
|
|
|
|
{
|
|
|
|
if (verboseCastFailure != null)
|
|
|
|
{
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal lb = DeclareLocal(Types.Object);
|
2009-08-31 09:02:34 +04:00
|
|
|
Emit(OpCodes.Stloc, lb);
|
|
|
|
Emit(OpCodes.Ldloc, lb);
|
|
|
|
Emit(OpCodes.Isinst, type);
|
|
|
|
Emit(OpCodes.Dup);
|
|
|
|
CodeEmitterLabel ok = DefineLabel();
|
|
|
|
Emit(OpCodes.Brtrue_S, ok);
|
|
|
|
Emit(OpCodes.Ldloc, lb);
|
|
|
|
Emit(OpCodes.Brfalse_S, ok); // handle null
|
|
|
|
Emit(OpCodes.Ldtoken, type);
|
|
|
|
Emit(OpCodes.Ldloc, lb);
|
|
|
|
Emit(OpCodes.Call, verboseCastFailure);
|
|
|
|
MarkLabel(ok);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Emit(OpCodes.Castclass, type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is basically the same as Castclass, except that it
|
|
|
|
// throws an IncompatibleClassChangeError on failure.
|
|
|
|
internal void EmitAssertType(Type type)
|
|
|
|
{
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal lb = DeclareLocal(Types.Object);
|
2009-08-31 09:02:34 +04:00
|
|
|
Emit(OpCodes.Stloc, lb);
|
|
|
|
Emit(OpCodes.Ldloc, lb);
|
|
|
|
Emit(OpCodes.Isinst, type);
|
|
|
|
Emit(OpCodes.Dup);
|
|
|
|
CodeEmitterLabel ok = DefineLabel();
|
|
|
|
Emit(OpCodes.Brtrue_S, ok);
|
|
|
|
Emit(OpCodes.Ldloc, lb);
|
|
|
|
Emit(OpCodes.Brfalse_S, ok); // handle null
|
|
|
|
EmitThrow("java.lang.IncompatibleClassChangeError");
|
|
|
|
MarkLabel(ok);
|
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void EmitUnboxSpecial(Type type)
|
2005-12-19 18:12:49 +03:00
|
|
|
{
|
2010-10-01 10:40:49 +04:00
|
|
|
// NOTE if the reference is null, we treat it as a default instance of the value type.
|
|
|
|
Emit(OpCodes.Dup);
|
|
|
|
CodeEmitterLabel label1 = DefineLabel();
|
|
|
|
Emit(OpCodes.Brtrue_S, label1);
|
|
|
|
Emit(OpCodes.Pop);
|
|
|
|
CodeEmitterLocal local = AllocTempLocal(type);
|
|
|
|
Emit(OpCodes.Ldloca, local);
|
|
|
|
Emit(OpCodes.Initobj, type);
|
|
|
|
Emit(OpCodes.Ldloc, local);
|
|
|
|
ReleaseTempLocal(local);
|
|
|
|
CodeEmitterLabel label2 = DefineLabel();
|
|
|
|
Emit(OpCodes.Br_S, label2);
|
|
|
|
MarkLabel(label1);
|
|
|
|
Emit(OpCodes.Unbox, type);
|
|
|
|
Emit(OpCodes.Ldobj, type);
|
|
|
|
MarkLabel(label2);
|
2005-12-19 18:12:49 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
// the purpose of this method is to avoid calling a wrong overload of Emit()
|
|
|
|
// (e.g. when passing a byte or short)
|
|
|
|
internal void Emit_Ldc_I4(int i)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2010-10-01 08:41:06 +04:00
|
|
|
Emit(OpCodes.Ldc_I4, i);
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_idiv()
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
// we need to special case dividing by -1, because the CLR div instruction
|
|
|
|
// throws an OverflowException when dividing Int32.MinValue by -1, and
|
|
|
|
// Java just silently overflows
|
2010-10-01 08:41:06 +04:00
|
|
|
Emit(OpCodes.Dup);
|
|
|
|
Emit(OpCodes.Ldc_I4_M1);
|
|
|
|
CodeEmitterLabel label = DefineLabel();
|
|
|
|
Emit(OpCodes.Bne_Un_S, label);
|
|
|
|
Emit(OpCodes.Pop);
|
|
|
|
Emit(OpCodes.Neg);
|
|
|
|
CodeEmitterLabel label2 = DefineLabel();
|
|
|
|
Emit(OpCodes.Br_S, label2);
|
|
|
|
MarkLabel(label);
|
|
|
|
Emit(OpCodes.Div);
|
|
|
|
MarkLabel(label2);
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_ldiv()
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
// we need to special case dividing by -1, because the CLR div instruction
|
|
|
|
// throws an OverflowException when dividing Int32.MinValue by -1, and
|
|
|
|
// Java just silently overflows
|
2010-10-01 08:41:06 +04:00
|
|
|
Emit(OpCodes.Dup);
|
|
|
|
Emit(OpCodes.Ldc_I4_M1);
|
|
|
|
Emit(OpCodes.Conv_I8);
|
|
|
|
CodeEmitterLabel label = DefineLabel();
|
|
|
|
Emit(OpCodes.Bne_Un_S, label);
|
|
|
|
Emit(OpCodes.Pop);
|
|
|
|
Emit(OpCodes.Neg);
|
|
|
|
CodeEmitterLabel label2 = DefineLabel();
|
|
|
|
Emit(OpCodes.Br_S, label2);
|
|
|
|
MarkLabel(label);
|
|
|
|
Emit(OpCodes.Div);
|
|
|
|
MarkLabel(label2);
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_instanceof(Type type)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2010-09-30 12:56:59 +04:00
|
|
|
Emit(OpCodes.Isinst, type);
|
|
|
|
Emit(OpCodes.Ldnull);
|
|
|
|
Emit(OpCodes.Cgt_Un);
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
2008-02-15 18:32:51 +03:00
|
|
|
internal enum Comparison
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2008-02-15 18:32:51 +03:00
|
|
|
LessOrEqual,
|
|
|
|
LessThan,
|
|
|
|
GreaterOrEqual,
|
|
|
|
GreaterThan
|
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_if_le_lt_ge_gt(Comparison comp, CodeEmitterLabel label)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-30 19:15:34 +04:00
|
|
|
// don't change this Ldc_I4_0 to Ldc_I4(0) because the optimizer recognizes
|
|
|
|
// only this specific pattern
|
|
|
|
Emit(OpCodes.Ldc_I4_0);
|
2008-02-15 18:32:51 +03:00
|
|
|
switch (comp)
|
|
|
|
{
|
|
|
|
case Comparison.LessOrEqual:
|
|
|
|
Emit(OpCodes.Ble, label);
|
|
|
|
break;
|
|
|
|
case Comparison.LessThan:
|
|
|
|
Emit(OpCodes.Blt, label);
|
|
|
|
break;
|
|
|
|
case Comparison.GreaterOrEqual:
|
|
|
|
Emit(OpCodes.Bge, label);
|
|
|
|
break;
|
|
|
|
case Comparison.GreaterThan:
|
|
|
|
Emit(OpCodes.Bgt, label);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-30 19:15:34 +04:00
|
|
|
private void EmitCmp(Type type, OpCode cmp1, OpCode cmp2)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-30 19:15:34 +04:00
|
|
|
CodeEmitterLocal value1 = AllocTempLocal(type);
|
|
|
|
CodeEmitterLocal value2 = AllocTempLocal(type);
|
|
|
|
Emit(OpCodes.Stloc, value2);
|
|
|
|
Emit(OpCodes.Stloc, value1);
|
|
|
|
Emit(OpCodes.Ldloc, value1);
|
|
|
|
Emit(OpCodes.Ldloc, value2);
|
|
|
|
Emit(cmp1);
|
|
|
|
Emit(OpCodes.Ldloc, value1);
|
|
|
|
Emit(OpCodes.Ldloc, value2);
|
|
|
|
Emit(cmp2);
|
|
|
|
Emit(OpCodes.Sub);
|
|
|
|
ReleaseTempLocal(value2);
|
|
|
|
ReleaseTempLocal(value1);
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_lcmp()
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-30 19:15:34 +04:00
|
|
|
EmitCmp(Types.Int64, OpCodes.Cgt, OpCodes.Clt);
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_fcmpl()
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-30 19:15:34 +04:00
|
|
|
EmitCmp(Types.Single, OpCodes.Cgt, OpCodes.Clt_Un);
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_fcmpg()
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-30 19:15:34 +04:00
|
|
|
EmitCmp(Types.Single, OpCodes.Cgt_Un, OpCodes.Clt);
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_dcmpl()
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-30 19:15:34 +04:00
|
|
|
EmitCmp(Types.Double, OpCodes.Cgt, OpCodes.Clt_Un);
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_dcmpg()
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-30 19:15:34 +04:00
|
|
|
EmitCmp(Types.Double, OpCodes.Cgt_Un, OpCodes.Clt);
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2010-10-01 12:11:49 +04:00
|
|
|
internal void Emit_And_I4(int v)
|
2009-07-14 11:25:46 +04:00
|
|
|
{
|
2010-10-01 12:11:49 +04:00
|
|
|
Emit(OpCodes.Ldc_I4, v);
|
2010-09-30 12:56:59 +04:00
|
|
|
Emit(OpCodes.And);
|
2009-07-14 11:25:46 +04:00
|
|
|
}
|
|
|
|
|
2009-04-06 14:10:17 +04:00
|
|
|
internal void CheckLabels()
|
2005-12-19 18:12:49 +03:00
|
|
|
{
|
|
|
|
#if LABELCHECK
|
|
|
|
foreach(System.Diagnostics.StackFrame frame in labels.Values)
|
|
|
|
{
|
|
|
|
string name = frame.GetFileName() + ":" + frame.GetFileLineNumber();
|
|
|
|
IKVM.Internal.JVM.CriticalFailure("Label failure: " + name, null);
|
|
|
|
}
|
2004-11-04 15:50:28 +03:00
|
|
|
#endif
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-11-04 15:50:28 +03:00
|
|
|
}
|
2003-05-30 16:08:59 +04:00
|
|
|
}
|