зеркало из https://github.com/mono/ikvm-fork.git
Implemented codegen improvement to use CLR fault handlers for Java catch all handlers, whenever possible.
This commit is contained in:
Родитель
3ca0627114
Коммит
0ed13314f0
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче