Update to the latest IKVM.Reflection
[mono.git] / mcs / class / IKVM.Reflection / Emit / ILGenerator.cs
index 21bd04467781ae3c7dadc636f96993f39bedd7af..b7be3f3a981264aec68145582e516567f30a74a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2008-2010 Jeroen Frijters
+  Copyright (C) 2008-2012 Jeroen Frijters
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -26,7 +26,6 @@ using System.Runtime.InteropServices;
 using System.Collections.Generic;
 using System.Diagnostics.SymbolStore;
 using System.Diagnostics;
-using IKVM.Reflection.Metadata;
 using IKVM.Reflection.Writer;
 
 namespace IKVM.Reflection.Emit
@@ -72,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)
@@ -99,29 +98,14 @@ 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
        {
-               private static readonly Type FAULT = new BakedType(null); // the type we use here doesn't matter, as long as it can never be used as a real exception type
                private readonly ModuleBuilder moduleBuilder;
                private readonly ByteBuffer code;
-               private readonly List<LocalBuilder> locals = new List<LocalBuilder>();
+               private readonly SignatureHelper locals;
+               private int localsCount;
                private readonly List<int> tokenFixups = new List<int>();
                private readonly List<int> labels = new List<int>();
                private readonly List<int> labelStackHeight = new List<int>();
@@ -130,6 +114,7 @@ namespace IKVM.Reflection.Emit
                private readonly List<ExceptionBlock> exceptions = new List<ExceptionBlock>();
                private readonly Stack<ExceptionBlock> exceptionStack = new Stack<ExceptionBlock>();
                private ushort maxStack;
+               private bool fatHeader;
                private int stackHeight;
                private Scope scope;
                private byte exceptionBlockAssistanceMode = EBAM_COMPAT;
@@ -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;    // null = finally block or handler with filter, 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
@@ -213,17 +209,13 @@ namespace IKVM.Reflection.Emit
                {
                        this.code = new ByteBuffer(initialCapacity);
                        this.moduleBuilder = moduleBuilder;
+                       this.locals = SignatureHelper.GetLocalVarSigHelper(moduleBuilder);
                        if (moduleBuilder.symbolWriter != null)
                        {
                                scope = new Scope(null);
                        }
                }
 
-               private bool IsLabelReachable(Label label)
-               {
-                       return labelStackHeight[label.Index] != -1;
-               }
-
                // non-standard API
                public void __DisableExceptionBlockAssistance()
                {
@@ -236,6 +228,24 @@ namespace IKVM.Reflection.Emit
                        exceptionBlockAssistanceMode = EBAM_CLEVER;
                }
 
+               // non-standard API
+               public int __MaxStackSize
+               {
+                       get { return maxStack; }
+                       set
+                       {
+                               maxStack = (ushort)value;
+                               fatHeader = true;
+                       }
+               }
+
+               // non-standard API
+               // returns -1 if the current position is currently unreachable
+               public int __StackHeight
+               {
+                       get { return stackHeight; }
+               }
+
                // new in .NET 4.0
                public int ILOffset
                {
@@ -244,17 +254,37 @@ 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);
@@ -262,7 +292,7 @@ namespace IKVM.Reflection.Emit
                        {
                                block.tryLength = code.Position - block.tryOffset;
                        }
-                       else if (exceptionType != null)
+                       else
                        {
                                block.handlerLength = code.Position - block.handlerOffset;
                                exceptionStack.Pop();
@@ -274,8 +304,7 @@ namespace IKVM.Reflection.Emit
                                exceptions.Add(block);
                                exceptionStack.Push(block);
                        }
-                       block.handlerOffset = code.Position;
-                       block.exceptionType = exceptionType;
+                       return block;
                }
 
                public Label BeginExceptionBlock()
@@ -291,25 +320,22 @@ namespace IKVM.Reflection.Emit
 
                public void BeginExceptFilterBlock()
                {
-                       ExceptionBlock block = BeginFinallyFilterFaultBlock();
-                       block.filterOffset = code.Position;
-                       UpdateStack(1);
+                       ExceptionBlock block = BeginCatchOrFilterBlock();
+                       block.kind = ExceptionHandlingClauseOptions.Filter;
+                       block.filterOffsetOrExceptionTypeToken = code.Position;
                }
 
                public void BeginFaultBlock()
                {
-                       ExceptionBlock block = BeginFinallyFilterFaultBlock();
-                       block.handlerOffset = code.Position;
-                       block.exceptionType = FAULT;
+                       BeginFinallyFaultBlock(ExceptionHandlingClauseOptions.Fault);
                }
 
                public void BeginFinallyBlock()
                {
-                       ExceptionBlock block = BeginFinallyFilterFaultBlock();
-                       block.handlerOffset = code.Position;
+                       BeginFinallyFaultBlock(ExceptionHandlingClauseOptions.Finally);
                }
 
