using System.Collections.Generic;
using System.Diagnostics.SymbolStore;
using System.Diagnostics;
-using IKVM.Reflection.Metadata;
using IKVM.Reflection.Writer;
namespace IKVM.Reflection.Emit
}
}
- public sealed class LocalBuilder
+ public sealed class LocalBuilder : LocalVariableInfo
{
- private readonly Type localType;
- private readonly int index;
- private readonly bool pinned;
internal string name;
internal int startOffset;
internal int endOffset;
internal LocalBuilder(Type localType, int index, bool pinned)
+ : base(index, localType, pinned)
+ {
+ }
+
+ internal LocalBuilder(Type localType, int index, bool pinned, CustomModifiers customModifiers)
+ : base(index, localType, pinned, customModifiers)
{
- this.localType = localType;
- this.index = index;
- this.pinned = pinned;
}
public void SetLocalSymInfo(string name)
this.startOffset = startOffset;
this.endOffset = endOffset;
}
-
- public Type LocalType
- {
- get { return localType; }
- }
-
- public int LocalIndex
- {
- get { return index; }
- }
-
- public bool IsPinned
- {
- get { return pinned; }
- }
}
public sealed class ILGenerator
internal int offset;
}
- private sealed class ExceptionBlock : IComparer<ExceptionBlock>
+ internal sealed class ExceptionBlock : IComparer<ExceptionBlock>
{
internal readonly int ordinal;
internal Label labelEnd;
internal int tryLength;
internal int handlerOffset;
internal int handlerLength;
- internal Type exceptionType; // MarkerType.Finally = finally block, MarkerType.Filter = handler with filter, MarkerType.Fault = fault block
- internal int filterOffset;
+ internal int filterOffsetOrExceptionTypeToken;
+ internal ExceptionHandlingClauseOptions kind;
internal ExceptionBlock(int ordinal)
{
this.ordinal = ordinal;
}
+ internal ExceptionBlock(ExceptionHandler h)
+ {
+ this.ordinal = -1;
+ this.tryOffset = h.TryOffset;
+ this.tryLength = h.TryLength;
+ this.handlerOffset = h.HandlerOffset;
+ this.handlerLength = h.HandlerLength;
+ this.kind = h.Kind;
+ this.filterOffsetOrExceptionTypeToken = kind == ExceptionHandlingClauseOptions.Filter ? h.FilterOffset : h.ExceptionTypeToken;
+ }
+
int IComparer<ExceptionBlock>.Compare(ExceptionBlock x, ExceptionBlock y)
{
// Mono's sort insists on doing unnecessary comparisons
public void BeginCatchBlock(Type exceptionType)
{
- ExceptionBlock block = exceptionStack.Peek();
- if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
+ if (exceptionType == null)
{
- if (exceptionType == null)
+ // this must be a catch block after a filter
+ ExceptionBlock block = exceptionStack.Peek();
+ if (block.kind != ExceptionHandlingClauseOptions.Filter || block.handlerOffset != 0)
{
- Emit(OpCodes.Endfilter);
+ throw new ArgumentNullException("exceptionType");
}
- else
+ if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
{
- Emit(OpCodes.Leave, block.labelEnd);
+ Emit(OpCodes.Endfilter);
}
+ stackHeight = 0;
+ UpdateStack(1);
+ block.handlerOffset = code.Position;
+ }
+ else
+ {
+ ExceptionBlock block = BeginCatchOrFilterBlock();
+ block.kind = ExceptionHandlingClauseOptions.Clause;
+ block.filterOffsetOrExceptionTypeToken = moduleBuilder.GetTypeTokenForMemberRef(exceptionType);
+ block.handlerOffset = code.Position;
+ }
+ }
+
+ private ExceptionBlock BeginCatchOrFilterBlock()
+ {
+ ExceptionBlock block = exceptionStack.Peek();
+ if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
+ {
+ Emit(OpCodes.Leave, block.labelEnd);
}
stackHeight = 0;
UpdateStack(1);
- if (exceptionType == null)
+ if (block.tryLength == 0)
{
- if (block.exceptionType != MarkerType.Filter || block.handlerOffset != 0)
- {
- throw new ArgumentNullException("exceptionType");
- }
- block.handlerOffset = code.Position;
+ block.tryLength = code.Position - block.tryOffset;
}
else
{
- if (block.tryLength == 0)
- {
- block.tryLength = code.Position - block.tryOffset;
- }
- else
- {
- block.handlerLength = code.Position - block.handlerOffset;
- exceptionStack.Pop();
- ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
- newBlock.labelEnd = block.labelEnd;
- newBlock.tryOffset = block.tryOffset;
- newBlock.tryLength = block.tryLength;
- block = newBlock;
- exceptions.Add(block);
- exceptionStack.Push(block);
- }
- block.exceptionType = exceptionType;
- if (exceptionType == MarkerType.Filter)
- {
- block.filterOffset = code.Position;
- }
- else
- {
- block.handlerOffset = code.Position;
- }
+ block.handlerLength = code.Position - block.handlerOffset;
+ exceptionStack.Pop();
+ ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
+ newBlock.labelEnd = block.labelEnd;
+ newBlock.tryOffset = block.tryOffset;
+ newBlock.tryLength = block.tryLength;
+ block = newBlock;
+ exceptions.Add(block);
+ exceptionStack.Push(block);
}
+ return block;
}
public Label BeginExceptionBlock()
public void BeginExceptFilterBlock()
{
- BeginCatchBlock(MarkerType.Filter);
+ ExceptionBlock block = BeginCatchOrFilterBlock();
+ block.kind = ExceptionHandlingClauseOptions.Filter;
+ block.filterOffsetOrExceptionTypeToken = code.Position;
}
public void BeginFaultBlock()
{
- BeginFinallyFaultBlock(MarkerType.Fault);
+ BeginFinallyFaultBlock(ExceptionHandlingClauseOptions.Fault);
}
public void BeginFinallyBlock()
{
- BeginFinallyFaultBlock(MarkerType.Finally);
+ BeginFinallyFaultBlock(ExceptionHandlingClauseOptions.Finally);
}
- private void BeginFinallyFaultBlock(Type type)
+ private void BeginFinallyFaultBlock(ExceptionHandlingClauseOptions kind)
{
ExceptionBlock block = exceptionStack.Peek();
if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
exceptionStack.Push(block);
}
block.handlerOffset = code.Position;
- block.exceptionType = type;
+ block.kind = kind;
stackHeight = 0;
}
ExceptionBlock block = exceptionStack.Pop();
if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
{
- if (block.filterOffset != 0 || (block.exceptionType != MarkerType.Finally && block.exceptionType != MarkerType.Fault))
+ if (block.kind != ExceptionHandlingClauseOptions.Finally && block.kind != ExceptionHandlingClauseOptions.Fault)
{
Emit(OpCodes.Leave, block.labelEnd);
}
public LocalBuilder __DeclareLocal(Type localType, bool pinned, CustomModifiers customModifiers)
{
- LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned);
+ LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned, customModifiers);
locals.__AddArgument(localType, pinned, customModifiers);
if (scope != null)
{
public void Emit(OpCode opc, FieldInfo field)
{
Emit(opc);
- WriteToken(moduleBuilder.GetFieldToken(field));
+ WriteToken(moduleBuilder.GetFieldToken(field).Token);
}
public void Emit(OpCode opc, short arg)
}
}
- private void WriteToken(FieldToken token)
- {
- if (token.IsPseudoToken)
- {
- tokenFixups.Add(code.Position);
- }
- code.Write(token.Token);
- }
-
- private void WriteToken(MethodToken token)
+ private void WriteToken(int token)
{
- if (token.IsPseudoToken)
+ if (ModuleBuilder.IsPseudoToken(token))
{
tokenFixups.Add(code.Position);
}
- code.Write(token.Token);
+ code.Write(token);
}
private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
{
UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount);
Emit(opc);
- WriteToken(moduleBuilder.GetMethodTokenForIL(method));
+ WriteToken(moduleBuilder.GetMethodTokenForIL(method).Token);
}
public void Emit(OpCode opc, ConstructorInfo constructor)
}
else
{
- rva = WriteFatHeaderAndCode(bb, ref localVarSigTok, initLocals);
+ if (localsCount != 0)
+ {
+ localVarSigTok = moduleBuilder.GetSignatureToken(locals).Token;
+ }
+ rva = WriteFatHeaderAndCode(bb, localVarSigTok, initLocals);
}
if (moduleBuilder.symbolWriter != null)
}
}
- private int WriteTinyHeaderAndCode(ByteBuffer bb)
+ internal static void WriteTinyHeader(ByteBuffer bb, int length)
{
- int rva = bb.Position;
const byte CorILMethod_TinyFormat = 0x2;
- bb.Write((byte)(CorILMethod_TinyFormat | (code.Length << 2)));
- WriteCode(bb);
- return rva;
+ bb.Write((byte)(CorILMethod_TinyFormat | (length << 2)));
}
- private int WriteFatHeaderAndCode(ByteBuffer bb, ref int localVarSigTok, bool initLocals)
+ private int WriteTinyHeaderAndCode(ByteBuffer bb)
{
- // fat headers require 4-byte alignment
- bb.Align(4);
int rva = bb.Position;
+ WriteTinyHeader(bb, code.Length);
+ AddTokenFixups(bb.Position, moduleBuilder.tokenFixupOffsets, tokenFixups);
+ bb.Write(code);
+ return rva;
+ }
- if (localsCount != 0)
- {
- localVarSigTok = moduleBuilder.GetSignatureToken(locals).Token;
- }
-
+ internal static void WriteFatHeader(ByteBuffer bb, bool initLocals, bool exceptions, ushort maxStack, int codeLength, int localVarSigTok)
+ {
const byte CorILMethod_FatFormat = 0x03;
const byte CorILMethod_MoreSects = 0x08;
const byte CorILMethod_InitLocals = 0x10;
flagsAndSize |= CorILMethod_InitLocals;
}
- if (exceptions.Count > 0)
+ if (exceptions)
{
flagsAndSize |= CorILMethod_MoreSects;
}
bb.Write(flagsAndSize);
bb.Write(maxStack);
- bb.Write(code.Length);
+ bb.Write(codeLength);
bb.Write(localVarSigTok);
+ }
- WriteCode(bb);
-
+ private int WriteFatHeaderAndCode(ByteBuffer bb, int localVarSigTok, bool initLocals)
+ {
+ // fat headers require 4-byte alignment
+ bb.Align(4);
+ int rva = bb.Position;
+ WriteFatHeader(bb, initLocals, exceptions.Count > 0, maxStack, code.Length, localVarSigTok);
+ AddTokenFixups(bb.Position, moduleBuilder.tokenFixupOffsets, tokenFixups);
+ bb.Write(code);
if (exceptions.Count > 0)
{
- bb.Align(4);
+ exceptions.Sort(exceptions[0]);
+ WriteExceptionHandlers(bb, exceptions);
+ }
+ return rva;
+ }
- bool fat = false;
+ internal static void WriteExceptionHandlers(ByteBuffer bb, List<ExceptionBlock> exceptions)
+ {
+ bb.Align(4);
+
+ bool fat = false;
+ if (exceptions.Count * 12 + 4 > 255)
+ {
+ fat = true;
+ }
+ else
+ {
foreach (ExceptionBlock block in exceptions)
{
if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
break;
}
}
- exceptions.Sort(exceptions[0]);
- if (exceptions.Count * 12 + 4 > 255)
- {
- fat = true;
- }
- const byte CorILMethod_Sect_EHTable = 0x1;
- const byte CorILMethod_Sect_FatFormat = 0x40;
- const short COR_ILEXCEPTION_CLAUSE_EXCEPTION = 0x0000;
- const short COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001;
- const short COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002;
- const short COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004;
-
- if (fat)
+ }
+
+ const byte CorILMethod_Sect_EHTable = 0x1;
+ const byte CorILMethod_Sect_FatFormat = 0x40;
+
+ if (fat)
+ {
+ bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
+ int dataSize = exceptions.Count * 24 + 4;
+ bb.Write((byte)dataSize);
+ bb.Write((short)(dataSize >> 8));
+ foreach (ExceptionBlock block in exceptions)
{
- bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
- int dataSize = exceptions.Count * 24 + 4;
- bb.Write((byte)dataSize);
- bb.Write((short)(dataSize >> 8));
- foreach (ExceptionBlock block in exceptions)
- {
- if (block.exceptionType == MarkerType.Fault)
- {
- bb.Write((int)COR_ILEXCEPTION_CLAUSE_FAULT);
- }
- else if (block.exceptionType == MarkerType.Filter)
- {
- bb.Write((int)COR_ILEXCEPTION_CLAUSE_FILTER);
- }
- else if (block.exceptionType == MarkerType.Finally)
- {
- bb.Write((int)COR_ILEXCEPTION_CLAUSE_FINALLY);
- }
- else
- {
- bb.Write((int)COR_ILEXCEPTION_CLAUSE_EXCEPTION);
- }
- bb.Write(block.tryOffset);
- bb.Write(block.tryLength);
- bb.Write(block.handlerOffset);
- bb.Write(block.handlerLength);
- if (block.exceptionType != MarkerType.Fault && block.exceptionType != MarkerType.Filter && block.exceptionType != MarkerType.Finally)
- {
- bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
- }
- else
- {
- bb.Write(block.filterOffset);
- }
- }
+ bb.Write((int)block.kind);
+ bb.Write(block.tryOffset);
+ bb.Write(block.tryLength);
+ bb.Write(block.handlerOffset);
+ bb.Write(block.handlerLength);
+ bb.Write(block.filterOffsetOrExceptionTypeToken);
}
- else
+ }
+ else
+ {
+ bb.Write(CorILMethod_Sect_EHTable);
+ bb.Write((byte)(exceptions.Count * 12 + 4));
+ bb.Write((short)0);
+ foreach (ExceptionBlock block in exceptions)
{
- bb.Write(CorILMethod_Sect_EHTable);
- bb.Write((byte)(exceptions.Count * 12 + 4));
- bb.Write((short)0);
- foreach (ExceptionBlock block in exceptions)
- {
- if (block.exceptionType == MarkerType.Fault)
- {
- bb.Write(COR_ILEXCEPTION_CLAUSE_FAULT);
- }
- else if (block.exceptionType == MarkerType.Filter)
- {
- bb.Write(COR_ILEXCEPTION_CLAUSE_FILTER);
- }
- else if (block.exceptionType == MarkerType.Finally)
- {
- bb.Write(COR_ILEXCEPTION_CLAUSE_FINALLY);
- }
- else
- {
- bb.Write(COR_ILEXCEPTION_CLAUSE_EXCEPTION);
- }
- bb.Write((short)block.tryOffset);
- bb.Write((byte)block.tryLength);
- bb.Write((short)block.handlerOffset);
- bb.Write((byte)block.handlerLength);
- if (block.exceptionType != MarkerType.Fault && block.exceptionType != MarkerType.Filter && block.exceptionType != MarkerType.Finally)
- {
- bb.Write(moduleBuilder.GetTypeTokenForMemberRef(block.exceptionType));
- }
- else
- {
- bb.Write(block.filterOffset);
- }
- }
+ bb.Write((short)block.kind);
+ bb.Write((short)block.tryOffset);
+ bb.Write((byte)block.tryLength);
+ bb.Write((short)block.handlerOffset);
+ bb.Write((byte)block.handlerLength);
+ bb.Write(block.filterOffsetOrExceptionTypeToken);
}
}
- return rva;
}
- private void WriteCode(ByteBuffer bb)
+ internal static void AddTokenFixups(int codeOffset, List<int> tokenFixupOffsets, IEnumerable<int> tokenFixups)
{
- int codeOffset = bb.Position;
- foreach (int fixup in this.tokenFixups)
+ foreach (int fixup in tokenFixups)
{
- moduleBuilder.tokenFixupOffsets.Add(fixup + codeOffset);
+ tokenFixupOffsets.Add(fixup + codeOffset);
}
- bb.Write(code);
}
private void WriteScope(Scope scope, int localVarSigTok)