[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Synchronisation and Optimisation
Would it correct the problem if we made CSE kill all information about
fields (and arrays and globals) when it encounters a monitorexit
statement? That is,
NaiveSideEffectTester: unitCanWriteTo( Unit u, Value v )
would return true if u was a monitorexit, and v was visible to other
threads?
Ondrej
On Fri, Apr 12, 2002 at 01:27:02PM +0100, Stephen Cheng wrote:
> > 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
>