-               private ExceptionBlock BeginFinallyFilterFaultBlock()
+               private void BeginFinallyFaultBlock(ExceptionHandlingClauseOptions kind)
                {
                        ExceptionBlock block = exceptionStack.Peek();
                        if (exceptionBlockAssistanceMode == EBAM_COMPAT || (exceptionBlockAssistanceMode == EBAM_CLEVER && stackHeight != -1))
@@ -343,8 +369,9 @@ namespace IKVM.Reflection.Emit
                                exceptions.Add(block);
                                exceptionStack.Push(block);
                        }
+                       block.handlerOffset = code.Position;
+                       block.kind = kind;
                        stackHeight = 0;
-                       return block;
                }
 
                public void EndExceptionBlock()
@@ -352,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 != null && block.exceptionType != FAULT))
+                               if (block.kind != ExceptionHandlingClauseOptions.Finally && block.kind != ExceptionHandlingClauseOptions.Fault)
                                {
                                        Emit(OpCodes.Leave, block.labelEnd);
                                }
@@ -388,8 +415,19 @@ namespace IKVM.Reflection.Emit
 
                public LocalBuilder DeclareLocal(Type localType, bool pinned)
                {
-                       LocalBuilder local = new LocalBuilder(localType, locals.Count, pinned);
-                       locals.Add(local);
+                       LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned);
+                       locals.AddArgument(localType, pinned);
+                       if (scope != null)
+                       {
+                               scope.locals.Add(local);
+                       }
+                       return local;
+               }
+
+               public LocalBuilder __DeclareLocal(Type localType, bool pinned, CustomModifiers customModifiers)
+               {
+                       LocalBuilder local = new LocalBuilder(localType, localsCount++, pinned, customModifiers);
+                       locals.__AddArgument(localType, pinned, customModifiers);
                        if (scope != null)
                        {
                                scope.locals.Add(local);
@@ -455,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)
@@ -632,22 +670,13 @@ namespace IKVM.Reflection.Emit
                        }
                }
 
-               private void WriteToken(FieldToken token)
+               private void WriteToken(int token)
                {
-                       if (token.IsPseudoToken)
+                       if (ModuleBuilder.IsPseudoToken(token))
                        {
                                tokenFixups.Add(code.Position);
                        }
-                       code.Write(token.Token);
-               }
-
-               private void WriteToken(MethodToken token)
-               {
-                       if (token.IsPseudoToken)
-                       {
-                               tokenFixups.Add(code.Position);
-                       }
-                       code.Write(token.Token);
+                       code.Write(token);
                }
 
                private void UpdateStack(OpCode opc, bool hasthis, Type returnType, int parameterCount)
@@ -679,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)
@@ -702,7 +731,7 @@ namespace IKVM.Reflection.Emit
                public void Emit(OpCode opc, string str)
                {
                        Emit(opc);
-                       code.Write(0x70000000 | moduleBuilder.UserStrings.Add(str));
+                       code.Write(moduleBuilder.GetStringConstant(str).Token);
                }
 
                public void Emit(OpCode opc, Type type)
@@ -722,10 +751,15 @@ namespace IKVM.Reflection.Emit
                {
                        Emit(opcode);
                        UpdateStack(opcode, signature.HasThis, signature.ReturnType, signature.ParameterCount);
-                       code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(signature.GetSignature(moduleBuilder))));
+                       code.Write(moduleBuilder.GetSignatureToken(signature).Token);
                }
 
                public void EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes)
+               {
+                       __EmitCall(opc, method, optionalParameterTypes, null);
+               }
+
+               public void __EmitCall(OpCode opc, MethodInfo method, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
                {
                        if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
                        {
@@ -735,20 +769,7 @@ namespace IKVM.Reflection.Emit
                        {
                                Emit(opc);
                                UpdateStack(opc, method.HasThis, method.ReturnType, method.ParameterCount + optionalParameterTypes.Length);
-                               ByteBuffer sig = new ByteBuffer(16);
-                               method.MethodSignature.WriteMethodRefSig(moduleBuilder, sig, optionalParameterTypes);
-                               MemberRefTable.Record record = new MemberRefTable.Record();
-                               if (method.Module == moduleBuilder)
-                               {
-                                       record.Class = method.MetadataToken;
-                               }
-                               else
-                               {
-                                       record.Class = moduleBuilder.GetTypeTokenForMemberRef(method.DeclaringType ?? method.Module.GetModuleType());
-                               }
-                               record.Name = moduleBuilder.Strings.Add(method.Name);
-                               record.Signature = moduleBuilder.Blobs.Add(sig);
-                               code.Write(0x0A000000 | moduleBuilder.MemberRef.FindOrAddRecord(record));
+                               code.Write(moduleBuilder.__GetMethodToken(method, optionalParameterTypes, customModifiers).Token);
                        }
                }
 
@@ -757,25 +778,42 @@ namespace IKVM.Reflection.Emit
                        EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes);
                }
 
