From 0ed13314f0e0f3fde64784008dad64755690ce1f Mon Sep 17 00:00:00 2001 From: jfrijters Date: Tue, 8 Jun 2010 05:25:14 +0000 Subject: [PATCH] Implemented codegen improvement to use CLR fault handlers for Java catch all handlers, whenever possible. --- runtime/TypeWrapper.cs | 39 ++++++-- runtime/compiler.cs | 104 ++++++++------------ runtime/verifier.cs | 209 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 254 insertions(+), 98 deletions(-) diff --git a/runtime/TypeWrapper.cs b/runtime/TypeWrapper.cs index 44735682..9f98916b 100644 --- a/runtime/TypeWrapper.cs +++ b/runtime/TypeWrapper.cs @@ -4620,14 +4620,22 @@ namespace IKVM.Internal sealed class VerifierTypeWrapper : TypeWrapper { internal static readonly TypeWrapper Invalid = null; - internal static readonly TypeWrapper Null = new VerifierTypeWrapper("null", 0, null); - internal static readonly TypeWrapper UninitializedThis = new VerifierTypeWrapper("uninitialized-this", 0, null); + internal static readonly TypeWrapper Null = new VerifierTypeWrapper("null", 0, null, null); + internal static readonly TypeWrapper UninitializedThis = new VerifierTypeWrapper("uninitialized-this", 0, null, null); internal static readonly TypeWrapper Unloadable = new UnloadableTypeWrapper(""); - internal static readonly TypeWrapper ExtendedFloat = new VerifierTypeWrapper("", 0, null); - internal static readonly TypeWrapper ExtendedDouble = new VerifierTypeWrapper("", 0, null); + internal static readonly TypeWrapper ExtendedFloat = new VerifierTypeWrapper("", 0, null, null); + internal static readonly TypeWrapper ExtendedDouble = new VerifierTypeWrapper("", 0, null, null); private int index; private TypeWrapper underlyingType; + private MethodAnalyzer methodAnalyzer; + +#if STUB_GENERATOR + internal class MethodAnalyzer + { + internal void ClearFaultBlockException(int dummy) { } + } +#endif public override string ToString() { @@ -4636,7 +4644,12 @@ namespace IKVM.Internal internal static TypeWrapper MakeNew(TypeWrapper type, int bytecodeIndex) { - return new VerifierTypeWrapper("new", bytecodeIndex, type); + return new VerifierTypeWrapper("new", bytecodeIndex, type, null); + } + + internal static TypeWrapper MakeFaultBlockException(MethodAnalyzer ma, int handlerIndex) + { + return new VerifierTypeWrapper("", handlerIndex, null, ma); } // NOTE the "this" type is special, it can only exist in local[0] and on the stack @@ -4646,7 +4659,7 @@ namespace IKVM.Internal // stack (using ldarg_0). internal static TypeWrapper MakeThis(TypeWrapper type) { - return new VerifierTypeWrapper("this", 0, type); + return new VerifierTypeWrapper("this", 0, type, null); } internal static bool IsNew(TypeWrapper w) @@ -4654,6 +4667,11 @@ namespace IKVM.Internal return w != null && w.IsVerifierType && ReferenceEquals(w.Name, "new"); } + internal static bool IsFaultBlockException(TypeWrapper w) + { + return w != null && w.IsVerifierType && ReferenceEquals(w.Name, ""); + } + internal static bool IsNullOrUnloadable(TypeWrapper w) { return w == Null || w.IsUnloadable; @@ -4664,6 +4682,12 @@ namespace IKVM.Internal return w != null && w.IsVerifierType && ReferenceEquals(w.Name, "this"); } + internal static void ClearFaultBlockException(TypeWrapper w) + { + VerifierTypeWrapper vtw = (VerifierTypeWrapper)w; + vtw.methodAnalyzer.ClearFaultBlockException(vtw.Index); + } + internal int Index { get @@ -4680,11 +4704,12 @@ namespace IKVM.Internal } } - private VerifierTypeWrapper(string name, int index, TypeWrapper underlyingType) + private VerifierTypeWrapper(string name, int index, TypeWrapper underlyingType, MethodAnalyzer methodAnalyzer) : base(TypeWrapper.VerifierTypeModifiersHack, name, null) { this.index = index; this.underlyingType = underlyingType; + this.methodAnalyzer = methodAnalyzer; } internal override ClassLoaderWrapper GetClassLoader() diff --git a/runtime/compiler.cs b/runtime/compiler.cs index d6a99ee1..429d4949 100644 --- a/runtime/compiler.cs +++ b/runtime/compiler.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2009 Jeroen Frijters + Copyright (C) 2002-2010 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 @@ -173,8 +173,6 @@ sealed class Compiler private readonly ClassFile.Method m; private readonly CodeEmitter ilGenerator; private readonly MethodAnalyzer ma; - private readonly ClassFile.Method.InstructionFlags[] flags; - private readonly ExceptionTableEntry[] exceptions; private readonly ISymbolDocumentWriter symboldocument; private readonly LineNumberTableAttribute.LineNumberWriter lineNumbers; private bool nonleaf; @@ -300,9 +298,6 @@ sealed class Compiler } } - flags = ma.ComputePartialReachability(0, m.ExceptionTable); - exceptions = MethodAnalyzer.UntangleExceptionBlocks(classFile, m.Instructions, flags, m.ExceptionTable); - // if we're emitting debugging information, we need to use scopes for local variables if(debug) { @@ -414,6 +409,7 @@ sealed class Compiler New, This, UnitializedThis, + FaultBlockException, Other } private Compiler compiler; @@ -466,6 +462,10 @@ sealed class Compiler // uninitialized references cannot be stored in a local, but we can reload them types[i] = StackType.UnitializedThis; } + else if (VerifierTypeWrapper.IsFaultBlockException(type)) + { + types[i] = StackType.FaultBlockException; + } else { types[i] = StackType.Other; @@ -481,7 +481,8 @@ sealed class Compiler compiler.ilGenerator.Emit(OpCodes.Ldnull); break; case StackType.New: - // new objects aren't really there on the stack + case StackType.FaultBlockException: + // objects aren't really there on the stack break; case StackType.This: case StackType.UnitializedThis: @@ -505,7 +506,8 @@ sealed class Compiler compiler.ilGenerator.LazyEmitPop(); break; case StackType.New: - // new objects aren't really there on the stack + case StackType.FaultBlockException: + // objects aren't really there on the stack break; case StackType.Other: compiler.ilGenerator.Emit(OpCodes.Stloc, locals[i]); @@ -615,7 +617,7 @@ sealed class Compiler ilGenerator.Emit(OpCodes.Call, monitorEnterMethod); ilGenerator.BeginExceptionBlock(); Block b = new Block(c, 0, int.MaxValue, -1, new List(), true); - c.Compile(b); + c.Compile(b, c.ma.ComputePartialReachability(0, true)); b.Leave(); ilGenerator.BeginFinallyBlock(); ilGenerator.Emit(OpCodes.Ldloc, monitor); @@ -626,14 +628,15 @@ sealed class Compiler else { Block b = new Block(c, 0, int.MaxValue, -1, null, false); - c.Compile(b); + c.Compile(b, c.ma.ComputePartialReachability(0, true)); b.Leave(); } if(c.lineNumbers != null) { + InstructionFlags[] flags = c.ma.ComputePartialReachability(0, false); for(int i = 0; i < m.Instructions.Length; i++) { - if((c.flags[i] & InstructionFlags.Reachable) == 0) + if((flags[i] & InstructionFlags.Reachable) == 0) { // skip unreachable instructions } @@ -885,31 +888,9 @@ sealed class Compiler } } - private bool IsGuardedBlock(Stack blockStack, int instructionIndex, int instructionCount) - { - int start = instructionIndex; - int end = instructionIndex + instructionCount; - for(int i = 0; i < exceptions.Length; i++) - { - ExceptionTableEntry e = exceptions[i]; - if(e.endIndex > start && e.startIndex < end) - { - foreach(Block block in blockStack) - { - if(block.ExceptionIndex == i) - { - goto next; - } - } - return true; - } - next:; - } - return false; - } - - private void Compile(Block block) + private void Compile(Block block, InstructionFlags[] flags) { + ExceptionTableEntry[] exceptions = ma.GetExceptionTableFor(flags); int exceptionIndex = 0; Instruction[] code = m.Instructions; Stack blockStack = new Stack(); @@ -948,32 +929,10 @@ sealed class Compiler int handlerIndex = exc.handlerIndex; - if(exc.catch_type == 0 - && handlerIndex + 2 < m.Instructions.Length - && m.Instructions[handlerIndex].NormalizedOpCode == NormalizedByteCode.__aload - && m.Instructions[handlerIndex + 1].NormalizedOpCode == NormalizedByteCode.__monitorexit - && m.Instructions[handlerIndex + 2].NormalizedOpCode == NormalizedByteCode.__athrow - && !IsGuardedBlock(blockStack, handlerIndex, 3)) + if(exc.catch_type == 0 && VerifierTypeWrapper.IsFaultBlockException(ma.GetRawStackTypeWrapper(handlerIndex, 0))) { - // this is the Jikes & Eclipse Java Compiler synchronization block exit ilGenerator.BeginFaultBlock(); - LoadLocal(handlerIndex); - ilGenerator.Emit(OpCodes.Call, monitorExitMethod); - ilGenerator.EndExceptionBlockNoFallThrough(); - } - else if(exc.catch_type == 0 - && handlerIndex + 3 < m.Instructions.Length - && m.Instructions[handlerIndex].NormalizedOpCode == NormalizedByteCode.__astore - && m.Instructions[handlerIndex + 1].NormalizedOpCode == NormalizedByteCode.__aload - && m.Instructions[handlerIndex + 2].NormalizedOpCode == NormalizedByteCode.__monitorexit - && m.Instructions[handlerIndex + 3].NormalizedOpCode == NormalizedByteCode.__aload - && m.Instructions[handlerIndex + 4].NormalizedOpCode == NormalizedByteCode.__athrow - && !IsGuardedBlock(blockStack, handlerIndex, 5)) - { - // this is the javac synchronization block exit - ilGenerator.BeginFaultBlock(); - LoadLocal(handlerIndex + 1); - ilGenerator.Emit(OpCodes.Call, monitorExitMethod); + Compile(new Block(this, 0, block.EndIndex, exceptionIndex, null, false), ma.ComputePartialReachability(handlerIndex, true)); ilGenerator.EndExceptionBlockNoFallThrough(); } else @@ -1802,6 +1761,10 @@ sealed class Compiler // so we don't have to worry about that. ilGenerator.Emit(OpCodes.Ldarg_0); } + else if (VerifierTypeWrapper.IsFaultBlockException(type)) + { + // not really there + } else { LocalVar v = LoadLocal(i); @@ -1827,6 +1790,10 @@ sealed class Compiler // the unitialized ref is loaded we redirect to the this reference ilGenerator.LazyEmitPop(); } + else if(VerifierTypeWrapper.IsFaultBlockException(type)) + { + // not really there + } else { StoreLocal(i); @@ -1866,7 +1833,7 @@ sealed class Compiler ilGenerator.Emit(OpCodes.Ldstr, wrapper.Name); ilGenerator.Emit(OpCodes.Call, ByteCodeHelperMethods.DynamicNewCheckOnly); } - else if(wrapper != clazz && RequiresExplicitClassInit(wrapper, i + 1)) + else if(wrapper != clazz && RequiresExplicitClassInit(wrapper, i + 1, flags)) { // trigger cctor (as the spec requires) wrapper.EmitRunClassConstructor(ilGenerator); @@ -2572,12 +2539,19 @@ sealed class Compiler ilGenerator.Emit(OpCodes.Throw); break; case NormalizedByteCode.__athrow: - if(ma.GetRawStackTypeWrapper(i, 0).IsUnloadable) + if (VerifierTypeWrapper.IsFaultBlockException(ma.GetRawStackTypeWrapper(i, 0))) { - ilGenerator.Emit(OpCodes.Castclass, Types.Exception); + ilGenerator.Emit(OpCodes.Endfinally); + } + else + { + if (ma.GetRawStackTypeWrapper(i, 0).IsUnloadable) + { + ilGenerator.Emit(OpCodes.Castclass, Types.Exception); + } + ilGenerator.Emit(OpCodes.Call, unmapExceptionMethod); + ilGenerator.Emit(OpCodes.Throw); } - ilGenerator.Emit(OpCodes.Call, unmapExceptionMethod); - ilGenerator.Emit(OpCodes.Throw); break; case NormalizedByteCode.__tableswitch: { @@ -2736,7 +2710,7 @@ sealed class Compiler } } - private bool RequiresExplicitClassInit(TypeWrapper tw, int index) + private bool RequiresExplicitClassInit(TypeWrapper tw, int index, InstructionFlags[] flags) { ClassFile.Method.Instruction[] code = m.Instructions; for (; index < code.Length; index++) diff --git a/runtime/verifier.cs b/runtime/verifier.cs index 05aa3efc..2d95e7b7 100644 --- a/runtime/verifier.cs +++ b/runtime/verifier.cs @@ -307,6 +307,16 @@ class InstructionState { return VerifierTypeWrapper.Invalid; } + if(VerifierTypeWrapper.IsFaultBlockException(type1)) + { + VerifierTypeWrapper.ClearFaultBlockException(type1); + return FindCommonBaseType(CoreClasses.java.lang.Throwable.Wrapper, type2); + } + if(VerifierTypeWrapper.IsFaultBlockException(type2)) + { + VerifierTypeWrapper.ClearFaultBlockException(type2); + return FindCommonBaseType(type1, CoreClasses.java.lang.Throwable.Wrapper); + } if(type1.IsPrimitive || type2.IsPrimitive) { return VerifierTypeWrapper.Invalid; @@ -677,6 +687,11 @@ class InstructionState } } + internal TypeWrapper PopFaultBlockException() + { + return stack[--stackSize]; + } + internal TypeWrapper PopAnyType() { if(stackSize == 0) @@ -692,6 +707,11 @@ class InstructionState { type = ((VerifierTypeWrapper)type).UnderlyingType; } + if(VerifierTypeWrapper.IsFaultBlockException(type)) + { + VerifierTypeWrapper.ClearFaultBlockException(type); + type = CoreClasses.java.lang.Throwable.Wrapper; + } return type; } @@ -878,6 +898,16 @@ class InstructionState } } } + + internal void ClearFaultBlockException() + { + if(VerifierTypeWrapper.IsFaultBlockException(stack[0])) + { + StackCopyOnWrite(); + changed = true; + stack[0] = CoreClasses.java.lang.Throwable.Wrapper; + } + } } struct StackState @@ -916,6 +946,11 @@ struct StackState { type = ((VerifierTypeWrapper)type).UnderlyingType; } + if(VerifierTypeWrapper.IsFaultBlockException(type)) + { + VerifierTypeWrapper.ClearFaultBlockException(type); + type = CoreClasses.java.lang.Throwable.Wrapper; + } return type; } @@ -1118,6 +1153,7 @@ class MethodAnalyzer private LocalVar[/*instructionIndex*/][/*localIndex*/] invokespecialLocalVars; private LocalVar[/*index*/] allLocalVars; private List errorMessages; + private ExceptionTableEntry[] exceptions; static MethodAnalyzer() { @@ -1147,6 +1183,7 @@ class MethodAnalyzer // HACK because types have to have identity, the new types are cached here Dictionary newTypes = new Dictionary(); + Dictionary faultTypes = new Dictionary(); try { @@ -1205,15 +1242,21 @@ class MethodAnalyzer firstNonArgLocalIndex++; } } - AnalyzeTypeFlow(wrapper, thisType, mw, localStoreReaders, newTypes); + AnalyzeTypeFlow(wrapper, thisType, mw, localStoreReaders, newTypes, faultTypes); + exceptions = UntangleExceptionBlocks(classFile, method.ExceptionTable); OptimizationPass(wrapper, classLoader); FinalCodePatchup(wrapper, mw); + if (AnalyzePotentialFaultBlocks()) + { + AnalyzeTypeFlow(wrapper, thisType, mw, localStoreReaders, newTypes, faultTypes); + } AnalyzeLocalVariables(localStoreReaders, classLoader); + ComputePartialReachability(0, true); } - private void AnalyzeTypeFlow(TypeWrapper wrapper, TypeWrapper thisType, MethodWrapper mw, Dictionary[] localStoreReaders, Dictionary newTypes) + private void AnalyzeTypeFlow(TypeWrapper wrapper, TypeWrapper thisType, MethodWrapper mw, Dictionary[] localStoreReaders, Dictionary newTypes, Dictionary faultTypes) { - InstructionState s = state[0].Copy(); + InstructionState s = new InstructionState(method.MaxLocals, method.MaxStack); bool done = false; ClassFile.Method.Instruction[] instructions = method.Instructions; while(!done) @@ -1233,11 +1276,18 @@ class MethodAnalyzer { if(method.ExceptionTable[j].startIndex <= i && i < method.ExceptionTable[j].endIndex) { + int idx = method.ExceptionTable[j].handlerIndex; InstructionState ex = state[i].CopyLocals(); int catch_type = method.ExceptionTable[j].catch_type; if(catch_type == 0) { - ex.PushType(CoreClasses.java.lang.Throwable.Wrapper); + TypeWrapper tw; + if (!faultTypes.TryGetValue(idx, out tw)) + { + tw = VerifierTypeWrapper.MakeFaultBlockException(this, idx); + faultTypes.Add(idx, tw); + } + ex.PushType(tw); } else { @@ -1245,7 +1295,6 @@ class MethodAnalyzer // Throwable as the type and recording a loader constraint ex.PushType(GetConstantPoolClassType(catch_type)); } - int idx = method.ExceptionTable[j].handlerIndex; state[idx] += ex; } } @@ -1265,6 +1314,11 @@ class MethodAnalyzer } case NormalizedByteCode.__astore: { + if(VerifierTypeWrapper.IsFaultBlockException(s.PeekType())) + { + s.SetLocalType(instr.NormalizedArg1, s.PopFaultBlockException(), i); + break; + } // NOTE since the reference can be uninitialized, we cannot use PopObjectType TypeWrapper type = s.PopType(); if(type.IsPrimitive) @@ -2058,7 +2112,14 @@ class MethodAnalyzer s.GetLocalInt(instr.Arg1, ref localStoreReaders[i]); break; case NormalizedByteCode.__athrow: - s.PopObjectType(CoreClasses.java.lang.Throwable.Wrapper); + if (VerifierTypeWrapper.IsFaultBlockException(s.PeekType())) + { + s.PopFaultBlockException(); + } + else + { + s.PopObjectType(CoreClasses.java.lang.Throwable.Wrapper); + } break; case NormalizedByteCode.__tableswitch: case NormalizedByteCode.__lookupswitch: @@ -2229,7 +2290,7 @@ class MethodAnalyzer if (assertionsDisabled != null) { // compute branch targets - InstructionFlags[] flags = ComputePartialReachability(0, method.ExceptionTable); + InstructionFlags[] flags = ComputePartialReachability(0, false); ClassFile.Method.Instruction[] instructions = method.Instructions; for (int i = 0; i < instructions.Length; i++) { @@ -2465,7 +2526,7 @@ class MethodAnalyzer } } - internal InstructionFlags[] ComputePartialReachability(int initialInstructionIndex, ClassFile.Method.ExceptionTableEntry[] exceptionTable) + internal InstructionFlags[] ComputePartialReachability(int initialInstructionIndex, bool skipFaultBlocks) { ClassFile.Method.Instruction[] instructions = method.Instructions; InstructionFlags[] flags = new InstructionFlags[instructions.Length]; @@ -2481,12 +2542,15 @@ class MethodAnalyzer done = false; flags[i] |= InstructionFlags.Processed; // mark the exception handlers reachable from this instruction - for (int j = 0; j < exceptionTable.Length; j++) + for (int j = 0; j < exceptions.Length; j++) { - if (exceptionTable[j].startIndex <= i && i < exceptionTable[j].endIndex) + if (exceptions[j].startIndex <= i && i < exceptions[j].endIndex) { - int idx = exceptionTable[j].handlerIndex; - flags[idx] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; + int idx = exceptions[j].handlerIndex; + if (!skipFaultBlocks || !VerifierTypeWrapper.IsFaultBlockException(state[idx].GetStackByIndex(0))) + { + flags[idx] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; + } } } // mark the successor instructions @@ -2531,6 +2595,7 @@ class MethodAnalyzer case NormalizedByteCode.__areturn: case NormalizedByteCode.__return: case NormalizedByteCode.__athrow: + case NormalizedByteCode.__athrow_no_unmap: case NormalizedByteCode.__static_error: break; default: @@ -2559,7 +2624,7 @@ class MethodAnalyzer Dictionary forwarders = new Dictionary(); if(classLoader.EmitDebugInfo) { - InstructionFlags[] flags = ComputePartialReachability(0, method.ExceptionTable); + InstructionFlags[] flags = ComputePartialReachability(0, false); // if we're emitting debug info, we need to keep dead stores as well... for(int i = 0; i < instructions.Length; i++) { @@ -2668,8 +2733,9 @@ class MethodAnalyzer this.allLocalVars = locals.ToArray(); } - internal static ExceptionTableEntry[] UntangleExceptionBlocks(ClassFile classFile, ClassFile.Method.Instruction[] instructions, InstructionFlags[] flags, ExceptionTableEntry[] exceptionTable) + private ExceptionTableEntry[] UntangleExceptionBlocks(ClassFile classFile, ExceptionTableEntry[] exceptionTable) { + ClassFile.Method.Instruction[] instructions = method.Instructions; List ar = new List(exceptionTable); // This optimization removes the recursive exception handlers that Java compiler place around @@ -2711,6 +2777,14 @@ class MethodAnalyzer ar.RemoveAt(i); i--; } + else if (index + 1 < instructions.Length + && ei.endIndex == index + 1 + && instructions[index].NormalizedOpCode == NormalizedByteCode.__astore) + { + // this is the finally guard that javac produces + ar.RemoveAt(i); + i--; + } } } @@ -2916,18 +2990,6 @@ class MethodAnalyzer next: ; } - // remove unreachable exception handlers (because the code gen depends on that) - for (int i = 0; i < ar.Count; i++) - { - // if the first instruction is unreachable, the entire block is unreachable, - // because you can't jump into a block (we've just split the blocks to ensure that) - if ((flags[ar[i].startIndex] & InstructionFlags.Reachable) == 0) - { - ar.RemoveAt(i); - i--; - } - } - ExceptionTableEntry[] exceptions = ar.ToArray(); Array.Sort(exceptions, new ExceptionSorter()); @@ -2957,6 +3019,79 @@ class MethodAnalyzer return exceptions; } + private bool AnalyzePotentialFaultBlocks() + { + ClassFile.Method.Instruction[] code = method.Instructions; + bool changed = false; + bool done = false; + while (!done) + { + done = true; + Stack stack = new Stack(); + ExceptionTableEntry current = new ExceptionTableEntry(0, code.Length, -1, ushort.MaxValue, -1); + stack.Push(current); + for (int i = 0; i < exceptions.Length; i++) + { + while (exceptions[i].startIndex >= current.endIndex) + { + current = stack.Pop(); + } + Debug.Assert(exceptions[i].startIndex >= current.startIndex && exceptions[i].endIndex <= current.endIndex); + if (exceptions[i].catch_type == 0 + && state[exceptions[i].handlerIndex] != null + && VerifierTypeWrapper.IsFaultBlockException(GetRawStackTypeWrapper(exceptions[i].handlerIndex, 0))) + { + InstructionFlags[] flags = ComputePartialReachability(exceptions[i].handlerIndex, true); + for (int j = 0; j < code.Length; j++) + { + if ((flags[j] & InstructionFlags.Reachable) != 0) + { + switch (code[j].NormalizedOpCode) + { + case NormalizedByteCode.__return: + case NormalizedByteCode.__areturn: + case NormalizedByteCode.__ireturn: + case NormalizedByteCode.__lreturn: + case NormalizedByteCode.__freturn: + case NormalizedByteCode.__dreturn: + goto not_fault_block; + case NormalizedByteCode.__athrow: + for (int k = i + 1; k < exceptions.Length; k++) + { + if (exceptions[k].startIndex <= j && j < exceptions[k].endIndex) + { + goto not_fault_block; + } + } + break; + } + if (j < current.startIndex || j >= current.endIndex) + { + goto not_fault_block; + } + else if (exceptions[i].startIndex <= j && j < exceptions[i].endIndex) + { + goto not_fault_block; + } + else + { + continue; + } + not_fault_block: + VerifierTypeWrapper.ClearFaultBlockException(GetRawStackTypeWrapper(exceptions[i].handlerIndex, 0)); + done = false; + changed = true; + break; + } + } + } + stack.Push(current); + current = exceptions[i]; + } + } + return changed; + } + private void SetHardError(ref ClassFile.Method.Instruction instruction, HardError hardError, string message, params object[] args) { string text = string.Format(message, args); @@ -3652,4 +3787,26 @@ class MethodAnalyzer { return allLocalVars; } + + internal void ClearFaultBlockException(int instructionIndex) + { + Debug.Assert(state[instructionIndex].GetStackHeight() == 1); + state[instructionIndex].ClearFaultBlockException(); + } + + internal ExceptionTableEntry[] GetExceptionTableFor(InstructionFlags[] flags) + { + List list = new List(); + // return only reachable exception handlers (because the code gen depends on that) + for (int i = 0; i < exceptions.Length; i++) + { + // if the first instruction is unreachable, the entire block is unreachable, + // because you can't jump into a block (we've just split the blocks to ensure that) + if ((flags[exceptions[i].startIndex] & InstructionFlags.Reachable) != 0) + { + list.Add(exceptions[i]); + } + } + return list.ToArray(); + } }