| // Copyright (c) 2018 the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| package uninitializedfinal; | |
| // Test that leaks an instance before its final field has been initialized to a thread that | |
| // reads that field. This tests that redundant field load elimination does not eliminate | |
| // field reads (even of final fields) that cross a monitor operation. | |
| public class UninitializedFinalFieldLeak { | |
| public static class PollingThread extends Thread { | |
| public int result = 0; | |
| UninitializedFinalFieldLeak f; | |
| PollingThread(UninitializedFinalFieldLeak f) { | |
| this.f = f; | |
| } | |
| // Read the field a number of times. Then lock on the object to await field initialization. | |
| public void run() { | |
| result += f.i; | |
| result += f.i; | |
| result += f.i; | |
| f.threadReadsDone = true; | |
| synchronized (f) { | |
| result += f.i; | |
| } | |
| // The right result is 42. Reading the uninitialized 0 three times and then | |
| // reading the initialized value. It is safe to remove the two redundant loads | |
| // before the monitor operation. | |
| System.out.println(result); | |
| } | |
| } | |
| public final int i; | |
| public volatile boolean threadReadsDone = false; | |
| public UninitializedFinalFieldLeak() throws InterruptedException { | |
| // Leak the object to a thread and start the thread with the lock on the object taken. | |
| // Then allow the other thread to run and read the uninitialized field. | |
| // Finally, initialize the field and release the lock. | |
| PollingThread t = new PollingThread(this); | |
| synchronized (this) { | |
| t.start(); | |
| while (!threadReadsDone) { | |
| Thread.yield(); | |
| } | |
| i = 42; | |
| } | |
| t.join(); | |
| } | |
| public static void main(String[] args) throws InterruptedException { | |
| new UninitializedFinalFieldLeak(); | |
| } | |
| } |