Update to the latest IKVM.Reflection
[mono.git] / mcs / class / IKVM.Reflection / Emit / ILGenerator.cs
index 7fddd7bcdb6f0edbfbeb7083f8a9c01d98db4c18..b7be3f3a981264aec68145582e516567f30a74a6 100644 (file)
@@ -71,20 +71,20 @@ 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)
@@ -98,21 +98,6 @@ namespace IKVM.Reflection.Emit
                        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
@@ -143,7 +128,7 @@ namespace IKVM.Reflection.Emit
                        internal int offset;
                }
 
-               private sealed class ExceptionBlock : IComparer<ExceptionBlock>
+               internal sealed class ExceptionBlock : IComparer<ExceptionBlock>
                {
                        internal readonly int ordinal;
                        internal Label labelEnd;
@@ -151,14 +136,25 @@ namespace IKVM.Reflection.Emit
                        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
@@ -258,56 +254,57 @@ namespace IKVM.Reflection.Emit
 
                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()
@@ -323,20 +320,22 @@ namespace IKVM.Reflection.Emit
 
                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))
@@ -371,7 +370,7 @@ namespace IKVM.Reflection.Emit
                                exceptionStack.Push(block);
                        }
                        block.handlerOffset = code.Position;
-                       block.exceptionType = type;
+                       block.kind = kind;
                        stackHeight = 0;
                }
 
@@ -380,7 +379,7 @@ namespace IKVM.Reflection.Emit
                        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);
                                }
@@ -427,7 +426,7 @@ namespace IKVM.Reflection.Emit
 
                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)
                        {
@@ -494,7 +493,7 @@ namespace IKVM.Reflection.Emit
                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)
@@ -671,22 +670,13 @@ namespace IKVM.Reflection.Emit
                        }
                }
 
-               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)
@@ -718,7 +708,7 @@ namespace IKVM.Reflection.Emit
                {
                        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)
@@ -928,7 +918,11 @@ namespace IKVM.Reflection.Emit
                        }
                        else
                        {
-                               rva = WriteFatHeaderAndCode(bb, ref localVarSigTok, initLocals);
+                               if (localsCount != 0)
+                               {
+                                       localVarSigTok = moduleBuilder.GetSignatureToken(locals).Token;
+                               }
+                               rva = WriteFatHeaderAndCode(bb, localVarSigTok, initLocals);
                        }
 
                        if (moduleBuilder.symbolWriter != null)
@@ -995,26 +989,23 @@ namespace IKVM.Reflection.Emit
                        }
                }
 
-               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;
@@ -1025,23 +1016,44 @@ namespace IKVM.Reflection.Emit
                                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)
@@ -1050,105 +1062,50 @@ namespace IKVM.Reflection.Emit
                                                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)