+               public void __EmitCall(OpCode opc, ConstructorInfo constructor, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
+               {
+                       __EmitCall(opc, constructor.GetMethodInfo(), optionalParameterTypes, customModifiers);
+               }
+
                public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
                {
-                       returnType = returnType ?? moduleBuilder.universe.System_Void;
-                       Emit(opc);
-                       UpdateStack(opc, false, returnType, parameterTypes.Length);
-                       ByteBuffer sig = new ByteBuffer(16);
-                       Signature.WriteStandAloneMethodSig(moduleBuilder, sig, callingConvention, returnType, parameterTypes);
-                       code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(sig)));
+                       SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
+                       sig.AddArguments(parameterTypes, null, null);
+                       Emit(opc, sig);
                }
 
                public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
                {
-                       returnType = returnType ?? moduleBuilder.universe.System_Void;
-                       optionalParameterTypes = optionalParameterTypes ?? Type.EmptyTypes;
+                       SignatureHelper sig = SignatureHelper.GetMethodSigHelper(moduleBuilder, callingConvention, returnType);
+                       sig.AddArguments(parameterTypes, null, null);
+                       sig.AddSentinel();
+                       sig.AddArguments(optionalParameterTypes, null, null);
+                       Emit(opc, sig);
+               }
+
+               public void __EmitCalli(OpCode opc, __StandAloneMethodSig sig)
+               {
                        Emit(opc);
-                       UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, returnType, parameterTypes.Length + optionalParameterTypes.Length);
-                       ByteBuffer sig = new ByteBuffer(16);
-                       Signature.WriteStandAloneMethodSig(moduleBuilder, sig, callingConvention, returnType, parameterTypes, optionalParameterTypes);
-                       code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(sig)));
+                       if (sig.IsUnmanaged)
+                       {
+                               UpdateStack(opc, false, sig.ReturnType, sig.ParameterCount);
+                       }
+                       else
+                       {
+                               CallingConventions callingConvention = sig.CallingConvention;
+                               UpdateStack(opc, (callingConvention & CallingConventions.HasThis | CallingConventions.ExplicitThis) == CallingConventions.HasThis, sig.ReturnType, sig.ParameterCount);
+                       }
+                       ByteBuffer bb = new ByteBuffer(16);
+                       Signature.WriteStandAloneMethodSig(moduleBuilder, bb, sig);
+                       code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(bb)));
                }
 
                public void EmitWriteLine(string text)
@@ -874,13 +912,17 @@ namespace IKVM.Reflection.Emit
                        int localVarSigTok = 0;
 
                        int rva;
-                       if (locals.Count == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64)
+                       if (localsCount == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64 && !fatHeader)
                        {
                                rva = WriteTinyHeaderAndCode(bb);
                        }
                        else
                        {
-                               rva = WriteFatHeaderAndCode(bb, ref localVarSigTok, initLocals);
+                               if (localsCount != 0)
+                               {
+                                       localVarSigTok = moduleBuilder.GetSignatureToken(locals).Token;
+                               }
+                               rva = WriteFatHeaderAndCode(bb, localVarSigTok, initLocals);
                        }
 
                        if (moduleBuilder.symbolWriter != null)
@@ -947,28 +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 (locals.Count != 0)
-                       {
-                               ByteBuffer localVarSig = new ByteBuffer(locals.Count + 2);
-                               Signature.WriteLocalVarSig(moduleBuilder, localVarSig, locals);
-                               localVarSigTok = 0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(localVarSig));
-                       }
-
+               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;
@@ -979,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)
@@ -1004,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 == FAULT)
-                                               {
-                                                       bb.Write((int)COR_ILEXCEPTION_CLAUSE_FAULT);
-                                               }
-                                               else if (block.filterOffset != 0)
-                                               {
-                                                       bb.Write((int)COR_ILEXCEPTION_CLAUSE_FILTER);
-                                               }
-                                               else if (block.exceptionType != null)
-                                               {
-                                                       bb.Write((int)COR_ILEXCEPTION_CLAUSE_EXCEPTION);
-                                               }
-                                               else
-                                               {
-                                                       bb.Write((int)COR_ILEXCEPTION_CLAUSE_FINALLY);
-                                               }
-                                               bb.Write(block.tryOffset);
-                                               bb.Write(block.tryLength);
-                                               bb.Write(block.handlerOffset);
-                                               bb.Write(block.handlerLength);
-                                               if (block.exceptionType != null && block.exceptionType != FAULT)
-                                               {
-                                                       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 == FAULT)
-                                               {
-                                                       bb.Write(COR_ILEXCEPTION_CLAUSE_FAULT);
-                                               }
-                                               else if (block.filterOffset != 0)
-                                               {
-                                                       bb.Write(COR_ILEXCEPTION_CLAUSE_FILTER);
-                                               }
-                                               else if (block.exceptionType != null)
-                                               {
-                                                       bb.Write(COR_ILEXCEPTION_CLAUSE_EXCEPTION);
-                                               }
-                                               else
-                                               {
-                                                       bb.Write(COR_ILEXCEPTION_CLAUSE_FINALLY);
-                                               }
-                                               bb.Write((short)block.tryOffset);
-                                               bb.Write((byte)block.tryLength);
-                                               bb.Write((short)block.handlerOffset);
-                                               bb.Write((byte)block.handlerLength);
-                                               if (block.exceptionType != null && block.exceptionType != FAULT)
-                                               {
-                                                       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)