[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: remove-unreachable-traps
On Wed, Aug 25, 2004 at 01:15:22AM -0600, John Jorgensen wrote:
> I originally added the remove-unreachable-traps option just after
> I discovered that code generated from an ExceptionalUnitGraph
> could be unverifiable (as a consequence of the bytecode verifier
> assuming that all instructions in the scope of a handler have the
> potential to throw an exception caught by the handler). My notes
> from this period say that I had observed
> UnreachableCodeEliminator removing an unreachable handler, after
> which PatchingChain redirected the Trap's handlerUnit to the last
> unit preceding the handler, resulting in unverifiable code
> because the resulting "handler" didn't pop any exception off the
> stack. This story doesn't make any sense to me now, though,
> since the Trap corresponding to the eliminated handler should
> have been eliminated as well; probably my notes record a mistake I
> made because I still didn't understand bytecode verification well
> enough to recognize the real circumstances that led to
> unverifiable code.
>
> olhotak> If unreachable traps are left in, it is not possible to produce
> olhotak> bytecode from baf: these traps have no entry points,
> olhotak> so the baf code assumes their initial stack height
> olhotak> is zero, yet the first thing they do is pop the
> olhotak> exception. Does anyone remember why they are not
> olhotak> removed by default?
>
> Is this a "Negative stack height has been attained" exception
> being thrown by soot.baf.JasminClass? I dealt with this once
> before, with revision 1135, (originally made in the
> soot-2-exceptional branch). I changed the mechanism that set the
> initial stack heights so that unreachable handlers would have
> have an initial height of 1 instead of 0, but it looks like I put
> my handler test inside an existing loop which ignored Traps which
> trap zero units. Oops. Under the assumption that your test case
> involves a handler that is unreachable because the try block is
> empty, and not because the ExceptionalUnitGraph has deemed the
> handler to be unreachable, then it is my bungled fix to
> JasminClass, and not remove-unreachable-traps, that is the
> probable cause of your problem. I'll take another look at it
> tomorrow evening.
Hi John...
I'm not sure whether the try block itself becomes empty, but the trap
gets removed from the list of traps, but the code in the catch block
doesn't.
I've managed to reproduce the bug without abc, in a Jimple file. If you
run Soot with -O on the attached NewSwitch2.jimple, you will see the
Negative stack height message. The reason is that the optimized Jimple
contains the following piece of code:
label2:
r3 := @caughtexception;
r6 = staticinvoke <FFDC2: FFDC2 aspectOf()>();
virtualinvoke r6.<FFDC2: void afterThrowing$0(java.lang.Throwable)>(r3);
throw r3;
r2 := @caughtexception;
r5 = staticinvoke <FFDC2: FFDC2 aspectOf()>();
virtualinvoke r5.<FFDC2: void afterThrowing$0(java.lang.Throwable)>(r2);
throw r2;
Note that the r2 := @caughtexception has no label and is not the target
of any trap (the trap that it was the target of has been removed).
Also interesting is that jop runs the UnreachableCodeEliminator twice.
If you change it to run it a third time, it gets rid of the unreachable
handler, and everything works. But I don't think increasing the number
of times it runs each time is a reliable solution.
Ondrej
public class NewSwitch2 extends java.lang.Object
{
static void <clinit>()
{
return;
}
protected void <init>()
{
NewSwitch2 r0, r3;
java.lang.Throwable r1, r4, exception;
FFDC2 r2, r5, theAspect;
int i0;
r0 := @this: NewSwitch2;
r3 = r0;
i0 = 3;
specialinvoke r3.<java.lang.Object: void <init>()>();
nop;
label0:
nop;
nop;
label1:
tableswitch(i0)
{
case 3: goto label2;
default: goto label3;
};
label2:
goto label3;
label3:
nop;
goto label5;
label4:
r4 := @caughtexception;
r5 = staticinvoke <FFDC2: FFDC2 aspectOf()>();
virtualinvoke r5.<FFDC2: void afterThrowing$0(java.lang.Throwable)>(r4);
throw r4;
label5:
nop;
nop;
goto label6;
label6:
nop;
label7:
nop;
goto label9;
label8:
r1 := @caughtexception;
r2 = staticinvoke <FFDC2: FFDC2 aspectOf()>();
virtualinvoke r2.<FFDC2: void afterThrowing$0(java.lang.Throwable)>(r1);
throw r1;
label9:
nop;
nop;
goto label11;
label10:
exception := @caughtexception;
theAspect = staticinvoke <FFDC2: FFDC2 aspectOf()>();
virtualinvoke theAspect.<FFDC2: void afterThrowing$0(java.lang.Throwable)>(exception);
throw exception;
label11:
nop;
nop;
return;
catch java.lang.Throwable from label7 to label8 with label8;
catch java.lang.Throwable from label1 to label4 with label4;
catch java.lang.Throwable from label0 to label10 with label10;
}
protected void <init>(int)
{
NewSwitch2 this;
int p;
java.lang.Throwable exception, exception1;
FFDC2 theAspect, theAspect2;
this := @this: NewSwitch2;
p := @parameter0: int;
specialinvoke this.<java.lang.Object: void <init>()>();
nop;
label0:
nop;
nop;
label1:
tableswitch(p)
{
case 3: goto label2;
default: goto label3;
};
label2:
goto label3;
label3:
nop;
goto label5;
label4:
exception := @caughtexception;
theAspect = staticinvoke <FFDC2: FFDC2 aspectOf()>();
virtualinvoke theAspect.<FFDC2: void afterThrowing$0(java.lang.Throwable)>(exception);
throw exception;
label5:
nop;
nop;
goto label7;
label6:
exception1 := @caughtexception;
theAspect2 = staticinvoke <FFDC2: FFDC2 aspectOf()>();
virtualinvoke theAspect2.<FFDC2: void afterThrowing$0(java.lang.Throwable)>(exception1);
throw exception1;
label7:
nop;
nop;
return;
catch java.lang.Throwable from label1 to label4 with label4;
catch java.lang.Throwable from label0 to label6 with label6;
}
}
public class FFDC2 extends java.lang.Object
{
public static final FFDC2 abc$perSingletonInstance;
private static java.lang.Throwable abc$initFailureCause;
private static void abc$postClinit()
{
FFDC2 theAspect;
theAspect = new FFDC2;
specialinvoke theAspect.<FFDC2: void <init>()>();
<FFDC2: FFDC2 abc$perSingletonInstance> = theAspect;
return;
}
public void <init>()
{
FFDC2 this;
this := @this: FFDC2;
specialinvoke this.<java.lang.Object: void <init>()>();
nop;
return;
}
static void <clinit>()
{
java.lang.Throwable catchLocal;
label0:
staticinvoke <FFDC2: void abc$postClinit()>();
label1:
goto label3;
label2:
catchLocal := @caughtexception;
<FFDC2: java.lang.Throwable abc$initFailureCause> = catchLocal;
label3:
nop;
return;
catch java.lang.Throwable from label0 to label1 with label2;
}
public final void afterThrowing$0(java.lang.Throwable)
{
FFDC2 this;
java.lang.Throwable t;
this := @this: FFDC2;
t := @parameter0: java.lang.Throwable;
return;
}
public static FFDC2 aspectOf() throws org.aspectj.lang.NoAspectBoundException
{
FFDC2 theAspect;
org.aspectj.lang.NoAspectBoundException nabException;
java.lang.Throwable failureCause;
theAspect = <FFDC2: FFDC2 abc$perSingletonInstance>;
if theAspect == null goto label0;
return theAspect;
label0:
nabException = new org.aspectj.lang.NoAspectBoundException;
failureCause = <FFDC2: java.lang.Throwable abc$initFailureCause>;
specialinvoke nabException.<org.aspectj.lang.NoAspectBoundException: void <init>(java.lang.String,java.lang.Throwable)>("FFDC2", failureCause);
throw nabException;
}
public static boolean hasAspect()
{
FFDC2 theAspect;
theAspect = <FFDC2: FFDC2 abc$perSingletonInstance>;
if theAspect == null goto label0;
return 1;
label0:
return 0;
}
}