|  | // 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(); | 
|  | } | 
|  | } |