2003-05-30 16:08:59 +04:00
|
|
|
/*
|
2004-10-04 23:30:53 +04:00
|
|
|
Copyright (C) 2002, 2004 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
|
|
|
{
|
2005-06-01 13:49:30 +04:00
|
|
|
class CountingILGenerator
|
|
|
|
{
|
|
|
|
private ILGenerator ilgen;
|
|
|
|
private int offset;
|
|
|
|
private ArrayList locals = new ArrayList();
|
|
|
|
private Stack exceptionStack = new Stack();
|
|
|
|
private bool inFinally;
|
2005-06-19 14:44:53 +04:00
|
|
|
private IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter linenums;
|
2004-11-04 15:50:28 +03:00
|
|
|
#if LABELCHECK
|
|
|
|
private Hashtable labels = new Hashtable();
|
|
|
|
#endif
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
public static implicit operator CountingILGenerator(ILGenerator ilgen)
|
|
|
|
{
|
|
|
|
return new CountingILGenerator(ilgen);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal CountingILGenerator(ILGenerator ilgen)
|
|
|
|
{
|
|
|
|
this.ilgen = ilgen;
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal int GetILOffset()
|
|
|
|
{
|
|
|
|
return offset;
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginCatchBlock(Type exceptionType)
|
|
|
|
{
|
|
|
|
offset += 5;
|
|
|
|
ilgen.BeginCatchBlock(exceptionType);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginExceptFilterBlock()
|
|
|
|
{
|
|
|
|
offset += 5;
|
|
|
|
ilgen.BeginExceptFilterBlock();
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal Label BeginExceptionBlock()
|
|
|
|
{
|
|
|
|
exceptionStack.Push(inFinally);
|
|
|
|
inFinally = false;
|
|
|
|
return ilgen.BeginExceptionBlock();
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginFaultBlock()
|
|
|
|
{
|
2005-07-20 11:26:10 +04:00
|
|
|
inFinally = true;
|
2005-06-01 13:49:30 +04:00
|
|
|
offset += 5;
|
|
|
|
ilgen.BeginFaultBlock();
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginFinallyBlock()
|
|
|
|
{
|
|
|
|
inFinally = true;
|
|
|
|
offset += 5;
|
|
|
|
ilgen.BeginFinallyBlock();
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void BeginScope()
|
|
|
|
{
|
|
|
|
ilgen.BeginScope();
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal LocalBuilder DeclareLocal(Type localType)
|
|
|
|
{
|
|
|
|
LocalBuilder loc = ilgen.DeclareLocal(localType);
|
|
|
|
locals.Add(loc);
|
|
|
|
return loc;
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal Label DefineLabel()
|
|
|
|
{
|
|
|
|
Label label = ilgen.DefineLabel();
|
2004-11-04 15:50:28 +03:00
|
|
|
#if LABELCHECK
|
|
|
|
labels.Add(label, new System.Diagnostics.StackFrame(1, true));
|
|
|
|
#endif
|
2005-06-01 13:49:30 +04:00
|
|
|
return label;
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode)
|
|
|
|
{
|
|
|
|
offset += opcode.Size;
|
|
|
|
ilgen.Emit(opcode);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, byte arg)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 1;
|
|
|
|
ilgen.Emit(opcode, arg);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, ConstructorInfo con)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
ilgen.Emit(opcode, con);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, double arg)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 8;
|
|
|
|
ilgen.Emit(opcode, arg);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, FieldInfo field)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
ilgen.Emit(opcode, field);
|
|
|
|
}
|
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-06-01 13:49:30 +04:00
|
|
|
offset += opcode.Size + 2;
|
|
|
|
ilgen.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)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
ilgen.Emit(opcode, arg);
|
|
|
|
}
|
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-06-01 13:49:30 +04:00
|
|
|
offset += opcode.Size + 8;
|
|
|
|
ilgen.Emit(opcode, arg);
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2005-06-01 13:49:30 +04:00
|
|
|
|
|
|
|
internal void Emit(OpCode opcode, Label label)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2005-06-01 13:49:30 +04:00
|
|
|
offset += opcode.Size;
|
|
|
|
ilgen.Emit(opcode, label);
|
|
|
|
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, Label[] labels)
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
2005-06-01 13:49:30 +04:00
|
|
|
offset += 5 + labels.Length * 4;
|
|
|
|
ilgen.Emit(opcode, labels);
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, LocalBuilder local)
|
|
|
|
{
|
|
|
|
ilgen.Emit(opcode, local);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
ilgen.Emit(opcode, meth);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, sbyte arg)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 1;
|
|
|
|
ilgen.Emit(opcode, arg);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, SignatureHelper signature)
|
|
|
|
{
|
|
|
|
offset += opcode.Size;
|
|
|
|
ilgen.Emit(opcode, signature);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
ilgen.Emit(opcode, arg);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, string arg)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
ilgen.Emit(opcode, arg);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Emit(OpCode opcode, Type cls)
|
|
|
|
{
|
|
|
|
offset += opcode.Size + 4;
|
|
|
|
ilgen.Emit(opcode, cls);
|
|
|
|
}
|
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)
|
|
|
|
{
|
|
|
|
offset += opcode.Size;
|
|
|
|
ilgen.EmitCall(opcode, methodInfo, optionalParameterTypes);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
offset += 5;
|
|
|
|
ilgen.EmitCalli(opcode, unmanagedCallConv, returnType, parameterTypes);
|
|
|
|
}
|
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)
|
|
|
|
{
|
|
|
|
offset += 5;
|
|
|
|
ilgen.EmitCalli(opcode, callingConvention, returnType, parameterTypes, optionalParameterTypes);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EmitWriteLine(FieldInfo fld)
|
|
|
|
{
|
|
|
|
ilgen.EmitWriteLine(fld);
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EmitWriteLine(LocalBuilder localBuilder)
|
|
|
|
{
|
|
|
|
ilgen.EmitWriteLine(localBuilder);
|
|
|
|
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-06-01 13:49:30 +04:00
|
|
|
offset += 10;
|
|
|
|
ilgen.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-06-01 13:49:30 +04:00
|
|
|
if(inFinally)
|
|
|
|
{
|
|
|
|
offset += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
offset += 5;
|
|
|
|
}
|
|
|
|
inFinally = (bool)exceptionStack.Pop();
|
|
|
|
ilgen.EndExceptionBlock();
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void EndScope()
|
|
|
|
{
|
|
|
|
ilgen.EndScope();
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void MarkLabel(Label loc)
|
|
|
|
{
|
2004-11-04 15:50:28 +03:00
|
|
|
#if LABELCHECK
|
|
|
|
labels.Remove(loc);
|
|
|
|
#endif
|
2005-06-01 13:49:30 +04:00
|
|
|
ilgen.MarkLabel(loc);
|
|
|
|
}
|
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)
|
|
|
|
{
|
|
|
|
ilgen.MarkSequencePoint(document, startLine, startColumn, endLine, endColumn);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void ThrowException(Type excType)
|
|
|
|
{
|
|
|
|
offset += 6;
|
|
|
|
ilgen.ThrowException(excType);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void UsingNamespace(string usingNamespace)
|
|
|
|
{
|
|
|
|
ilgen.UsingNamespace(usingNamespace);
|
|
|
|
}
|
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
|
|
|
{
|
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
|
|
|
{
|
2005-06-01 13:49:30 +04:00
|
|
|
if(!IKVM.Internal.JVM.NoStackTraceInfo && linenums != null)
|
|
|
|
{
|
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
|
|
|
}
|
2004-11-04 15:50:28 +03:00
|
|
|
|
2005-06-01 13:49:30 +04:00
|
|
|
internal void Finish()
|
|
|
|
{
|
2004-11-04 15:50:28 +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);
|
|
|
|
}
|
|
|
|
#endif
|
2005-06-01 13:49:30 +04:00
|
|
|
}
|
2004-11-04 15:50:28 +03:00
|
|
|
}
|
2003-05-30 16:08:59 +04:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
public abstract class CodeEmitter
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-10-19 17:43:55 +04:00
|
|
|
internal abstract void Emit(CountingILGenerator ilgen);
|
2003-05-30 16:08:59 +04:00
|
|
|
}
|
|
|
|
}
|
2005-12-07 12:06:32 +03:00
|
|
|
#endif
|