changeset 14027:aba77882e314

be more careful with clinit of CompilationTask
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Wed, 26 Feb 2014 11:10:27 -0800
parents 57a2d00ef771
children fad977c86a88
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java
diffstat 2 files changed, 27 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Feb 26 15:56:11 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Feb 26 11:10:27 2014 -0800
@@ -30,6 +30,7 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.phases.common.InliningUtil.*;
 
+import java.io.*;
 import java.lang.reflect.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
@@ -52,9 +53,14 @@
 
 public class CompilationTask implements Runnable, Comparable {
 
+    // Keep static finals in a group with withinEnqueue as the last one. CompilationTask can be
+    // called from within it's own clinit so it needs to be careful about accessing state. Once
+    // withinEnqueue is non-null we assume that CompilationTask is fully initialized.
+    private static final AtomicLong uniqueTaskIds = new AtomicLong();
+
     private static final DebugMetric BAILOUTS = Debug.metric("Bailouts");
 
-    public static final ThreadLocal<Boolean> withinEnqueue = new ThreadLocal<Boolean>() {
+    private static final ThreadLocal<Boolean> withinEnqueue = new ThreadLocal<Boolean>() {
 
         @Override
         protected Boolean initialValue() {
@@ -62,6 +68,22 @@
         }
     };
 
+    public static final boolean isWithinEnqueue() {
+        // It's possible this can be called before the <clinit> has completed so check for null
+        return withinEnqueue == null || withinEnqueue.get();
+    }
+
+    public static class BeginEnqueue implements Closeable {
+        public BeginEnqueue() {
+            assert !withinEnqueue.get();
+            withinEnqueue.set(Boolean.TRUE);
+        }
+
+        public void close() {
+            withinEnqueue.set(Boolean.FALSE);
+        }
+    }
+
     private enum CompilationStatus {
         Queued, Running, Finished
     }
@@ -74,8 +96,6 @@
 
     private StructuredGraph graph;
 
-    private static final AtomicLong uniqueTaskIds = new AtomicLong();
-
     /**
      * A long representing the sequence number of this task. Used for sorting the compile queue.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Feb 26 15:56:11 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Feb 26 11:10:27 2014 -0800
@@ -248,14 +248,10 @@
             // Compile until the queue is empty.
             int z = 0;
             while (true) {
-                try {
-                    assert !CompilationTask.withinEnqueue.get();
-                    CompilationTask.withinEnqueue.set(Boolean.TRUE);
+                try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) {
                     if (compileQueue.getCompletedTaskCount() >= Math.max(3, compileQueue.getTaskCount())) {
                         break;
                     }
-                } finally {
-                    CompilationTask.withinEnqueue.set(Boolean.FALSE);
                 }
 
                 Thread.sleep(100);
@@ -325,9 +321,7 @@
     }
 
     public void shutdownCompiler() throws Exception {
-        try {
-            assert !CompilationTask.withinEnqueue.get();
-            CompilationTask.withinEnqueue.set(Boolean.TRUE);
+        try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) {
             // We have to use a privileged action here because shutting down the compiler might be
             // called from user code which very likely contains unprivileged frames.
             AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@@ -336,8 +330,6 @@
                     return null;
                 }
             });
-        } finally {
-            CompilationTask.withinEnqueue.set(Boolean.FALSE);
         }
 
         printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false);
@@ -537,7 +529,7 @@
             return;
         }
 
-        if (CompilationTask.withinEnqueue.get()) {
+        if (CompilationTask.isWithinEnqueue()) {
             // This is required to avoid deadlocking a compiler thread. The issue is that a
             // java.util.concurrent.BlockingQueue is used to implement the compilation worker
             // queues. If a compiler thread triggers a compilation, then it may be blocked trying
@@ -547,8 +539,7 @@
 
         // Don't allow blocking compiles from CompilerThreads
         boolean block = blocking && !(Thread.currentThread() instanceof CompilerThread);
-        CompilationTask.withinEnqueue.set(Boolean.TRUE);
-        try {
+        try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) {
             if (method.tryToQueueForCompilation()) {
                 assert method.isQueuedForCompilation();
 
@@ -565,8 +556,6 @@
                     // The compile queue was already shut down.
                 }
             }
-        } finally {
-            CompilationTask.withinEnqueue.set(Boolean.FALSE);
         }
     }