Merge
authorvlivanov
Mon, 26 Aug 2013 21:48:19 -0700
changeset 19714 5afc245c36a7
parent 19711 95cc0162a92d (current diff)
parent 19713 8ef23b417f55 (diff)
child 19716 2f8937c12d14
Merge
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java	Mon Aug 26 16:12:20 2013 +0200
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java	Mon Aug 26 21:48:19 2013 -0700
@@ -106,10 +106,12 @@
                         " (" + getMethod().getBytes() + " bytes) " + getReason());
             }
         }
+        stream.printf(" (end time: %6.4f", getTimeStamp());
         if (getEndNodes() > 0) {
-            stream.printf(" (end time: %6.4f nodes: %d live: %d)", getTimeStamp(), getEndNodes(), getEndLiveNodes());
+            stream.printf(" nodes: %d live: %d", getEndNodes(), getEndLiveNodes());
         }
-        stream.println("");
+        stream.println(")");
+
         if (getReceiver() != null) {
             emit(stream, indent + 4);
             //                 stream.println("type profile " + method.holder + " -> " + receiver + " (" +
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java	Mon Aug 26 16:12:20 2013 +0200
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java	Mon Aug 26 21:48:19 2013 -0700
@@ -207,7 +207,12 @@
     }
 
     String search(Attributes attr, String name) {
-        return search(attr, name, null);
+        String result = attr.getValue(name);
+        if (result != null) {
+            return result;
+        } else {
+            throw new InternalError("can't find " + name);
+        }
     }
 
     String search(Attributes attr, String name, String defaultValue) {
@@ -215,13 +220,7 @@
         if (result != null) {
             return result;
         }
-        if (defaultValue != null) {
-            return defaultValue;
-        }
-        for (int i = 0; i < attr.getLength(); i++) {
-            System.out.println(attr.getQName(i) + " " + attr.getValue(attr.getQName(i)));
-        }
-        throw new InternalError("can't find " + name);
+        return defaultValue;
     }
     int indent = 0;
 
@@ -268,17 +267,18 @@
             Phase p = new Phase(search(atts, "name"),
                     Double.parseDouble(search(atts, "stamp")),
                     Integer.parseInt(search(atts, "nodes", "0")),
-                    Integer.parseInt(search(atts, "live")));
+                    Integer.parseInt(search(atts, "live", "0")));
             phaseStack.push(p);
         } else if (qname.equals("phase_done")) {
             Phase p = phaseStack.pop();
-            if (! p.getId().equals(search(atts, "name"))) {
+            String phaseName = search(atts, "name", null);
+            if (phaseName != null && !p.getId().equals(phaseName)) {
                 System.out.println("phase: " + p.getId());
                 throw new InternalError("phase name mismatch");
             }
             p.setEnd(Double.parseDouble(search(atts, "stamp")));
             p.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
-            p.setEndLiveNodes(Integer.parseInt(search(atts, "live")));
+            p.setEndLiveNodes(Integer.parseInt(search(atts, "live", "0")));
             compile.getPhases().add(p);
         } else if (qname.equals("task")) {
             compile = new Compilation(Integer.parseInt(search(atts, "compile_id", "-1")));
@@ -413,8 +413,8 @@
             }
         } else if (qname.equals("parse_done")) {
             CallSite call = scopes.pop();
-            call.setEndNodes(Integer.parseInt(search(atts, "nodes", "1")));
-            call.setEndLiveNodes(Integer.parseInt(search(atts, "live", "1")));
+            call.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
+            call.setEndLiveNodes(Integer.parseInt(search(atts, "live", "0")));
             call.setTimeStamp(Double.parseDouble(search(atts, "stamp")));
             scopes.push(call);
         }
--- a/hotspot/src/share/vm/c1/c1_Compilation.cpp	Mon Aug 26 16:12:20 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp	Mon Aug 26 21:48:19 2013 -0700
@@ -74,16 +74,19 @@
  private:
   JavaThread* _thread;
   CompileLog* _log;
+  TimerName _timer;
 
  public:
   PhaseTraceTime(TimerName timer)
