[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: Question re. compilation of exceptions/monitors in Jimple (fwd)



Please ignore my previous post. I think I have a mistake in the analysis. I will post an update later.
 
Regards,
Stephen
-----Original Message-----
From: owner-soot-list@sable.mcgill.ca [mailto:owner-soot-list@sable.mcgill.ca]On Behalf Of Stephen Cheng
Sent: 30 April 2002 16:21
To: Jean-Pierre.Talpin@irisa.fr; Bruno.Ledez@irisa.fr
Cc: Soot
Subject: RE: Question re. compilation of exceptions/monitors in Jimple (fwd)

Hello Jean-Pierre,
 
I had a second look in the problem and I found that the situation has nothing to do with RTJ. I believe there is a bug with SiteInliner/SynchronizeeManager classes that will potentially cause problems to all applications with synchronized method. Given the fact some implementation are JDK library methods are synchronised, well, you can say all J2SE/J2ME apps are potentially compromised by this bug.
 
I have tried to reproduce the problem using JDK 1.3.1_01 (soot.Main --app -soot-classpath c:\java\jdk1.3.1_01\jre\lib\rt.jar;.\ -O -W MEE):, and I managed to reproduce the bug. The resultant jimple code looks almost identical to your output.
 
I have added some debug printouts in Soot and it shows two instance of method inlining:
C:\sandbox\soottest\classes>java soot.Main --app --soot-classpath c:\java\jdk1.3
.1_01\jre\lib\rt.jar;.\ -O -W -J MEE
Soot started on Tue Apr 30 15:39:47 BST 2002
 
Adding inline candiadates in StaticInliner
target: <MEE: java.lang.Object newInstance(java.lang.Class)>
container: <MEE: void essai()>
Statement: $r4 = staticinvoke <MEE: java.lang.Object newInstance(java.lang.Class
)>($r3)
 
Adding inline candiadate in StaticInliner
target: <MEE: void essai()>
container: <MEE: void main(java.lang.String[])>
Statement: staticinvoke <MEE: void essai()>()
Transforming MEE...
Soot finished on Tue Apr 30 15:39:51 BST 2002
Soot has run for 0 min. 4 sec.
 
In both cases StaticInliner is inlining a static invokation with a static method in the same class file (MEE). (Aside: IMO replacing static calls with inline code does not produce much gain in speed and likely to increase size, and therefore should not be incldued as a standard optimisation techniques)
 
The bug surfaces  when SiteInliner attempts replace the static invokation of <MEE: newInstance() inside MEE: essai()>.
The method <MEE: java.lang.Object newInstance(java.lang.Class)> is a synchronised method. It can potentially throw an exception. When an exception is thrown inside  newInstance() the control is passed back to the caller, but at the same time the VM would automatically unlock the monitor (since it is a synchronised method).
 
This behaviour is not reproduced in the inlined code. The SynchronizerManager does not correctly insert monitoexit code prior to the athrow instructions. See the following commented Jimple fragments for details:
 
<For your reference the original newInstance()>
    public static synchronized java.lang.Object newInstance(java.lang.Class ) throws java.lang.InstantiationException, java.lang.IllegalAccessException
    {
        java.lang.Class r0;
        java.lang.Object r2;
        java.lang.Throwable $r3;
 
        r0 := @parameter0: java.lang.Class;
 
     label0:
        r2 = virtualinvoke r0.<java.lang.Class: java.lang.Object newInstance()>();
        goto label2;
 
     label1:
        $r3 := @caughtexception;
        throw $r3;
 
     label2:
        return r2;
 
        catch java.lang.Throwable from label0 to label1 with label1;
    }
 
<the method where inlining takes place>
    public static void essai()
    {
        java.io.PrintStream $r0, $r5, $r7;
        java.lang.String r1;
        java.lang.Class $r3, $r8;
        java.lang.Exception $r6;
        java.lang.Throwable r9, $r13;
        java.lang.Object r12;
 
        $r0 = <java.lang.System: java.io.PrintStream out>;
        virtualinvoke $r0.<java.io.PrintStream: void println(java.lang.String)>("Hello");
 
// The non-optimised version look like this
//     label0:
//        $r3 = staticinvoke <java.lang.Class: java.lang.Class forName(java.lang.String)>("java.lang.Integer");
//        $r4 = staticinvoke <MEE: java.lang.Object newInstance(java.lang.Class)>($r3);
//        r1 = (java.lang.String) $r4;
//        $r5 = <java.lang.System: java.io.PrintStream out>;
//        virtualinvoke $r5.<java.io.PrintStream: void println(java.lang.String)>(r1);
 
     label0:
        $r3 = staticinvoke <java.lang.Class: java.lang.Class forName(java.lang.String)>("java.lang.Integer");
// Soot replaced staticinvoke <MEE: java.lang.Object newInstance(java.lang.Class)>($r3) with this bunch of code
 
        $r8 = <MEE: java.lang.Class class$MEE>;
        if $r8 != null goto label1;
 
        $r8 = staticinvoke <MEE: java.lang.Class class$(java.lang.String)>("MEE");
        <MEE: java.lang.Class class$MEE> = $r8;
 
// <Begin copy from newInstance()>
     label1:
// SynchronizerManager put this in to replace the automatic VM locking
        entermonitor $r8;
 
     label2:
        r12 = virtualinvoke $r3.<java.lang.Class: java.lang.Object newInstance()>();
        goto label4;
 
     label3:
        $r13 := @caughtexception;
// Synchronizer should put in an exitmonitor function here but didn't
        throw $r13;
 
     label4:
// SynchronizerManager put this in to replace the automatic VM unlocking
        exitmonitor $r8;
        goto label6;
//<Finish copy from newInstance()>
 
     label5:
        r9 := @caughtexception;
        exitmonitor $r8;
        throw r9;
 
     label6:
        r1 = (java.lang.String) r12;
        $r5 = <java.lang.System: java.io.PrintStream out>;
        virtualinvoke $r5.<java.io.PrintStream: void println(java.lang.String)>(r1);
 
     label7:
        goto label9;
 
     label8:
        $r6 := @caughtexception;
 
     label9:
        $r7 = <java.lang.System: java.io.PrintStream out>;
        virtualinvoke $r7.<java.io.PrintStream: void println(java.lang.String)>("Bye");
        return;
 
        catch java.lang.Throwable from label2 to label3 with label3;
        catch java.lang.Throwable from label2 to label4 with label5;
        catch java.lang.Exception from label0 to label7 with label8;
    }
 
I don't belive this bug is easy to fix. We cannot simply add a monitorexit in front of every athrow when inlining a synchronized method. Why? because some of the athrows can be caught again in the same method if there is a suitable exception block for it. Some heavy duty control flow analysis would be required to fix this problem properly.
 
Regards,
Stephen