2003-05-30 16:08:59 +04:00
|
|
|
/*
|
2009-04-06 14:10:17 +04:00
|
|
|
Copyright (C) 2002, 2004, 2005, 2006, 2008, 2009 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 08:03:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void Mark(ILGenerator ilgen, int offset)
|
|
|
|
{
|
|
|
|
ilgen.MarkLabel(label);
|
|
|
|
this.offset = offset;
|
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
|
|
|
#if !STATIC_COMPILER
|
|
|
|
internal int __LocalIndex
|
|
|
|
{
|
|
|
|
get { return local.LocalIndex; }
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
internal void Emit(ILGenerator ilgen, OpCode opcode)
|
2010-09-29 11:21:51 +04:00
|
|
|
{
|
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;
|
2010-01-28 12:18:33 +03:00
|
|
|
#if !STATIC_COMPILER
|
2005-06-01 13:49:30 +04:00
|
|
|
private int offset;
|
|
|
|
private bool inFinally;
|
2010-09-30 08:03:32 +04:00
|
|
|
private Stack<bool> exceptionStack = new Stack<bool>();
|
|
|
|
#endif
|
2005-06-19 14:44:53 +04:00
|
|
|
private IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter linenums;
|
2009-02-27 09:17:06 +03:00
|
|
|
private Expr[] stackArray = new Expr[8];
|
|
|
|
private int topOfStack;
|
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,
|
|
|
|
SequencePoint,
|
|
|
|
LineNumber,
|
|
|
|
Label,
|
|
|
|
WriteLine,
|
|
|
|
ThrowException,
|
|
|
|
BeginExceptionBlock,
|
|
|
|
BeginCatchBlock,
|
|
|
|
BeginFaultBlock,
|
|
|
|
BeginFinallyBlock,
|
|
|
|
EndExceptionBlock,
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
EndExceptionBlockFinally,
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
struct OpCodeWrapper
|
|
|
|
{
|
|
|
|
internal readonly CodeType type;
|
|
|
|
internal readonly OpCode opcode;
|
|
|
|
internal readonly object data;
|
|
|
|
|
|
|
|
internal OpCodeWrapper(CodeType type, OpCode opcode, object data)
|
|
|
|
{
|
|
|
|
this.type = type;
|
|
|
|
this.opcode = opcode;
|
|
|
|
this.data = data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
code.Add(new OpCodeWrapper(type, OpCodes.Nop, data));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void EmitOpCode(OpCode opcode, object arg)
|
|
|
|
{
|
|
|
|
code.Add(new OpCodeWrapper(CodeType.OpCode, opcode, arg));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void RealEmitPseudoOpCode(CodeType type, object data)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
linenums.AddMapping(GetILOffset(), (int)data);
|
|
|
|
break;
|
|
|
|
case CodeType.Label:
|
|
|
|
((CodeEmitterLabel)data).Mark(ilgen_real, GetILOffset());
|
|
|
|
break;
|
|
|
|
case CodeType.WriteLine:
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += 10;
|
|
|
|
#endif
|
|
|
|
ilgen_real.EmitWriteLine((string)data);
|
|
|
|
break;
|
|
|
|
case CodeType.ThrowException:
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += 6;
|
|
|
|
#endif
|
|
|
|
ilgen_real.ThrowException((Type)data);
|
|
|
|
break;
|
|
|
|
case CodeType.BeginExceptionBlock:
|
|
|
|
ilgen_real.BeginExceptionBlock();
|
|
|
|
break;
|
|
|
|
case CodeType.BeginCatchBlock:
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += 5;
|
|
|
|
#endif
|
|
|
|
ilgen_real.BeginCatchBlock((Type)data);
|
|
|
|
break;
|
|
|
|
case CodeType.BeginFaultBlock:
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += 5;
|
|
|
|
#endif
|
|
|
|
ilgen_real.BeginFaultBlock();
|
|
|
|
break;
|
|
|
|
case CodeType.BeginFinallyBlock:
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += 5;
|
|
|
|
#endif
|
|
|
|
ilgen_real.BeginFinallyBlock();
|
|
|
|
break;
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
case CodeType.EndExceptionBlockFinally:
|
|
|
|
offset += 1;
|
|
|
|
ilgen_real.EndExceptionBlock();
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case CodeType.EndExceptionBlock:
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += 5;
|
|
|
|
#endif
|
|
|
|
ilgen_real.EndExceptionBlock();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void RealEmitOpCode(OpCode opcode, object arg)
|
|
|
|
{
|
|
|
|
if (arg == null)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode);
|
|
|
|
}
|
|
|
|
else if (arg is int)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (int)arg);
|
|
|
|
}
|
|
|
|
else if (arg is long)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 8;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (long)arg);
|
|
|
|
}
|
|
|
|
else if (arg is MethodInfo)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (MethodInfo)arg);
|
|
|
|
}
|
|
|
|
else if (arg is ConstructorInfo)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (ConstructorInfo)arg);
|
|
|
|
}
|
|
|
|
else if (arg is FieldInfo)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (FieldInfo)arg);
|
|
|
|
}
|
|
|
|
else if (arg is sbyte)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 1;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (sbyte)arg);
|
|
|
|
}
|
|
|
|
else if (arg is byte)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 1;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (byte)arg);
|
|
|
|
}
|
|
|
|
else if (arg is short)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 2;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (short)arg);
|
|
|
|
}
|
|
|
|
else if (arg is float)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (float)arg);
|
|
|
|
}
|
|
|
|
else if (arg is double)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 8;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (double)arg);
|
|
|
|
}
|
|
|
|
else if (arg is string)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (string)arg);
|
|
|
|
}
|
|
|
|
else if (arg is Type)
|
|
|
|
{
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, (Type)arg);
|
|
|
|
}
|
|
|
|
else if (arg is CodeEmitterLocal)
|
|
|
|
{
|
|
|
|
CodeEmitterLocal local = (CodeEmitterLocal)arg;
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
int index = local.__LocalIndex;
|
|
|
|
if(index < 4 && opcode.Value != OpCodes.Ldloca.Value && opcode.Value != OpCodes.Ldloca_S.Value)
|
|
|
|
{
|
|
|
|
offset += 1;
|
|
|
|
}
|
|
|
|
else if(index < 256)
|
|
|
|
{
|
|
|
|
offset += 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
offset += 4;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
local.Emit(ilgen_real, opcode);
|
|
|
|
}
|
|
|
|
else if (arg is CodeEmitterLabel)
|
|
|
|
{
|
|
|
|
CodeEmitterLabel label = (CodeEmitterLabel)arg;
|
|
|
|
int currOffset = GetILOffset();
|
|
|
|
if (label.Offset == -1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else if (currOffset - label.Offset < 126)
|
|
|
|
{
|
|
|
|
if (opcode.Value == OpCodes.Brtrue.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Brtrue_S;
|
|
|
|
}
|
|
|
|
else if (opcode.Value == OpCodes.Brfalse.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Brfalse_S;
|
|
|
|
}
|
|
|
|
else if (opcode.Value == OpCodes.Br.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Br_S;
|
|
|
|
}
|
|
|
|
else if (opcode.Value == OpCodes.Beq.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Beq_S;
|
|
|
|
}
|
|
|
|
else if (opcode.Value == OpCodes.Bne_Un.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Bne_Un_S;
|
|
|
|
}
|
|
|
|
else if (opcode.Value == OpCodes.Ble.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Ble_S;
|
|
|
|
}
|
|
|
|
else if (opcode.Value == OpCodes.Blt.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Blt_S;
|
|
|
|
}
|
|
|
|
else if (opcode.Value == OpCodes.Bge.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Bge_S;
|
|
|
|
}
|
|
|
|
else if (opcode.Value == OpCodes.Bgt.Value)
|
|
|
|
{
|
|
|
|
opcode = OpCodes.Bgt_S;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
switch(opcode.OperandType)
|
|
|
|
{
|
|
|
|
case OperandType.InlineBrTarget:
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
break;
|
|
|
|
case OperandType.ShortInlineBrTarget:
|
|
|
|
offset += opcode.Size + 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ilgen_real.Emit(opcode, label.Label);
|
|
|
|
}
|
|
|
|
else if (arg is CodeEmitterLabel[])
|
|
|
|
{
|
|
|
|
CodeEmitterLabel[] labels = (CodeEmitterLabel[])arg;
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += 5 + labels.Length * 4;
|
|
|
|
#endif
|
|
|
|
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);
|
|
|
|
#if !STATIC_COMPILER
|
|
|
|
offset += 5;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-27 09:17:06 +03:00
|
|
|
private void PushStack(Expr expr)
|
|
|
|
{
|
|
|
|
Debug.Assert(expr != null);
|
|
|
|
if (topOfStack == stackArray.Length)
|
|
|
|
{
|
|
|
|
Array.Resize(ref stackArray, stackArray.Length * 2);
|
|
|
|
}
|
|
|
|
stackArray[topOfStack++] = expr;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void PushStackMayBeNull(Expr expr)
|
|
|
|
{
|
|
|
|
if (expr != null)
|
|
|
|
{
|
|
|
|
PushStack(expr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Expr PopStack()
|
|
|
|
{
|
|
|
|
if (topOfStack == 0)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return stackArray[--topOfStack];
|
|
|
|
}
|
|
|
|
|
|
|
|
private Expr PeekStack()
|
|
|
|
{
|
|
|
|
if (topOfStack == 0)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return stackArray[topOfStack - 1];
|
|
|
|
}
|
|
|
|
|
2010-09-30 08:03:32 +04:00
|
|
|
private void RemoveJumpNext()
|
|
|
|
{
|
|
|
|
for (int i = 1; i < code.Count; i++)
|
|
|
|
{
|
|
|
|
if (code[i].type == CodeType.Label
|
|
|
|
&& code[i - 1].type == CodeType.OpCode
|
|
|
|
&& code[i - 1].opcode == OpCodes.Br
|
|
|
|
&& code[i - 1].data == code[i].data)
|
|
|
|
{
|
|
|
|
code[i - 1] = new OpCodeWrapper(CodeType.Nop, OpCodes.Nop, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void DoEmit()
|
|
|
|
{
|
|
|
|
RemoveJumpNext();
|
|
|
|
for (int i = 0; i < code.Count; i++)
|
|
|
|
{
|
|
|
|
if (code[i].type == CodeType.OpCode)
|
|
|
|
{
|
|
|
|
RealEmitOpCode(code[i].opcode, code[i].data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RealEmitPseudoOpCode(code[i].type, code[i].data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return DeclareLocal(type);
|
|
|
|
}
|
|
|
|
|
2010-09-29 11:21:51 +04:00
|
|
|
internal void ReleaseTempLocal(CodeEmitterLocal 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
|
|
|
|
2010-09-28 12:02:07 +04:00
|
|
|
private int GetILOffset()
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
2010-01-28 12:18:33 +03:00
|
|
|
#if STATIC_COMPILER
|
2009-11-06 08:13:37 +03:00
|
|
|
return ilgen_real.ILOffset;
|
2009-08-13 11:16:19 +04:00
|
|
|
#else
|
2005-06-01 13:49:30 +04:00
|
|
|
return offset;
|
2009-08-13 11:16:19 +04:00
|
|
|
#endif
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
2010-09-30 08:03:32 +04:00
|
|
|
#if !STATIC_COMPILER
|
2005-06-01 13:49:30 +04:00
|
|
|
exceptionStack.Push(inFinally);
|
|
|
|
inFinally = false;
|
2010-09-30 08:03:32 +04:00
|
|
|
#endif
|
|
|
|
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()
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
2010-01-28 12:18:33 +03:00
|
|
|
#if !STATIC_COMPILER
|
2010-09-30 08:03:32 +04:00
|
|
|
inFinally = true;
|
2009-08-13 11:16:19 +04:00
|
|
|
#endif
|
2010-09-30 08:03:32 +04:00
|
|
|
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()
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
2010-01-28 12:18:33 +03:00
|
|
|
#if !STATIC_COMPILER
|
2010-09-30 08:03:32 +04:00
|
|
|
inFinally = true;
|
2009-08-13 11:16:19 +04:00
|
|
|
#endif
|
2010-09-30 08:03:32 +04:00
|
|
|
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()
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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
|
|
|
LazyGen();
|
|
|
|
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
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EmitWriteLine(string value)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.WriteLine, value);
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2005-06-01 13:49:30 +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-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
2010-09-30 08:03:32 +04:00
|
|
|
#if STATIC_COMPILER
|
|
|
|
EmitPseudoOpCode(CodeType.EndExceptionBlock, null);
|
|
|
|
#else
|
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();
|
2010-09-30 08:03:32 +04:00
|
|
|
#endif
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EndScope()
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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)
|
|
|
|
{
|
2005-12-19 18:12:49 +03:00
|
|
|
LazyGen();
|
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-28 12:02:07 +04:00
|
|
|
LazyGen();
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.SequencePoint, (int)line);
|
2010-09-28 12:02:07 +04:00
|
|
|
}
|
|
|
|
// we only add a line number mapping if the stack is empty because the CLR JIT only generates native to IL mappings
|
|
|
|
// for locations where the stack is empty and we don't want to needlessly flush the stack
|
|
|
|
if (topOfStack == 0)
|
|
|
|
{
|
2010-09-30 08:03:32 +04:00
|
|
|
EmitPseudoOpCode(CodeType.LineNumber, (int)line);
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
|
2009-02-27 09:17:06 +03:00
|
|
|
internal void LazyEmitPop()
|
|
|
|
{
|
|
|
|
Expr exp = PeekStack();
|
2009-03-02 07:52:05 +03:00
|
|
|
if (exp == null || exp.HasSideEffect || exp.IsIncomplete)
|
2009-02-27 09:17:06 +03:00
|
|
|
{
|
|
|
|
Emit(OpCodes.Pop);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PopStack();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-02 09:31:55 +03:00
|
|
|
internal void LazyEmitLoadClass(TypeWrapper type)
|
2009-02-27 09:17:06 +03:00
|
|
|
{
|
|
|
|
PushStack(new ClassLiteralExpr(type));
|
|
|
|
}
|
|
|
|
|
2005-12-19 18:12:49 +03:00
|
|
|
internal void LazyEmitBox(Type type)
|
2005-06-01 13:49:30 +04:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new BoxExpr(PopStack(), type));
|
2005-12-19 18:12:49 +03:00
|
|
|
}
|
|
|
|
|
2006-11-27 10:39:30 +03:00
|
|
|
internal void LazyEmitUnbox(Type type)
|
2005-12-20 15:44:29 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
BoxExpr box = PeekStack() as BoxExpr;
|
2006-11-27 10:39:30 +03:00
|
|
|
if(box != null)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
|
|
|
PushStack(new BoxUnboxExpr(box.Expr, type));
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new UnboxExpr(PopStack(), type));
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
2005-12-20 15:44:29 +03:00
|
|
|
}
|
|
|
|
|
2006-11-27 10:39:30 +03:00
|
|
|
internal void LazyEmitLdobj(Type type)
|
2005-12-20 15:44:29 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
BoxUnboxExpr boxunbox = PeekStack() as BoxUnboxExpr;
|
2006-11-27 10:39:30 +03:00
|
|
|
if(boxunbox != null)
|
2005-12-20 15:44:29 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2006-11-27 10:39:30 +03:00
|
|
|
// box/unbox+ldobj annihilate each other
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStackMayBeNull(boxunbox.Expr);
|
2005-12-20 15:44:29 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new LdobjExpr(PopStack(), type));
|
2005-12-20 15:44:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-19 18:12:49 +03:00
|
|
|
internal void LazyEmitUnboxSpecial(Type type)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
BoxExpr box = PeekStack() as BoxExpr;
|
2006-11-27 10:39:30 +03:00
|
|
|
if(box != null)
|
2005-12-19 18:12:49 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2005-12-19 18:12:49 +03:00
|
|
|
// the unbox and lazy box cancel each other out
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStackMayBeNull(box.Expr);
|
2005-12-19 18:12:49 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// NOTE if the reference is null, we treat it as a default instance of the value type.
|
|
|
|
Emit(OpCodes.Dup);
|
2008-06-03 16:10:07 +04:00
|
|
|
CodeEmitterLabel label1 = DefineLabel();
|
2005-12-19 18:12:49 +03:00
|
|
|
Emit(OpCodes.Brtrue_S, label1);
|
|
|
|
Emit(OpCodes.Pop);
|
|
|
|
Emit(OpCodes.Ldloc, DeclareLocal(type));
|
2008-06-03 16:10:07 +04:00
|
|
|
CodeEmitterLabel label2 = DefineLabel();
|
2005-12-19 18:12:49 +03:00
|
|
|
Emit(OpCodes.Br_S, label2);
|
|
|
|
MarkLabel(label1);
|
|
|
|
Emit(OpCodes.Unbox, type);
|
|
|
|
Emit(OpCodes.Ldobj, type);
|
|
|
|
MarkLabel(label2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-27 09:17:06 +03:00
|
|
|
internal void LazyEmitLdnull()
|
|
|
|
{
|
|
|
|
PushStack(new NullExpr());
|
|
|
|
}
|
|
|
|
|
2006-11-27 10:39:30 +03:00
|
|
|
internal void LazyEmitLdc_I4(int i)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new ConstIntExpr(i));
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmitLdc_I8(long l)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new ConstLongExpr(l));
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
2007-06-12 13:47:40 +04:00
|
|
|
internal void LazyEmitLdstr(string str)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new ConstStringExpr(str));
|
2007-06-12 13:47:40 +04:00
|
|
|
}
|
|
|
|
|
2006-11-27 10:39:30 +03:00
|
|
|
internal void LazyEmit_idiv()
|
|
|
|
{
|
|
|
|
// 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
|
2009-02-27 09:17:06 +03:00
|
|
|
ConstIntExpr v = PeekStack() as ConstIntExpr;
|
2006-11-27 10:39:30 +03:00
|
|
|
if(v != null)
|
|
|
|
{
|
|
|
|
if(v.i == -1)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2006-11-27 10:39:30 +03:00
|
|
|
Emit(OpCodes.Neg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Emit(OpCodes.Div);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Emit(OpCodes.Dup);
|
|
|
|
Emit(OpCodes.Ldc_I4_M1);
|
2008-06-03 16:10:07 +04:00
|
|
|
CodeEmitterLabel label = DefineLabel();
|
2006-11-27 10:39:30 +03:00
|
|
|
Emit(OpCodes.Bne_Un_S, label);
|
|
|
|
Emit(OpCodes.Pop);
|
|
|
|
Emit(OpCodes.Neg);
|
2008-06-03 16:10:07 +04:00
|
|
|
CodeEmitterLabel label2 = DefineLabel();
|
2006-11-27 10:39:30 +03:00
|
|
|
Emit(OpCodes.Br_S, label2);
|
|
|
|
MarkLabel(label);
|
|
|
|
Emit(OpCodes.Div);
|
|
|
|
MarkLabel(label2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_ldiv()
|
|
|
|
{
|
|
|
|
// 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
|
2009-02-27 09:17:06 +03:00
|
|
|
ConstLongExpr v = PeekStack() as ConstLongExpr;
|
2006-11-27 10:39:30 +03:00
|
|
|
if(v != null)
|
|
|
|
{
|
|
|
|
if(v.l == -1)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2006-11-27 10:39:30 +03:00
|
|
|
Emit(OpCodes.Neg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Emit(OpCodes.Div);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Emit(OpCodes.Dup);
|
|
|
|
Emit(OpCodes.Ldc_I4_M1);
|
|
|
|
Emit(OpCodes.Conv_I8);
|
2008-06-03 16:10:07 +04:00
|
|
|
CodeEmitterLabel label = DefineLabel();
|
2006-11-27 10:39:30 +03:00
|
|
|
Emit(OpCodes.Bne_Un_S, label);
|
|
|
|
Emit(OpCodes.Pop);
|
|
|
|
Emit(OpCodes.Neg);
|
2008-06-03 16:10:07 +04:00
|
|
|
CodeEmitterLabel label2 = DefineLabel();
|
2006-11-27 10:39:30 +03:00
|
|
|
Emit(OpCodes.Br_S, label2);
|
|
|
|
MarkLabel(label);
|
|
|
|
Emit(OpCodes.Div);
|
|
|
|
MarkLabel(label2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_instanceof(Type type)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new InstanceOfExpr(type));
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal void LazyEmit_ifeq(CodeEmitterLabel label)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
LazyEmit_if_ne_eq(label, false);
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal void LazyEmit_ifne(CodeEmitterLabel label)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
LazyEmit_if_ne_eq(label, true);
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
private void LazyEmit_if_ne_eq(CodeEmitterLabel label, bool brtrue)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
InstanceOfExpr instanceof = PeekStack() as InstanceOfExpr;
|
2008-02-15 18:32:51 +03:00
|
|
|
if (instanceof != null)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2006-11-27 10:39:30 +03:00
|
|
|
Emit(OpCodes.Isinst, instanceof.Type);
|
|
|
|
}
|
2008-02-15 18:32:51 +03:00
|
|
|
else
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
CmpExpr cmp = PeekStack() as CmpExpr;
|
2008-02-15 18:32:51 +03:00
|
|
|
if (cmp != null)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2008-02-15 18:32:51 +03:00
|
|
|
Emit(brtrue ? OpCodes.Bne_Un : OpCodes.Beq, label);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Emit(brtrue ? OpCodes.Brtrue : OpCodes.Brfalse, label);
|
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
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
private void EmitBcc(Comparison comp, CodeEmitterLabel label)
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal void LazyEmit_if_le_lt_ge_gt(Comparison comp, CodeEmitterLabel label)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
CmpExpr cmp = PeekStack() as CmpExpr;
|
2008-02-15 18:32:51 +03:00
|
|
|
if (cmp != null)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2008-02-15 18:32:51 +03:00
|
|
|
cmp.EmitBcc(this, comp, label);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Emit(OpCodes.Ldc_I4_0);
|
|
|
|
EmitBcc(comp, label);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_lcmp()
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new LCmpExpr());
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_fcmpl()
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new FCmplExpr());
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_fcmpg()
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new FCmpgExpr());
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_dcmpl()
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new DCmplExpr());
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_dcmpg()
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PushStack(new DCmpgExpr());
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmitAnd_I4(int v2)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
ConstIntExpr v1 = PeekStack() as ConstIntExpr;
|
2008-02-15 18:32:51 +03:00
|
|
|
if (v1 != null)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2008-02-15 18:32:51 +03:00
|
|
|
LazyEmitLdc_I4(v1.i & v2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LazyEmitLdc_I4(v2);
|
|
|
|
Emit(OpCodes.And);
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
internal void LazyEmit_baload()
|
|
|
|
{
|
|
|
|
PushStack(new ByteArrayLoadExpr());
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool Match<T1, T2>(out T1 t1, out T2 t2)
|
|
|
|
where T1 : Expr
|
|
|
|
where T2 : Expr
|
|
|
|
{
|
|
|
|
if (topOfStack < 2)
|
|
|
|
{
|
|
|
|
t1 = null;
|
|
|
|
t2 = null;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
t1 = stackArray[topOfStack - 1] as T1;
|
|
|
|
t2 = stackArray[topOfStack - 2] as T2;
|
|
|
|
return t1 != null && t2 != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_iand()
|
|
|
|
{
|
|
|
|
ConstIntExpr v1;
|
|
|
|
ByteArrayLoadExpr v2;
|
|
|
|
if (Match(out v1, out v2) && v1.i == 0xFF)
|
|
|
|
{
|
|
|
|
PopStack();
|
|
|
|
PopStack();
|
|
|
|
Emit(OpCodes.Ldelem_U1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Emit(OpCodes.And);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_land()
|
|
|
|
{
|
|
|
|
ConstLongExpr v1;
|
|
|
|
ConvertLong v2;
|
|
|
|
if (Match(out v1, out v2) && v1.l == 0xFF && v2.Expr is ByteArrayLoadExpr)
|
|
|
|
{
|
|
|
|
PopStack();
|
|
|
|
PopStack();
|
|
|
|
Emit(OpCodes.Ldelem_U1);
|
|
|
|
Emit(OpCodes.Conv_I8);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Emit(OpCodes.And);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void LazyEmit_i2l()
|
|
|
|
{
|
|
|
|
PushStack(new ConvertLong(PopStack()));
|
|
|
|
}
|
|
|
|
|
2007-06-12 13:47:40 +04:00
|
|
|
internal string PopLazyLdstr()
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
ConstStringExpr str = PeekStack() as ConstStringExpr;
|
2007-06-12 13:47:40 +04:00
|
|
|
if(str != null)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
PopStack();
|
2007-06-12 13:47:40 +04:00
|
|
|
return str.str;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2009-03-02 09:31:55 +03:00
|
|
|
internal TypeWrapper PeekLazyClassLiteral()
|
|
|
|
{
|
|
|
|
ClassLiteralExpr lit = PeekStack() as ClassLiteralExpr;
|
|
|
|
if (lit != null)
|
|
|
|
{
|
|
|
|
return lit.Type;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2005-12-19 18:12:49 +03:00
|
|
|
private void LazyGen()
|
2004-11-04 15:50:28 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
int len = topOfStack;
|
|
|
|
topOfStack = 0;
|
|
|
|
for(int i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
stackArray[i].Emit(this);
|
|
|
|
}
|
2004-11-04 15:50:28 +03:00
|
|
|
}
|
2005-12-19 18:12:49 +03: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
|
|
|
}
|
2006-11-27 10:39:30 +03:00
|
|
|
|
|
|
|
abstract class Expr
|
|
|
|
{
|
2009-07-14 11:25:46 +04:00
|
|
|
internal virtual bool HasSideEffect { get { return false; } }
|
2006-11-27 10:39:30 +03:00
|
|
|
|
2009-03-02 07:52:05 +03:00
|
|
|
internal virtual bool IsIncomplete { get { return false; } }
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal abstract void Emit(CodeEmitter ilgen);
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
abstract class UnaryExpr : Expr
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
internal readonly Expr Expr;
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
protected UnaryExpr(Expr expr)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
this.Expr = expr;
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
internal sealed override bool IsIncomplete
|
2009-03-02 07:52:05 +03:00
|
|
|
{
|
|
|
|
get { return Expr == null; }
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
internal override bool HasSideEffect
|
|
|
|
{
|
|
|
|
get { return Expr != null && Expr.HasSideEffect; }
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
if (Expr != null)
|
|
|
|
{
|
|
|
|
Expr.Emit(ilgen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
abstract class ExprWithExprAndType : UnaryExpr
|
|
|
|
{
|
|
|
|
internal readonly Type Type;
|
|
|
|
|
|
|
|
protected ExprWithExprAndType(Expr expr, Type type)
|
|
|
|
: base(expr)
|
|
|
|
{
|
|
|
|
this.Type = type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed class BoxExpr : ExprWithExprAndType
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
internal BoxExpr(Expr expr, Type type)
|
|
|
|
: base(expr, type)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
base.Emit(ilgen);
|
|
|
|
ilgen.Emit(OpCodes.Box, Type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
sealed class UnboxExpr : ExprWithExprAndType
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
internal UnboxExpr(Expr expr, Type type)
|
|
|
|
: base(expr, type)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
base.Emit(ilgen);
|
|
|
|
ilgen.Emit(OpCodes.Unbox, Type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
sealed class BoxUnboxExpr : ExprWithExprAndType
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
internal BoxUnboxExpr(Expr expr, Type type)
|
|
|
|
: base(expr, type)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
base.Emit(ilgen);
|
|
|
|
// unbox leaves a pointer to the value of the stack (instead of the value)
|
|
|
|
// so we have to copy the value into a local variable and load the address
|
|
|
|
// of the local onto the stack
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal local = ilgen.DeclareLocal(Type);
|
2006-11-27 10:39:30 +03:00
|
|
|
ilgen.Emit(OpCodes.Stloc, local);
|
|
|
|
ilgen.Emit(OpCodes.Ldloca, local);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
sealed class LdobjExpr : ExprWithExprAndType
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
internal LdobjExpr(Expr expr, Type type)
|
|
|
|
: base(expr, type)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
base.Emit(ilgen);
|
|
|
|
ilgen.Emit(OpCodes.Ldobj, Type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
sealed class NullExpr : Expr
|
2009-02-27 09:17:06 +03:00
|
|
|
{
|
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldnull);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
sealed class ConstIntExpr : Expr
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
internal readonly int i;
|
|
|
|
|
|
|
|
internal ConstIntExpr(int i)
|
|
|
|
{
|
|
|
|
this.i = i;
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
switch(i)
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_M1);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_0);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_1);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_2);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_3);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_4);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_5);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_6);
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_7);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_8);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if(i >= -128 && i <= 127)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_S, (sbyte)i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4, i);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-15 18:32:51 +03:00
|
|
|
sealed class ConstLongExpr : Expr
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
internal readonly long l;
|
|
|
|
|
|
|
|
internal ConstLongExpr(long l)
|
|
|
|
{
|
|
|
|
this.l = l;
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2008-02-15 18:32:51 +03:00
|
|
|
switch (l)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_M1);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_0);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_1);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_2);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_3);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_4);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_5);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_6);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_7);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_8);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
break;
|
|
|
|
default:
|
2008-02-15 18:32:51 +03:00
|
|
|
if (l >= -2147483648L && l <= 4294967295L)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2008-02-15 18:32:51 +03:00
|
|
|
if (l >= -128 && l <= 127)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_S, (sbyte)l);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4, (int)l);
|
|
|
|
}
|
2008-02-15 18:32:51 +03:00
|
|
|
if (l < 0)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Conv_U8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I8, l);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-15 18:32:51 +03:00
|
|
|
sealed class ConstStringExpr : Expr
|
2007-06-12 13:47:40 +04:00
|
|
|
{
|
|
|
|
internal readonly string str;
|
|
|
|
|
|
|
|
internal ConstStringExpr(string str)
|
|
|
|
{
|
|
|
|
this.str = str;
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2007-06-12 13:47:40 +04:00
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldstr, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-15 18:32:51 +03:00
|
|
|
sealed class InstanceOfExpr : Expr
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
internal readonly Type Type;
|
|
|
|
|
2006-11-27 10:39:30 +03:00
|
|
|
internal InstanceOfExpr(Type type)
|
|
|
|
{
|
2009-02-27 09:17:06 +03:00
|
|
|
this.Type = type;
|
2006-11-27 10:39:30 +03:00
|
|
|
}
|
|
|
|
|
2009-03-02 07:52:05 +03:00
|
|
|
internal override bool IsIncomplete
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
2006-11-27 10:39:30 +03:00
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Isinst, this.Type);
|
|
|
|
ilgen.Emit(OpCodes.Ldnull);
|
|
|
|
ilgen.Emit(OpCodes.Cgt_Un);
|
|
|
|
}
|
|
|
|
}
|
2008-02-15 18:32:51 +03:00
|
|
|
|
|
|
|
abstract class CmpExpr : Expr
|
|
|
|
{
|
|
|
|
internal CmpExpr()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-03-02 07:52:05 +03:00
|
|
|
internal override bool IsIncomplete
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal abstract void EmitBcc(CodeEmitter ilgen, Comparison comp, CodeEmitterLabel label);
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
sealed class LCmpExpr : CmpExpr
|
|
|
|
{
|
|
|
|
internal LCmpExpr()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal sealed override void Emit(CodeEmitter ilgen)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal value1 = ilgen.AllocTempLocal(Types.Int64);
|
|
|
|
CodeEmitterLocal value2 = ilgen.AllocTempLocal(Types.Int64);
|
2008-02-15 18:32:51 +03:00
|
|
|
ilgen.Emit(OpCodes.Stloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Stloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Cgt);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Clt);
|
|
|
|
ilgen.Emit(OpCodes.Sub);
|
|
|
|
ilgen.ReleaseTempLocal(value2);
|
|
|
|
ilgen.ReleaseTempLocal(value1);
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal sealed override void EmitBcc(CodeEmitter ilgen, Comparison comp, CodeEmitterLabel label)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
ilgen.EmitBcc(comp, label);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class FCmplExpr : CmpExpr
|
|
|
|
{
|
|
|
|
protected virtual Type FloatOrDouble()
|
|
|
|
{
|
2009-10-14 18:58:41 +04:00
|
|
|
return Types.Single;
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal sealed override void Emit(CodeEmitter ilgen)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal value1 = ilgen.AllocTempLocal(FloatOrDouble());
|
|
|
|
CodeEmitterLocal value2 = ilgen.AllocTempLocal(FloatOrDouble());
|
2008-02-15 18:32:51 +03:00
|
|
|
ilgen.Emit(OpCodes.Stloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Stloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Cgt);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Clt_Un);
|
|
|
|
ilgen.Emit(OpCodes.Sub);
|
|
|
|
ilgen.ReleaseTempLocal(value1);
|
|
|
|
ilgen.ReleaseTempLocal(value2);
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal sealed override void EmitBcc(CodeEmitter ilgen, Comparison comp, CodeEmitterLabel label)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
switch (comp)
|
|
|
|
{
|
|
|
|
case Comparison.LessOrEqual:
|
|
|
|
ilgen.Emit(OpCodes.Ble_Un, label);
|
|
|
|
break;
|
|
|
|
case Comparison.LessThan:
|
|
|
|
ilgen.Emit(OpCodes.Blt_Un, label);
|
|
|
|
break;
|
|
|
|
case Comparison.GreaterOrEqual:
|
|
|
|
ilgen.Emit(OpCodes.Bge, label);
|
|
|
|
break;
|
|
|
|
case Comparison.GreaterThan:
|
|
|
|
ilgen.Emit(OpCodes.Bgt, label);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class FCmpgExpr : CmpExpr
|
|
|
|
{
|
|
|
|
protected virtual Type FloatOrDouble()
|
|
|
|
{
|
2009-10-14 18:58:41 +04:00
|
|
|
return Types.Single;
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal sealed override void Emit(CodeEmitter ilgen)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
2010-09-29 11:21:51 +04:00
|
|
|
CodeEmitterLocal value1 = ilgen.AllocTempLocal(FloatOrDouble());
|
|
|
|
CodeEmitterLocal value2 = ilgen.AllocTempLocal(FloatOrDouble());
|
2008-02-15 18:32:51 +03:00
|
|
|
ilgen.Emit(OpCodes.Stloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Stloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Cgt_Un);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value1);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, value2);
|
|
|
|
ilgen.Emit(OpCodes.Clt);
|
|
|
|
ilgen.Emit(OpCodes.Sub);
|
|
|
|
ilgen.ReleaseTempLocal(value1);
|
|
|
|
ilgen.ReleaseTempLocal(value2);
|
|
|
|
}
|
|
|
|
|
2008-06-03 16:10:07 +04:00
|
|
|
internal sealed override void EmitBcc(CodeEmitter ilgen, Comparison comp, CodeEmitterLabel label)
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
switch (comp)
|
|
|
|
{
|
|
|
|
case Comparison.LessOrEqual:
|
|
|
|
ilgen.Emit(OpCodes.Ble, label);
|
|
|
|
break;
|
|
|
|
case Comparison.LessThan:
|
|
|
|
ilgen.Emit(OpCodes.Blt, label);
|
|
|
|
break;
|
|
|
|
case Comparison.GreaterOrEqual:
|
|
|
|
ilgen.Emit(OpCodes.Bge_Un, label);
|
|
|
|
break;
|
|
|
|
case Comparison.GreaterThan:
|
|
|
|
ilgen.Emit(OpCodes.Bgt_Un, label);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
sealed class DCmplExpr : FCmplExpr
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
protected override Type FloatOrDouble()
|
|
|
|
{
|
2009-10-14 18:58:41 +04:00
|
|
|
return Types.Double;
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
sealed class DCmpgExpr : FCmpgExpr
|
2008-02-15 18:32:51 +03:00
|
|
|
{
|
|
|
|
protected override Type FloatOrDouble()
|
|
|
|
{
|
2009-10-14 18:58:41 +04:00
|
|
|
return Types.Double;
|
2008-02-15 18:32:51 +03:00
|
|
|
}
|
|
|
|
}
|
2009-02-27 09:17:06 +03:00
|
|
|
|
2009-07-14 11:25:46 +04:00
|
|
|
sealed class ClassLiteralExpr : Expr
|
2009-02-27 09:17:06 +03:00
|
|
|
{
|
2009-03-02 09:31:55 +03:00
|
|
|
internal readonly TypeWrapper Type;
|
2009-02-27 09:17:06 +03:00
|
|
|
|
2009-03-02 09:31:55 +03:00
|
|
|
internal ClassLiteralExpr(TypeWrapper type)
|
2009-02-27 09:17:06 +03:00
|
|
|
{
|
2009-03-02 09:31:55 +03:00
|
|
|
this.Type = type;
|
2009-02-27 09:17:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
|
|
|
{
|
2009-07-13 12:34:37 +04:00
|
|
|
Type.EmitClassLiteral(ilgen);
|
2009-02-27 09:17:06 +03:00
|
|
|
}
|
|
|
|
}
|
2009-07-14 11:25:46 +04:00
|
|
|
|
|
|
|
sealed class ByteArrayLoadExpr : Expr
|
|
|
|
{
|
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldelem_I1);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override bool HasSideEffect
|
|
|
|
{
|
|
|
|
get { return true; }
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override bool IsIncomplete
|
|
|
|
{
|
|
|
|
get { return true; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed class ConvertLong : UnaryExpr
|
|
|
|
{
|
|
|
|
internal ConvertLong(Expr expr)
|
|
|
|
: base(expr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Emit(CodeEmitter ilgen)
|
|
|
|
{
|
|
|
|
base.Emit(ilgen);
|
|
|
|
ilgen.Emit(OpCodes.Conv_I8);
|
|
|
|
}
|
|
|
|
}
|
2004-11-04 15:50:28 +03:00
|
|
|
}
|
2003-05-30 16:08:59 +04:00
|
|
|
}
|