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

RE: Synchronisation and Optimisation



> With regards to flushing values of an object, I believe this is the
> responsiblity of the VM's implementation of the monitorenter & monitorexit
> bytecodes. The actual implementation (assuming it is correct)
> should have no
> relevance to effects at the Jimple level.

After a bit of experimentation and some further thinking, I agree with
Rhodes that it is not the responsibility of jimplication process to "flush".
It is in fact the compiler's (or optimiser's) responsibility to ensure that
all field caches are "flushed" whenever there is a monitorenter/monitorexit.
I.e. next time the field is accessed again the compiler must generate code
to get the field, rather than using a cached (local variable) copy of the
field.

I have been investigating the CSE implementation. CSE eliminates repeated
access to fields. It seems to pay no heed to monitorenter/monitorexit. The
following example seems to indicate CSE is generating incorrect code in the
presence of monitorenter/monitorexit. I have marked the possibly incorrect
changes made by CSE after label0.

Original java:
public class Ex3Sync {

    int sharedInt = 10;

	void testSync3() {
        int x = sharedInt + 3;

        synchronized (this) {
            sharedInt = sharedInt + sharedInt + 1;

            System.out.println( "sharedInt =" + sharedInt);
            System.out.println( "x =" + x);
        }

	}
}

This is the Jimple code for the Non-optimised class file:
soot.Main -j Ex3: (abstract)
    void testSync3()
    {
        Ex3Sync r0, r1;
        int i0, $i1, $i2, $i3, $i4, $i5, $i6;
        java.io.PrintStream $r2, $r7;
        java.lang.String $r3, $r4, $r5, $r6, $r8, $r9, $r10, $r11;
        java.lang.Throwable $r12;

        r0 := @this;
        $i1 = r0.sharedInt;
        i0 = $i1 + 3;
        r1 = r0;
        entermonitor r1;

     label0:
        $i2 = r0.sharedInt;
        $i3 = r0.sharedInt;
        $i4 = $i2 + $i3;
        $i5 = $i4 + 1;
        r0.sharedInt = $i5;
        $r2 = java.lang.System.out;
        $r3 = "sharedInt =";
        $i6 = r0.sharedInt;
        $r4 = java.lang.String.valueOf($i6);
        $r5 = java.lang.String.valueOf($r4);
        $r6 = $r3.concat($r5);
        $r2.println($r6);
        $r7 = java.lang.System.out;
        $r8 = "x =";
        $r9 = java.lang.String.valueOf(i0);
        $r10 = java.lang.String.valueOf($r9);
        $r11 = $r8.concat($r10);
        $r7.println($r11);

     label1:
        exitmonitor r1;
        goto label3;

     label2:
        $r12 := @caughtexception;
        exitmonitor r1;
        throw $r12;

     label3:
        return;

        catch java.lang.Throwable from label0 to label1 with label2;
    }


This is jimple code for the optimised class file:

soot.Main -O -j Ex3Sync (Abstract)

    void testSync3()
    {
        Ex3Sync r0;
        int i0, i1, $i2, $i3, $i4;
        java.io.PrintStream $r1, $r6;
        java.lang.String $r2, $r3, $r4, $r5, $r7, $r8, $r9, $r10;
        java.lang.Throwable $r11;

        r0 := @this;
        i0 = r0.sharedInt;
        i1 = i0 + 3;
        entermonitor r0;

     label0:
>> Note here
>>        $i2 = i0 + i0;
>>        $i3 = $i2 + 1;
        r0.sharedInt = $i3;
        $r1 = java.lang.System.out;
        $r2 = "sharedInt =";
        $i4 = r0.sharedInt;
        $r3 = java.lang.String.valueOf($i4);
        $r4 = java.lang.String.valueOf($r3);
        $r5 = $r2.concat($r4);
        $r1.println($r5);
        $r6 = java.lang.System.out;
        $r7 = "x =";
        $r8 = java.lang.String.valueOf(i1);
        $r9 = java.lang.String.valueOf($r8);
        $r10 = $r7.concat($r9);
        $r6.println($r10);

     label1:
        exitmonitor r0;
        goto label3;

     label2:
        $r11 := @caughtexception;
        exitmonitor r0;
        throw $r11;

     label3:
        return;

        catch java.lang.Throwable from label0 to label1 with label2;
    }

Note:
CSE has changed the code from:

        ...
        entermonitor r1;

     label0:
        $i2 = r0.sharedInt;
        $i3 = r0.sharedInt;
        $i4 = $i2 + $i3;
        $i5 = $i4 + 1;
        r0.sharedInt = $i5;
        ...

to:
        ...
        entermonitor r0;

     label0:
>> Note here
>>        $i2 = i0 + i0;
>>        $i3 = $i2 + 1;
        r0.sharedInt = $i3;
        ...

In the optimised version, sharedInt = sharedInt + sharedInt + 1 would never
use the value updated by another thread, in violation of the VM
specification.

Regards,
Stephen