Implemented codegen improvement to use CLR fault handlers for Java catch all handlers, whenever possible.

This commit is contained in:
jfrijters 2010-06-08 05:25:14 +00:00
Родитель 3ca0627114
Коммит 0ed13314f0
3 изменённых файлов: 254 добавлений и 98 удалений

Просмотреть файл

@ -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("<verifier>");
internal static readonly TypeWrapper ExtendedFloat = new VerifierTypeWrapper("<extfloat>", 0, null);
internal static readonly TypeWrapper ExtendedDouble = new VerifierTypeWrapper("<extdouble>", 0, null);
internal static readonly TypeWrapper ExtendedFloat = new VerifierTypeWrapper("<extfloat>", 0, null, null);
internal static readonly TypeWrapper ExtendedDouble = new VerifierTypeWrapper("<extdouble>", 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("<fault>", 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, "<fault>");
}
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()

Просмотреть файл

@ -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<object>(), 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<Block> 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<Block> blockStack = new Stack<Block>();
@ -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++)

Просмотреть файл

@ -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<string> 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<int, TypeWrapper> newTypes = new Dictionary<int,TypeWrapper>();
Dictionary<int, TypeWrapper> faultTypes = new Dictionary<int, TypeWrapper>();
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<int, string>[] localStoreReaders, Dictionary<int, TypeWrapper> newTypes)
private void AnalyzeTypeFlow(TypeWrapper wrapper, TypeWrapper thisType, MethodWrapper mw, Dictionary<int, string>[] localStoreReaders, Dictionary<int, TypeWrapper> newTypes, Dictionary<int, TypeWrapper> 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<LocalVar, LocalVar> forwarders = new Dictionary<LocalVar,LocalVar>();
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<ExceptionTableEntry> ar = new List<ExceptionTableEntry>(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<ExceptionTableEntry> stack = new Stack<ExceptionTableEntry>();
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<ExceptionTableEntry> list = new List<ExceptionTableEntry>();
// 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();
}
}