ikvm-fork/runtime/CodeEmitter.cs

1255 строки
25 KiB
C#
Исходник Обычный вид История

2003-05-30 16:08:59 +04:00
/*
Copyright (C) 2002, 2004, 2005, 2006, 2008 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
*/
2005-12-07 12:06:32 +03:00
#if !COMPACT_FRAMEWORK
2003-05-30 16:08:59 +04:00
using System;
2004-10-19 17:43:55 +04:00
using System.Collections;
2003-05-30 16:08:59 +04:00
using System.Reflection;
using System.Reflection.Emit;
2004-10-19 17:43:55 +04:00
using System.Runtime.InteropServices;
using System.Diagnostics.SymbolStore;
2005-06-01 13:49:30 +04:00
namespace IKVM.Internal
2004-10-19 17:43:55 +04:00
{
class CodeEmitterLabel
2005-12-29 18:48:32 +03:00
{
private Label label;
private int offset = -1;
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;
}
set
{
offset = value;
}
}
}
class CodeEmitter
2005-06-01 13:49:30 +04:00
{
private ILGenerator ilgen_real;
2005-06-01 13:49:30 +04:00
private int offset;
private ArrayList locals = new ArrayList();
private Stack exceptionStack = new Stack();
private bool inFinally;
2006-05-04 12:09:56 +04:00
#if STATIC_COMPILER
2005-06-19 14:44:53 +04:00
private IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter linenums;
2006-05-04 12:09:56 +04:00
#endif // STATIC_COMPILER
2006-11-27 10:39:30 +03:00
private Expr stack;
private CodeEmitterLabel lazyBranch;
private LocalBuilder[] tempLocals = new LocalBuilder[32];
2004-11-04 15:50:28 +03:00
#if LABELCHECK
2005-12-19 18:12:49 +03:00
private Hashtable labels = new Hashtable();
2004-11-04 15:50:28 +03:00
#endif
2004-10-19 17:43:55 +04:00
internal static CodeEmitter Create(MethodBuilder mb)
2005-06-01 13:49:30 +04:00
{
return new CodeEmitter(mb.GetILGenerator());
2005-06-01 13:49:30 +04:00
}
2004-10-19 17:43:55 +04:00
internal static CodeEmitter Create(ConstructorBuilder cb)
{
return new CodeEmitter(cb.GetILGenerator());
}
internal static CodeEmitter Create(DynamicMethod dm)
{
return new CodeEmitter(dm.GetILGenerator());
}
private CodeEmitter(ILGenerator ilgen)
2005-06-01 13:49:30 +04:00
{
this.ilgen_real = ilgen;
}
internal LocalBuilder UnsafeAllocTempLocal(Type type)
{
int free = -1;
for (int i = 0; i < tempLocals.Length; i++)
{
LocalBuilder lb = tempLocals[i];
if (lb == null)
{
if (free == -1)
{
free = i;
}
}
else if (lb.LocalType == type)
{
return lb;
}
}
LocalBuilder lb1 = DeclareLocal(type);
if (free != -1)
{
tempLocals[free] = lb1;
}
return lb1;
}
internal LocalBuilder AllocTempLocal(Type type)
{
for (int i = 0; i < tempLocals.Length; i++)
{
LocalBuilder lb = tempLocals[i];
if (lb != null && lb.LocalType == type)
{
tempLocals[i] = null;
return lb;
}
}
return DeclareLocal(type);
}
internal void ReleaseTempLocal(LocalBuilder lb)
{
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
internal bool IsStackEmpty
{
get
{
return stack == null;
}
}
2005-06-01 13:49:30 +04:00
internal int GetILOffset()
{
2005-12-19 18:12:49 +03:00
LazyGen();
2005-06-01 13:49:30 +04:00
return offset;
}
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();
2005-06-01 13:49:30 +04:00
offset += 5;
ilgen_real.BeginCatchBlock(exceptionType);
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 BeginExceptFilterBlock()
{
2005-12-19 18:12:49 +03:00
LazyGen();
2005-06-01 13:49:30 +04:00
offset += 5;
ilgen_real.BeginExceptFilterBlock();
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 Label BeginExceptionBlock()
{
2005-12-19 18:12:49 +03:00
LazyGen();
2005-06-01 13:49:30 +04:00
exceptionStack.Push(inFinally);
inFinally = false;
return ilgen_real.BeginExceptionBlock();
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();
2005-07-20 11:26:10 +04:00
inFinally = true;
2005-06-01 13:49:30 +04:00
offset += 5;
ilgen_real.BeginFaultBlock();
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();
2005-06-01 13:49:30 +04:00
inFinally = true;
offset += 5;
ilgen_real.BeginFinallyBlock();
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();
ilgen_real.BeginScope();
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 LocalBuilder DeclareLocal(Type localType)
{
LocalBuilder loc = ilgen_real.DeclareLocal(localType);
2005-06-01 13:49:30 +04:00
locals.Add(loc);
return loc;
}
2004-10-19 17:43:55 +04:00
internal CodeEmitterLabel DefineLabel()
2005-06-01 13:49:30 +04:00
{
Label label = 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
return new CodeEmitterLabel(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size;
ilgen_real.Emit(opcode);
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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 1;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 4;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 8;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 4;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 2;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 4;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 8;
ilgen_real.Emit(opcode, arg);
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
internal void Emit(OpCode opcode, CodeEmitterLabel label)
2004-10-19 17:43:55 +04:00
{
2005-12-19 18:12:49 +03:00
LazyGen();
2006-01-02 13:59:51 +03:00
if(label.Offset == -1)
{
if(opcode.Value == OpCodes.Br.Value)
{
lazyBranch = label;
return;
}
}
else if(offset - label.Offset < 126)
2005-12-29 18:48:32 +03:00
{
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;
}
}
2005-06-01 13:49:30 +04:00
offset += opcode.Size;
ilgen_real.Emit(opcode, label.Label);
2005-06-01 13:49:30 +04:00
switch(opcode.OperandType)
{
case OperandType.InlineBrTarget:
offset += 4;
break;
case OperandType.ShortInlineBrTarget:
offset += 1;
break;
default:
throw new NotImplementedException();
}
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +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();
2005-06-01 13:49:30 +04:00
offset += 5 + labels.Length * 4;
2005-12-29 18:48:32 +03:00
Label[] real = new Label[labels.Length];
for(int i = 0; i < labels.Length; i++)
{
real[i] = labels[i].Label;
}
ilgen_real.Emit(opcode, real);
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
internal void Emit(OpCode opcode, LocalBuilder local)
{
2005-12-19 18:12:49 +03:00
LazyGen();
ilgen_real.Emit(opcode, local);
2005-06-01 13:49:30 +04:00
int index = locals.IndexOf(local);
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;
}
}
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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 4;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 1;
ilgen_real.Emit(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, SignatureHelper signature)
{
2005-12-19 18:12:49 +03:00
LazyGen();
2005-06-01 13:49:30 +04:00
offset += opcode.Size;
ilgen_real.Emit(opcode, signature);
2005-06-01 13:49:30 +04:00
throw new NotImplementedException();
}
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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 4;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 4;
ilgen_real.Emit(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();
2005-06-01 13:49:30 +04:00
offset += opcode.Size + 4;
ilgen_real.Emit(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 EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
{
2005-12-19 18:12:49 +03:00
LazyGen();
2005-06-01 13:49:30 +04:00
offset += opcode.Size;
ilgen_real.EmitCall(opcode, methodInfo, optionalParameterTypes);
2005-06-01 13:49:30 +04:00
throw new NotImplementedException();
}
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();
2005-06-01 13:49:30 +04:00
offset += 5;
ilgen_real.EmitCalli(opcode, 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 EmitCalli(OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
{
2005-12-19 18:12:49 +03:00
LazyGen();
2005-06-01 13:49:30 +04:00
offset += 5;
ilgen_real.EmitCalli(opcode, callingConvention, returnType, parameterTypes, optionalParameterTypes);
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(FieldInfo fld)
{
2005-12-19 18:12:49 +03:00
LazyGen();
ilgen_real.EmitWriteLine(fld);
2005-06-01 13:49:30 +04:00
throw new NotImplementedException();
}
2004-10-19 17:43:55 +04:00
2005-06-01 13:49:30 +04:00
internal void EmitWriteLine(LocalBuilder localBuilder)
{
2005-12-19 18:12:49 +03:00
LazyGen();
ilgen_real.EmitWriteLine(localBuilder);
2005-06-01 13:49:30 +04:00
throw new NotImplementedException();
}
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();
2005-06-01 13:49:30 +04:00
offset += 10;
ilgen_real.EmitWriteLine(value);
2004-10-19 17:43:55 +04:00
}
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();
2005-06-01 13:49:30 +04:00
if(inFinally)
{
offset += 1;
}
else
{
offset += 5;
}
inFinally = (bool)exceptionStack.Pop();
ilgen_real.EndExceptionBlock();
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();
ilgen_real.EndScope();
2005-06-01 13:49:30 +04:00
}
2004-10-19 17:43:55 +04:00
internal void MarkLabel(CodeEmitterLabel loc)
2005-06-01 13:49:30 +04:00
{
2006-01-02 13:59:51 +03:00
if(lazyBranch == loc)
{
lazyBranch = null;
}
2005-12-19 18:12:49 +03:00
LazyGen();
2004-11-04 15:50:28 +03:00
#if LABELCHECK
2005-12-29 18:48:32 +03:00
labels.Remove(loc.Label);
2004-11-04 15:50:28 +03:00
#endif
ilgen_real.MarkLabel(loc.Label);
2005-12-29 18:48:32 +03:00
loc.Offset = offset;
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 MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
{
2005-12-19 18:12:49 +03:00
LazyGen();
ilgen_real.MarkSequencePoint(document, startLine, startColumn, endLine, endColumn);
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();
2005-06-01 13:49:30 +04:00
offset += 6;
ilgen_real.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 UsingNamespace(string usingNamespace)
{
2005-12-19 18:12:49 +03:00
LazyGen();
ilgen_real.UsingNamespace(usingNamespace);
2005-06-01 13:49:30 +04:00
}
2004-10-19 17:43:55 +04:00
2006-05-04 12:09:56 +04:00
#if STATIC_COMPILER
2005-06-01 13:49:30 +04:00
internal void SetLineNumber(ushort line)
2004-10-19 17:43:55 +04:00
{
2005-12-19 18:12:49 +03:00
LazyGen();
2005-06-01 13:49:30 +04:00
if(linenums == null)
{
2005-06-19 14:44:53 +04:00
linenums = new IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter(32);
2005-06-01 13:49:30 +04:00
}
2005-06-19 14:44:53 +04:00
linenums.AddMapping(offset, line);
2004-10-19 17:43:55 +04:00
}
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
2005-12-19 18:12:49 +03:00
internal void LazyEmitBox(Type type)
2005-06-01 13:49:30 +04:00
{
2006-11-27 10:39:30 +03:00
stack = new BoxExpr(stack, 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
{
2006-11-27 10:39:30 +03:00
BoxExpr box = stack as BoxExpr;
if(box != null)
{
stack = new BoxUnboxExpr(box.Expr, type);
}
else
{
stack = new UnboxExpr(stack, type);
}
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
{
2006-11-27 10:39:30 +03:00
BoxUnboxExpr boxunbox = stack as BoxUnboxExpr;
if(boxunbox != null)
2005-12-20 15:44:29 +03:00
{
2006-11-27 10:39:30 +03:00
// box/unbox+ldobj annihilate each other
stack = boxunbox.Expr;
2005-12-20 15:44:29 +03:00
}
else
{
2006-11-27 10:39:30 +03:00
stack = new LdobjExpr(stack, type);
2005-12-20 15:44:29 +03:00
}
}
2005-12-19 18:12:49 +03:00
internal void LazyEmitUnboxSpecial(Type type)
{
2006-11-27 10:39:30 +03:00
BoxExpr box = stack as BoxExpr;
if(box != null)
2005-12-19 18:12:49 +03:00
{
// the unbox and lazy box cancel each other out
2006-11-27 10:39:30 +03:00
stack = 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);
CodeEmitterLabel label1 = DefineLabel();
2005-12-19 18:12:49 +03:00
Emit(OpCodes.Brtrue_S, label1);
Emit(OpCodes.Pop);
Emit(OpCodes.Ldloc, DeclareLocal(type));
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);
}
}
2006-11-27 10:39:30 +03:00
internal void LazyEmitLdc_I4(int i)
{
LazyGen();
stack = new ConstIntExpr(i);
}
internal void LazyEmitLdc_I8(long l)
{
LazyGen();
stack = new ConstLongExpr(l);
}
internal void LazyEmitLdstr(string str)
{
LazyGen();
stack = new ConstStringExpr(str);
}
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
ConstIntExpr v = stack as ConstIntExpr;
if(v != null)
{
if(v.i == -1)
{
stack = null;
Emit(OpCodes.Neg);
}
else
{
Emit(OpCodes.Div);
}
}
else
{
Emit(OpCodes.Dup);
Emit(OpCodes.Ldc_I4_M1);
CodeEmitterLabel label = DefineLabel();
2006-11-27 10:39:30 +03:00
Emit(OpCodes.Bne_Un_S, label);
Emit(OpCodes.Pop);
Emit(OpCodes.Neg);
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
ConstLongExpr v = stack as ConstLongExpr;
if(v != null)
{
if(v.l == -1)
{
stack = null;
Emit(OpCodes.Neg);
}
else
{
Emit(OpCodes.Div);
}
}
else
{
Emit(OpCodes.Dup);
Emit(OpCodes.Ldc_I4_M1);
Emit(OpCodes.Conv_I8);
CodeEmitterLabel label = DefineLabel();
2006-11-27 10:39:30 +03:00
Emit(OpCodes.Bne_Un_S, label);
Emit(OpCodes.Pop);
Emit(OpCodes.Neg);
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)
{
LazyGen();
stack = new InstanceOfExpr(type);
}
internal void LazyEmit_ifeq(CodeEmitterLabel label)
{
LazyEmit_if_ne_eq(label, false);
}
internal void LazyEmit_ifne(CodeEmitterLabel label)
{
LazyEmit_if_ne_eq(label, true);
}
private void LazyEmit_if_ne_eq(CodeEmitterLabel label, bool brtrue)
2006-11-27 10:39:30 +03:00
{
InstanceOfExpr instanceof = stack as InstanceOfExpr;
if (instanceof != null)
2006-11-27 10:39:30 +03:00
{
stack = null;
Emit(OpCodes.Isinst, instanceof.Type);
}
else
{
CmpExpr cmp = stack as CmpExpr;
if (cmp != null)
{
stack = null;
Emit(brtrue ? OpCodes.Bne_Un : OpCodes.Beq, label);
return;
}
}
Emit(brtrue ? OpCodes.Brtrue : OpCodes.Brfalse, label);
2006-11-27 10:39:30 +03:00
}
internal enum Comparison
2006-11-27 10:39:30 +03:00
{
LessOrEqual,
LessThan,
GreaterOrEqual,
GreaterThan
}
private void EmitBcc(Comparison comp, CodeEmitterLabel label)
{
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;
}
}
internal void LazyEmit_if_le_lt_ge_gt(Comparison comp, CodeEmitterLabel label)
{
CmpExpr cmp = stack as CmpExpr;
if (cmp != null)
2006-11-27 10:39:30 +03:00
{
stack = null;
cmp.EmitBcc(this, comp, label);
}
else
{
Emit(OpCodes.Ldc_I4_0);
EmitBcc(comp, label);
}
}
internal void LazyEmit_lcmp()
{
LazyGen();
stack = new LCmpExpr();
}
internal void LazyEmit_fcmpl()
{
LazyGen();
stack = new FCmplExpr();
}
internal void LazyEmit_fcmpg()
{
LazyGen();
stack = new FCmpgExpr();
}
internal void LazyEmit_dcmpl()
{
LazyGen();
stack = new DCmplExpr();
}
internal void LazyEmit_dcmpg()
{
LazyGen();
stack = new DCmpgExpr();
}
internal void LazyEmitAnd_I4(int v2)
{
ConstIntExpr v1 = stack as ConstIntExpr;
if (v1 != null)
{
stack = null;
LazyEmitLdc_I4(v1.i & v2);
}
else
{
LazyEmitLdc_I4(v2);
Emit(OpCodes.And);
2006-11-27 10:39:30 +03:00
}
}
internal string PopLazyLdstr()
{
ConstStringExpr str = stack as ConstStringExpr;
if(str != null)
{
stack = null;
return str.str;
}
return null;
}
2005-12-19 18:12:49 +03:00
private void LazyGen()
2004-11-04 15:50:28 +03:00
{
2006-11-27 10:39:30 +03:00
if(stack != null)
2005-12-19 18:12:49 +03:00
{
2006-11-27 10:39:30 +03:00
Expr exp = stack;
stack = null;
exp.Emit(this);
2005-12-19 18:12:49 +03:00
}
2006-01-02 13:59:51 +03:00
if(lazyBranch != null)
{
offset += OpCodes.Br.Size + 4;
ilgen_real.Emit(OpCodes.Br, lazyBranch.Label);
2006-01-02 13:59:51 +03:00
lazyBranch = null;
}
2004-11-04 15:50:28 +03:00
}
2005-12-19 18:12:49 +03:00
internal void Finish()
{
#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
{
internal readonly Type Type;
protected Expr(Type type)
{
this.Type = type;
}
internal abstract void Emit(CodeEmitter ilgen);
2006-11-27 10:39:30 +03:00
}
abstract class UnaryExpr : Expr
{
internal readonly Expr Expr;
protected UnaryExpr(Expr expr, Type type)
: base(type)
{
this.Expr = expr;
}
internal override void Emit(CodeEmitter ilgen)
2006-11-27 10:39:30 +03:00
{
if (Expr != null)
{
Expr.Emit(ilgen);
}
}
}
class BoxExpr : UnaryExpr
{
internal BoxExpr(Expr expr, Type type)
: base(expr, type)
{
}
internal override void Emit(CodeEmitter ilgen)
2006-11-27 10:39:30 +03:00
{
base.Emit(ilgen);
ilgen.Emit(OpCodes.Box, Type);
}
}
class UnboxExpr : UnaryExpr
{
internal UnboxExpr(Expr expr, Type type)
: base(expr, type)
{
}
internal override void Emit(CodeEmitter ilgen)
2006-11-27 10:39:30 +03:00
{
base.Emit(ilgen);
ilgen.Emit(OpCodes.Unbox, Type);
}
}
class BoxUnboxExpr : UnaryExpr
{
internal BoxUnboxExpr(Expr expr, Type type)
: base(expr, type)
{
}
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
LocalBuilder local = ilgen.DeclareLocal(Type);
ilgen.Emit(OpCodes.Stloc, local);
ilgen.Emit(OpCodes.Ldloca, local);
}
}
class LdobjExpr : UnaryExpr
{
internal LdobjExpr(Expr expr, Type type)
: base(expr, type)
{
}
internal override void Emit(CodeEmitter ilgen)
2006-11-27 10:39:30 +03:00
{
base.Emit(ilgen);
ilgen.Emit(OpCodes.Ldobj, Type);
}
}
class ConstIntExpr : Expr
{
internal readonly int i;
internal ConstIntExpr(int i)
: base(typeof(int))
{
this.i = i;
}
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;
}
}
}
sealed class ConstLongExpr : Expr
2006-11-27 10:39:30 +03:00
{
internal readonly long l;
internal ConstLongExpr(long l)
: base(typeof(long))
{
this.l = l;
}
internal override void Emit(CodeEmitter ilgen)
2006-11-27 10:39:30 +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:
if (l >= -2147483648L && l <= 4294967295L)
2006-11-27 10:39:30 +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);
}
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;
}
}
}
sealed class ConstStringExpr : Expr
{
internal readonly string str;
internal ConstStringExpr(string str)
: base(typeof(string))
{
this.str = str;
}
internal override void Emit(CodeEmitter ilgen)
{
ilgen.Emit(OpCodes.Ldstr, str);
}
}
sealed class InstanceOfExpr : Expr
2006-11-27 10:39:30 +03:00
{
internal InstanceOfExpr(Type type)
: base(type)
{
}
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);
}
}
abstract class CmpExpr : Expr
{
internal CmpExpr()
: base(typeof(int))
{
}
internal abstract void EmitBcc(CodeEmitter ilgen, Comparison comp, CodeEmitterLabel label);
}
sealed class LCmpExpr : CmpExpr
{
internal LCmpExpr()
{
}
internal sealed override void Emit(CodeEmitter ilgen)
{
LocalBuilder value1 = ilgen.AllocTempLocal(typeof(long));
LocalBuilder value2 = ilgen.AllocTempLocal(typeof(long));
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);
}
internal sealed override void EmitBcc(CodeEmitter ilgen, Comparison comp, CodeEmitterLabel label)
{
ilgen.EmitBcc(comp, label);
}
}
class FCmplExpr : CmpExpr
{
protected virtual Type FloatOrDouble()
{
return typeof(float);
}
internal sealed override void Emit(CodeEmitter ilgen)
{
LocalBuilder value1 = ilgen.AllocTempLocal(FloatOrDouble());
LocalBuilder value2 = ilgen.AllocTempLocal(FloatOrDouble());
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);
}
internal sealed override void EmitBcc(CodeEmitter ilgen, Comparison comp, CodeEmitterLabel label)
{
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()
{
return typeof(float);
}
internal sealed override void Emit(CodeEmitter ilgen)
{
LocalBuilder value1 = ilgen.AllocTempLocal(FloatOrDouble());
LocalBuilder value2 = ilgen.AllocTempLocal(FloatOrDouble());
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);
}
internal sealed override void EmitBcc(CodeEmitter ilgen, Comparison comp, CodeEmitterLabel label)
{
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;
}
}
}
class DCmplExpr : FCmplExpr
{
protected override Type FloatOrDouble()
{
return typeof(double);
}
}
class DCmpgExpr : FCmpgExpr
{
protected override Type FloatOrDouble()
{
return typeof(double);
}
}
2004-11-04 15:50:28 +03:00
}
2003-05-30 16:08:59 +04:00
}
2005-12-07 12:06:32 +03:00
#endif