-  : TraceTime("", &timers[timer], CITime || CITimeEach, Verbose), _log(NULL) {
+  : TraceTime("", &timers[timer], CITime || CITimeEach, Verbose),
+    _log(NULL), _timer(timer)
+  {
     if (Compilation::current() != NULL) {
       _log = Compilation::current()->log();
     }
 
     if (_log != NULL) {
-      _log->begin_head("phase name='%s'", timer_name[timer]);
+      _log->begin_head("phase name='%s'", timer_name[_timer]);
       _log->stamp();
       _log->end_head();
     }
@@ -91,7 +94,7 @@
 
   ~PhaseTraceTime() {
     if (_log != NULL)
-      _log->done("phase");
+      _log->done("phase name='%s'", timer_name[_timer]);
   }
 };
 
--- a/hotspot/src/share/vm/runtime/thread.cpp	Mon Aug 26 16:12:20 2013 +0200
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Mon Aug 26 21:48:19 2013 -0700
@@ -3636,6 +3636,16 @@
   CompileBroker::compilation_init();
 #endif
 
+  if (EnableInvokeDynamic) {
+    // Pre-initialize some JSR292 core classes to avoid deadlock during class loading.
+    // It is done after compilers are initialized, because otherwise compilations of
+    // signature polymorphic MH intrinsics can be missed
+    // (see SystemDictionary::find_method_handle_intrinsic).
+    initialize_class(vmSymbols::java_lang_invoke_MethodHandle(), CHECK_0);
+    initialize_class(vmSymbols::java_lang_invoke_MemberName(), CHECK_0);
+    initialize_class(vmSymbols::java_lang_invoke_MethodHandleNatives(), CHECK_0);
+  }
+
 #if INCLUDE_MANAGEMENT
   Management::initialize(THREAD);
 #endif // INCLUDE_MANAGEMENT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/ConcurrentClassLoadingTest.java	Mon Aug 26 21:48:19 2013 -0700
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8022595
+ * @summary JSR292: deadlock during class loading of MethodHandles, MethodHandleImpl & MethodHandleNatives
+ *
+ * @run main/othervm ConcurrentClassLoadingTest
+ */
+import java.util.*;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+public class ConcurrentClassLoadingTest {
+    int numThreads = 0;
+    long seed = 0;
+    CyclicBarrier l;
+    Random rand;
+
+    public static void main(String[] args) throws Throwable {
+        ConcurrentClassLoadingTest test = new ConcurrentClassLoadingTest();
+        test.parseArgs(args);
+        test.run();
+    }
+
+    void parseArgs(String[] args) {
+        int i = 0;
+        while (i < args.length) {
+            String flag = args[i];
+            switch(flag) {
+                case "-seed":
+                    seed = Long.parseLong(args[++i]);
+                    break;
+                case "-numThreads":
+                    numThreads = Integer.parseInt(args[++i]);
+                    break;
+                default:
+                    throw new Error("Unknown flag: " + flag);
+            }
+            ++i;
+        }
+    }
+
+    void init() {
+        if (numThreads == 0) {
+            numThreads = Runtime.getRuntime().availableProcessors();
+        }
+
+        if (seed == 0) {
+            seed = (new Random()).nextLong();
+        }
+        rand = new Random(seed);
+
+        l = new CyclicBarrier(numThreads + 1);
+
+        System.out.printf("Threads: %d\n", numThreads);
+        System.out.printf("Seed: %d\n", seed);
+    }
+
+    final List<Loader> loaders = new ArrayList<>();
+
+    void prepare() {
+        List<String> c = new ArrayList<>(Arrays.asList(classNames));
+
+        // Split classes between loading threads
+        int count = (classNames.length / numThreads) + 1;
+        for (int t = 0; t < numThreads; t++) {
+            List<String> sel = new ArrayList<>();
+
+            System.out.printf("Thread #%d:\n", t);
+            for (int i = 0; i < count; i++) {
+                if (c.size() == 0) break;
+
+                int k = rand.nextInt(c.size());
+                String elem = c.remove(k);
+                sel.add(elem);
+                System.out.printf("\t%s\n", elem);
+            }
+            loaders.add(new Loader(sel));
+        }
+
+        // Print diagnostic info when the test hangs
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() {
+                boolean alive = false;
+                for (Loader l : loaders) {
+                    if (!l.isAlive())  continue;
+
+                    if (!alive) {
+                        System.out.println("Some threads are still alive:");
+                        alive = true;
+                    }
+
+                    System.out.println(l.getName());
+                    for (StackTraceElement elem : l.getStackTrace()) {
+                        System.out.println("\t"+elem.toString());
+                    }
+                }
+            }
+        });
+    }
+
+    public void run() throws Throwable {
+        init();
+        prepare();
+
+        for (Loader loader : loaders) {
+            loader.start();
+        }
+
+        l.await();
+
+        for (Loader loader : loaders) {
+            loader.join();
+        }
+    }
+
+    class Loader extends Thread {
+        List<String> classes;
+
+        public Loader(List<String> classes) {
+            this.classes = classes;
+            setDaemon(true);
+        }
+
+        @Override
+        public void run() {
+            try {
+                l.await();
+
+                for (String name : classes) {
+                    Class.forName(name).getName();
+                }
+            } catch (ClassNotFoundException | BrokenBarrierException | InterruptedException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    final static String[] classNames = {
+            "java.lang.invoke.AbstractValidatingLambdaMetafactory",
+            "java.lang.invoke.BoundMethodHandle",
+            "java.lang.invoke.CallSite",
+            "java.lang.invoke.ConstantCallSite",
+            "java.lang.invoke.DirectMethodHandle",
+            "java.lang.invoke.InnerClassLambdaMetafactory",
+            "java.lang.invoke.InvokeDynamic",
+            "java.lang.invoke.InvokeGeneric",
+            "java.lang.invoke.InvokerBytecodeGenerator",
+            "java.lang.invoke.Invokers",
+            "java.lang.invoke.LambdaConversionException",
+            "java.lang.invoke.LambdaForm",
+            "java.lang.invoke.LambdaMetafactory",
+            "java.lang.invoke.MagicLambdaImpl",
+            "java.lang.invoke.MemberName",
+            "java.lang.invoke.MethodHandle",
+            "java.lang.invoke.MethodHandleImpl",
+            "java.lang.invoke.MethodHandleInfo",
+            "java.lang.invoke.MethodHandleNatives",
+            "java.lang.invoke.MethodHandleProxies",
+            "java.lang.invoke.MethodHandles",
+            "java.lang.invoke.MethodHandleStatics",
+            "java.lang.invoke.MethodType",
+            "java.lang.invoke.MethodTypeForm",
+            "java.lang.invoke.MutableCallSite",
+            "java.lang.invoke.SerializedLambda",
+            "java.lang.invoke.SimpleMethodHandle",
+            "java.lang.invoke.SwitchPoint",
+            "java.lang.invoke.TypeConvertingMethodAdapter",
+            "java.lang.invoke.VolatileCallSite",
+            "java.lang.invoke.WrongMethodTypeException"
+    };
+}