From 1a3734cdfafb753a581e052c233f6a55d8073159 Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Tue, 27 May 2014 21:58:23 -0700 Subject: [PATCH 01/18] 8043896: Error reporting for insufficient shared region size is incorrect In SharedSpaceType, we have three enum types which are used in report_out_of_shared_space(SharedSpaceType type). In fact we supplied more than three messages and flags. This leads the warning always gives wrong message with the first not used. Reviewed-by: iklam, coleenp --- hotspot/src/share/vm/utilities/debug.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 604018f8dd9..ff3bc5d4c81 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -263,13 +263,11 @@ void report_untested(const char* file, int line, const char* message) { void report_out_of_shared_space(SharedSpaceType shared_space) { static const char* name[] = { - "native memory for metadata", "shared read only space", "shared read write space", "shared miscellaneous data space" }; static const char* flag[] = { - "Metaspace", "SharedReadOnlySize", "SharedReadWriteSize", "SharedMiscDataSize" From 39a66950594e30e74003f1e7c43c08a18c16ee61 Mon Sep 17 00:00:00 2001 From: Poonam Bajaj Date: Wed, 28 May 2014 06:26:05 -0700 Subject: [PATCH 02/18] 8043086: Hotspot is expected to report OOM which is occurred String.intern(), but crashes in JDK8u5 In case of allocation failure, restore the value of _chunk in Arena Reviewed-by: dholmes, dcubed --- hotspot/src/share/vm/memory/allocation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index 2a3f4135617..c0254d9123f 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -563,6 +563,7 @@ void* Arena::grow(size_t x, AllocFailType alloc_failmode) { _chunk = new (alloc_failmode, len) Chunk(len); if (_chunk == NULL) { + _chunk = k; // restore the previous value of _chunk return NULL; } if (k) k->set_next(_chunk); // Append new chunk to end of linked list From c291efb1dfddec04517441d707c4457a7dfc557a Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Wed, 28 May 2014 07:36:32 -0700 Subject: [PATCH 03/18] 6904403: assert(f == k->has_finalizer(),"inconsistent has_finalizer") with debug VM Don't assert if one of classes in hierarhy was redefined Reviewed-by: coleenp, sspitsyn --- .../share/vm/classfile/classFileParser.cpp | 10 +- hotspot/src/share/vm/oops/instanceKlass.cpp | 15 +++ hotspot/src/share/vm/oops/instanceKlass.hpp | 9 +- .../test/runtime/RedefineFinalizer/Agent.java | 94 +++++++++++++++++++ .../test/runtime/RedefineFinalizer/Main.java | 34 +++++++ .../runtime/RedefineFinalizer/Martyr.java | 33 +++++++ .../runtime/RedefineFinalizer/MartyrSon.java | 28 ++++++ .../runtime/RedefineFinalizer/manifest.mf | 5 + .../test/runtime/RedefineFinalizer/testme.sh | 49 ++++++++++ 9 files changed, 273 insertions(+), 4 deletions(-) create mode 100644 hotspot/test/runtime/RedefineFinalizer/Agent.java create mode 100644 hotspot/test/runtime/RedefineFinalizer/Main.java create mode 100644 hotspot/test/runtime/RedefineFinalizer/Martyr.java create mode 100644 hotspot/test/runtime/RedefineFinalizer/MartyrSon.java create mode 100644 hotspot/test/runtime/RedefineFinalizer/manifest.mf create mode 100644 hotspot/test/runtime/RedefineFinalizer/testme.sh diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 61d9875c283..608b43ae150 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -4359,9 +4359,15 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) { Method* m = k->lookup_method(vmSymbols::finalize_method_name(), vmSymbols::void_method_signature()); if (m != NULL && !m->is_empty_method()) { - f = true; + f = true; + } + + // Spec doesn't prevent agent from redefinition of empty finalizer. + // Despite the fact that it's generally bad idea and redefined finalizer + // will not work as expected we shouldn't abort vm in this case + if (!k->has_redefined_this_or_super()) { + assert(f == k->has_finalizer(), "inconsistent has_finalizer"); } - assert(f == k->has_finalizer(), "inconsistent has_finalizer"); #endif // Check if this klass supports the java.lang.Cloneable interface diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 34907dd55a5..bcf9dc0a097 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1501,6 +1501,21 @@ Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature, M return NULL; } +#ifdef ASSERT +// search through class hierarchy and return true if this class or +// one of the superclasses was redefined +bool InstanceKlass::has_redefined_this_or_super() const { + const InstanceKlass* klass = this; + while (klass != NULL) { + if (klass->has_been_redefined()) { + return true; + } + klass = InstanceKlass::cast(klass->super()); + } + return false; +} +#endif + // lookup a method in the default methods list then in all transitive interfaces // Do NOT return private or static methods Method* InstanceKlass::lookup_method_in_ordered_interfaces(Symbol* name, diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 9010b9171ac..57b06870290 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -754,6 +754,11 @@ class InstanceKlass: public Klass { bool implements_interface(Klass* k) const; bool is_same_or_direct_interface(Klass* k) const; +#ifdef ASSERT + // check whether this class or one of its superclasses was redefined + bool has_redefined_this_or_super() const; +#endif + // Access to the implementor of an interface. Klass* implementor() const { @@ -811,8 +816,8 @@ class InstanceKlass: public Klass { // Casting from Klass* static InstanceKlass* cast(Klass* k) { - assert(k->is_klass(), "must be"); - assert(k->oop_is_instance(), "cast to InstanceKlass"); + assert(k == NULL || k->is_klass(), "must be"); + assert(k == NULL || k->oop_is_instance(), "cast to InstanceKlass"); return (InstanceKlass*) k; } diff --git a/hotspot/test/runtime/RedefineFinalizer/Agent.java b/hotspot/test/runtime/RedefineFinalizer/Agent.java new file mode 100644 index 00000000000..92b274ab02c --- /dev/null +++ b/hotspot/test/runtime/RedefineFinalizer/Agent.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014, 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. + */ + +import java.lang.instrument.Instrumentation; +import java.lang.instrument.ClassDefinition; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +public class Agent implements Opcodes { + + private static byte[] makeNewMartyr() { + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + + cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "Martyr", null, "java/lang/Object", null); + cw.visitSource(null, null); + + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + Label lab0 = new Label(); + mv.visitLabel(lab0); + mv.visitLineNumber(1, lab0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + mv = cw.visitMethod(ACC_PUBLIC, "getName", "()Ljava/lang/String;", null, null); + mv.visitCode(); + Label lab0 = new Label(); + mv.visitLabel(lab0); + mv.visitLineNumber(6, lab0); + mv.visitLdcInsn("Redefinition done"); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + mv = cw.visitMethod(ACC_PROTECTED, "finalize", "()V", null, null); + mv.visitCode(); + Label lab0 = new Label(); + mv.visitLabel(lab0); + mv.visitLineNumber(8, lab0); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("Finalizer called"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + + cw.visitEnd(); + return cw.toByteArray(); + } + + + public static void premain(String args, Instrumentation inst) throws Exception { + agentmain(args, inst); + } + + public static void agentmain(String args, Instrumentation inst) throws Exception { + ClassDefinition martyrDef = + new ClassDefinition(Class.forName("Martyr"), makeNewMartyr()); + inst.redefineClasses(martyrDef); + } +} diff --git a/hotspot/test/runtime/RedefineFinalizer/Main.java b/hotspot/test/runtime/RedefineFinalizer/Main.java new file mode 100644 index 00000000000..77f9f926d75 --- /dev/null +++ b/hotspot/test/runtime/RedefineFinalizer/Main.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 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. + */ + +public class Main { + public static void main(String[] args) { + try { + MartyrSon m = new MartyrSon(); + System.out.println(m.getName()); + System.runFinalization(); + } catch (Throwable e) { + e.printStackTrace(); + } + } +} diff --git a/hotspot/test/runtime/RedefineFinalizer/Martyr.java b/hotspot/test/runtime/RedefineFinalizer/Martyr.java new file mode 100644 index 00000000000..95f8ff2e056 --- /dev/null +++ b/hotspot/test/runtime/RedefineFinalizer/Martyr.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 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. + */ + +public class Martyr { + public String getName() { + return "Redefinition NOT done"; + } + + protected void finalize() { + // should be empty + } + +} diff --git a/hotspot/test/runtime/RedefineFinalizer/MartyrSon.java b/hotspot/test/runtime/RedefineFinalizer/MartyrSon.java new file mode 100644 index 00000000000..22fd4e3e275 --- /dev/null +++ b/hotspot/test/runtime/RedefineFinalizer/MartyrSon.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014, 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. + */ + +class MartyrSon extends Martyr { + public String getName() { + return super.getName(); + } +} diff --git a/hotspot/test/runtime/RedefineFinalizer/manifest.mf b/hotspot/test/runtime/RedefineFinalizer/manifest.mf new file mode 100644 index 00000000000..e337a65c01a --- /dev/null +++ b/hotspot/test/runtime/RedefineFinalizer/manifest.mf @@ -0,0 +1,5 @@ +Main-Class: Main +Agent-Class: Agent +Can-Redefine-Classes: true +Can-Retransform-Classes: true +Premain-Class: Agent diff --git a/hotspot/test/runtime/RedefineFinalizer/testme.sh b/hotspot/test/runtime/RedefineFinalizer/testme.sh new file mode 100644 index 00000000000..3b50f5050db --- /dev/null +++ b/hotspot/test/runtime/RedefineFinalizer/testme.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +# Copyright (c) 2014 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 6904403 +# @summary Don't assert if we redefine finalize method +# @run shell testme.sh + +# This test shouldn't provoke and assert(f == k->has_finalizer()) failed: inconsistent has_finalizer + +. ${TESTSRC}/../../test_env.sh + +JAVAC=${COMPILEJAVA}${FS}bin${FS}javac +JAR=${COMPILEJAVA}${FS}bin${FS}jar +JAVA=${TESTJAVA}${FS}bin${FS}java + +TOOLS_JAR=${TESTJAVA}${FS}lib${FS}tools.jar + +cp ${TESTSRC}${FS}*.java . +${JAVAC} -XDignore.symbol.file -classpath ${TOOLS_JAR} -sourcepath ${TESTSRC} *.java +if [ $? -eq 1 ] + then + echo "Compilation failed" + exit +fi + +${JAR} cvfm testcase.jar ${TESTSRC}/manifest.mf . +${JAVA} -Xbootclasspath/a:${TOOLS_JAR} -javaagent:${PWD}/testcase.jar Main From 436e1ecdf25870ce9aecd85cf22c29151ea00f87 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Wed, 28 May 2014 22:59:29 +0200 Subject: [PATCH 04/18] 8043786: [TESTBUG] runtime/CommandLine/TestHexArguments.java test fails in nightly Changed test to not pass on external flags to child processes Reviewed-by: coleenp, hseigel --- hotspot/test/runtime/CommandLine/TestHexArguments.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/test/runtime/CommandLine/TestHexArguments.java b/hotspot/test/runtime/CommandLine/TestHexArguments.java index 1fd33466662..f62435ed28d 100644 --- a/hotspot/test/runtime/CommandLine/TestHexArguments.java +++ b/hotspot/test/runtime/CommandLine/TestHexArguments.java @@ -35,14 +35,14 @@ import com.oracle.java.testlibrary.*; public class TestHexArguments { public static void main(String args[]) throws Exception { String[] javaArgs = {"-XX:SharedBaseAddress=0x1D000000", "-version"}; - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, javaArgs); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(javaArgs); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Could not create the Java Virtual Machine"); output.shouldHaveExitValue(0); String[] javaArgs1 = {"-XX:SharedBaseAddress=1D000000", "-version"}; - pb = ProcessTools.createJavaProcessBuilder(true, javaArgs1); + pb = ProcessTools.createJavaProcessBuilder(javaArgs1); output = new OutputAnalyzer(pb.start()); output.shouldContain("Could not create the Java Virtual Machine"); } From 06a856ab8aa71fdb0be36dac3672c709878fcc47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Fri, 30 May 2014 10:37:39 +0200 Subject: [PATCH 05/18] 8044132: Quarantine unstable/broken GC tests Reviewed-by: ehelin, jwilhelm --- hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java | 1 + hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java | 1 + hotspot/test/gc/g1/TestHumongousShrinkHeap.java | 1 + hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java | 1 + 4 files changed, 4 insertions(+) diff --git a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java index 2de2826ed5b..947fd0f9c88 100644 --- a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java +++ b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java @@ -22,6 +22,7 @@ */ /* + * @ignore 8027915 * @test TestParallelHeapSizeFlags * @key gc * @bug 8006088 diff --git a/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java b/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java index 852076e768e..14ca6ed8d3b 100644 --- a/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java +++ b/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java @@ -22,6 +22,7 @@ */ /* + * @ignore 8025645 * @test TestUseCompressedOopsErgo * @key gc * @bug 8010722 diff --git a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java index c790c6464bd..4cf6c4187c4 100644 --- a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java +++ b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java @@ -22,6 +22,7 @@ */ /** + * @ignore 8041506, 8041946, 8042051 * @test TestHumongousShrinkHeap * @bug 8036025 * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects diff --git a/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java b/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java index 6f9b02de270..7a23509712d 100644 --- a/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java +++ b/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java @@ -22,6 +22,7 @@ */ /** + * @ignore 8042051 * @test TestDynShrinkHeap * @bug 8016479 * @summary Verify that the heap shrinks after full GC according to the current values of the Min/MaxHeapFreeRatio flags From 44fc435b7ecfd5c19c18e4b7c72ac9282f885632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Fri, 30 May 2014 10:43:51 +0200 Subject: [PATCH 06/18] 8042310: TestStringDeduplicationMemoryUsage test failing Reviewed-by: ehelin, jwilhelm --- .../TestStringDeduplicationMemoryUsage.java | 36 -------- .../gc/g1/TestStringDeduplicationTools.java | 89 ------------------- 2 files changed, 125 deletions(-) delete mode 100644 hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java diff --git a/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java b/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java deleted file mode 100644 index ba3428986e2..00000000000 --- a/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2014, 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 TestStringDeduplicationMemoryUsage - * @summary Test string deduplication memory usage - * @bug 8029075 - * @key gc - * @library /testlibrary - */ - -public class TestStringDeduplicationMemoryUsage { - public static void main(String[] args) throws Exception { - TestStringDeduplicationTools.testMemoryUsage(); - } -} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationTools.java b/hotspot/test/gc/g1/TestStringDeduplicationTools.java index 5b27aa68590..1f8347bf4a1 100644 --- a/hotspot/test/gc/g1/TestStringDeduplicationTools.java +++ b/hotspot/test/gc/g1/TestStringDeduplicationTools.java @@ -294,55 +294,6 @@ class TestStringDeduplicationTools { } } - private static class MemoryUsageTest { - public static void main(String[] args) { - System.out.println("Begin: MemoryUsageTest"); - - final boolean useStringDeduplication = Boolean.parseBoolean(args[0]); - final int numberOfStrings = LargeNumberOfStrings; - final int numberOfUniqueStrings = 1; - - ArrayList list = createStrings(numberOfStrings, numberOfUniqueStrings); - forceDeduplication(DefaultAgeThreshold, FullGC); - - if (useStringDeduplication) { - verifyStrings(list, numberOfUniqueStrings); - } - - System.gc(); - - System.out.println("Heap Memory Usage: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()); - System.out.println("Array Header Size: " + unsafe.ARRAY_CHAR_BASE_OFFSET); - - System.out.println("End: MemoryUsageTest"); - } - - public static OutputAnalyzer run(boolean useStringDeduplication) throws Exception { - String[] extraArgs = new String[0]; - - if (useStringDeduplication) { - extraArgs = new String[] { - "-XX:+UseStringDeduplication", - "-XX:+PrintStringDeduplicationStatistics", - "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold - }; - } - - String[] defaultArgs = new String[] { - "-XX:+PrintGC", - "-XX:+PrintGCDetails", - MemoryUsageTest.class.getName(), - "" + useStringDeduplication - }; - - ArrayList args = new ArrayList(); - args.addAll(Arrays.asList(extraArgs)); - args.addAll(Arrays.asList(defaultArgs)); - - return runTest(args.toArray(new String[args.size()])); - } - } - /* * Tests */ @@ -480,44 +431,4 @@ class TestStringDeduplicationTools { OutputAnalyzer output = InternedTest.run(); output.shouldHaveExitValue(0); } - - public static void testMemoryUsage() throws Exception { - // Test that memory usage is reduced after deduplication - OutputAnalyzer output; - final String heapMemoryUsagePattern = "Heap Memory Usage: (\\d+)"; - final String arrayHeaderSizePattern = "Array Header Size: (\\d+)"; - - // Run without deduplication - output = MemoryUsageTest.run(false); - output.shouldHaveExitValue(0); - final long heapMemoryUsageWithoutDedup = Long.parseLong(output.firstMatch(heapMemoryUsagePattern, 1)); - final long arrayHeaderSizeWithoutDedup = Long.parseLong(output.firstMatch(arrayHeaderSizePattern, 1)); - - // Run with deduplication - output = MemoryUsageTest.run(true); - output.shouldHaveExitValue(0); - final long heapMemoryUsageWithDedup = Long.parseLong(output.firstMatch(heapMemoryUsagePattern, 1)); - final long arrayHeaderSizeWithDedup = Long.parseLong(output.firstMatch(arrayHeaderSizePattern, 1)); - - // Sanity check to make sure one instance isn't using compressed class pointers and the other not - if (arrayHeaderSizeWithoutDedup != arrayHeaderSizeWithDedup) { - throw new Exception("Unexpected difference between array header sizes"); - } - - // Calculate expected memory usage with deduplication enabled. This calculation does - // not take alignment and padding into account, so it's a conservative estimate. - final long sizeOfChar = unsafe.ARRAY_CHAR_INDEX_SCALE; - final long sizeOfCharArray = StringLength * sizeOfChar + arrayHeaderSizeWithoutDedup; - final long bytesSaved = (LargeNumberOfStrings - 1) * sizeOfCharArray; - final long heapMemoryUsageWithDedupExpected = heapMemoryUsageWithoutDedup - bytesSaved; - - System.out.println("Memory usage summary:"); - System.out.println(" heapMemoryUsageWithoutDedup: " + heapMemoryUsageWithoutDedup); - System.out.println(" heapMemoryUsageWithDedup: " + heapMemoryUsageWithDedup); - System.out.println(" heapMemoryUsageWithDedupExpected: " + heapMemoryUsageWithDedupExpected); - - if (heapMemoryUsageWithDedup > heapMemoryUsageWithDedupExpected) { - throw new Exception("Unexpected memory usage, heapMemoryUsageWithDedup should be less or equal to heapMemoryUsageWithDedupExpected"); - } - } } From 265262330861847d9bb24d57580680c3c2ebc0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Tue, 3 Jun 2014 10:37:46 +0200 Subject: [PATCH 07/18] 8040807: G1: Enable G1CollectedHeap::stop() Reviewed-by: brutisso, jmasa, tschatzl --- .../vm/gc_implementation/g1/concurrentMark.cpp | 4 ++-- .../vm/gc_implementation/g1/concurrentMark.hpp | 4 +++- .../vm/gc_implementation/g1/g1CollectedHeap.cpp | 16 +++++----------- hotspot/src/share/vm/runtime/java.cpp | 9 ++------- hotspot/src/share/vm/runtime/thread.cpp | 10 ++-------- 5 files changed, 14 insertions(+), 29 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 24c62d775bd..7478a1e163c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -901,7 +901,7 @@ void ConcurrentMark::checkpointRootsInitialPre() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectorPolicy* g1p = g1h->g1_policy(); - _has_aborted = false; + clear_has_aborted(); #ifndef PRODUCT if (G1PrintReachableAtInitialMark) { @@ -3261,7 +3261,7 @@ void ConcurrentMark::abort() { } _first_overflow_barrier_sync.abort(); _second_overflow_barrier_sync.abort(); - _has_aborted = true; + set_has_aborted(); SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); satb_mq_set.abandon_partial_marking(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index 9d049a2a255..c4dbcda557f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -822,7 +822,9 @@ public: // Called to abort the marking cycle after a Full GC takes place. void abort(); - bool has_aborted() { return _has_aborted; } + bool has_aborted() { return _has_aborted; } + void set_has_aborted() { _has_aborted = true; } + void clear_has_aborted() { _has_aborted = false; } // This prints the global/local fingers. It is used for debugging. NOT_PRODUCT(void print_finger();) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 060ffb0b4a6..cef2ee0a8f0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -2174,20 +2174,14 @@ jint G1CollectedHeap::initialize() { } void G1CollectedHeap::stop() { -#if 0 - // Stopping concurrent worker threads is currently disabled until - // some bugs in concurrent mark has been resolve. Without fixing - // those bugs first we risk haning during VM exit when trying to - // stop these threads. - - // Abort any ongoing concurrent root region scanning and stop all - // concurrent threads. We do this to make sure these threads do - // not continue to execute and access resources (e.g. gclog_or_tty) - // that are destroyed during shutdown. + // Abort any ongoing concurrent mark and stop all concurrent threads. + // We do this to make sure these threads do not continue to execute + // and access resources (e.g. gclog_or_tty) that are destroyed during + // shutdown. + _cm->set_has_aborted(); _cm->root_regions()->abort(); _cm->root_regions()->wait_until_scan_finished(); stop_conc_gc_threads(); -#endif } size_t G1CollectedHeap::conservative_max_heap_alignment() { diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index e852b56ef54..3a075117afe 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -501,9 +501,6 @@ void before_exit(JavaThread * thread) { os::infinite_sleep(); } - // Stop any ongoing concurrent GC work - Universe::heap()->stop(); - // Terminate watcher thread - must before disenrolling any periodic task if (PeriodicTask::num_tasks() > 0) WatcherThread::stop(); @@ -518,10 +515,8 @@ void before_exit(JavaThread * thread) { StatSampler::disengage(); StatSampler::destroy(); - // We do not need to explicitly stop concurrent GC threads because the - // JVM will be taken down at a safepoint when such threads are inactive -- - // except for some concurrent G1 threads, see (comment in) - // Threads::destroy_vm(). + // Stop concurrent GC threads + Universe::heap()->stop(); // Print GC/heap related information. if (PrintGCDetails) { diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index e6d9eee7927..3591b35ece9 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -3966,14 +3966,8 @@ bool Threads::destroy_vm() { // GC vm_operations can get caught at the safepoint, and the // heap is unparseable if they are caught. Grab the Heap_lock // to prevent this. The GC vm_operations will not be able to - // queue until after the vm thread is dead. - // After this point, we'll never emerge out of the safepoint before - // the VM exits, so concurrent GC threads do not need to be explicitly - // stopped; they remain inactive until the process exits. - // Note: some concurrent G1 threads may be running during a safepoint, - // but these will not be accessing the heap, just some G1-specific side - // data structures that are not accessed by any other threads but them - // after this point in a terminal safepoint. + // queue until after the vm thread is dead. After this point, + // we'll never emerge out of the safepoint before the VM exits. MutexLocker ml(Heap_lock); From 426151a22e29e9eea719e09c2a3109a7b9f01bc8 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Tue, 3 Jun 2014 10:44:36 +0200 Subject: [PATCH 08/18] 8043239: G1: Missing post barrier in processing of j.l.ref.Reference objects Removed all write barriers during reference processing and added explicit write barriers when iterating through the discovered list. Reviewed-by: pliden, jmasa, tschatzl --- .../concurrentMarkSweepGeneration.cpp | 3 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 10 +-- .../parNew/parNewGeneration.cpp | 3 +- .../parallelScavenge/psParallelCompact.cpp | 3 +- .../parallelScavenge/psScavenge.cpp | 3 +- .../share/vm/memory/referenceProcessor.cpp | 89 ++++++------------- .../share/vm/memory/referenceProcessor.hpp | 23 +---- 7 files changed, 38 insertions(+), 96 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 43d6e923a7b..dba6f8ca7d7 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -311,8 +311,7 @@ void CMSCollector::ref_processor_init() { _cmsGen->refs_discovery_is_mt(), // mt discovery (int) MAX2(ConcGCThreads, ParallelGCThreads), // mt discovery degree _cmsGen->refs_discovery_is_atomic(), // discovery is not atomic - &_is_alive_closure, // closure for liveness info - false); // next field updates do not need write barrier + &_is_alive_closure); // closure for liveness info // Initialize the _ref_processor field of CMSGen _cmsGen->set_ref_processor(_ref_processor); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 060ffb0b4a6..83f819b3919 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -2246,12 +2246,9 @@ void G1CollectedHeap::ref_processing_init() { // degree of mt discovery false, // Reference discovery is not atomic - &_is_alive_closure_cm, + &_is_alive_closure_cm); // is alive closure // (for efficiency/performance) - true); - // Setting next fields of discovered - // lists requires a barrier. // STW ref processor _ref_processor_stw = @@ -2266,12 +2263,9 @@ void G1CollectedHeap::ref_processing_init() { // degree of mt discovery true, // Reference discovery is atomic - &_is_alive_closure_stw, + &_is_alive_closure_stw); // is alive closure // (for efficiency/performance) - false); - // Setting next fields of discovered - // lists does not require a barrier. } size_t G1CollectedHeap::capacity() const { diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index 2661e1280b6..5e979965731 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -1636,8 +1636,7 @@ void ParNewGeneration::ref_processor_init() { refs_discovery_is_mt(), // mt discovery (int) ParallelGCThreads, // mt discovery degree refs_discovery_is_atomic(), // atomic_discovery - NULL, // is_alive_non_header - false); // write barrier for next field updates + NULL); // is_alive_non_header } } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index de4c8bcdfd6..a9ffe54bd25 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -854,8 +854,7 @@ void PSParallelCompact::post_initialize() { true, // mt discovery (int) ParallelGCThreads, // mt discovery degree true, // atomic_discovery - &_is_alive_closure, // non-header is alive closure - false); // write barrier for next field updates + &_is_alive_closure); // non-header is alive closure _counters = new CollectorCounters("PSParallelCompact", 1); // Initialize static fields in ParCompactionManager. diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp index 81510c905a1..fd3030462b8 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp @@ -864,8 +864,7 @@ void PSScavenge::initialize() { true, // mt discovery (int) ParallelGCThreads, // mt discovery degree true, // atomic_discovery - NULL, // header provides liveness info - false); // next field updates do not need write barrier + NULL); // header provides liveness info // Cache the cardtable BarrierSet* bs = Universe::heap()->barrier_set(); diff --git a/hotspot/src/share/vm/memory/referenceProcessor.cpp b/hotspot/src/share/vm/memory/referenceProcessor.cpp index 2a87b4b65b6..2a074f21f15 100644 --- a/hotspot/src/share/vm/memory/referenceProcessor.cpp +++ b/hotspot/src/share/vm/memory/referenceProcessor.cpp @@ -96,12 +96,10 @@ ReferenceProcessor::ReferenceProcessor(MemRegion span, bool mt_discovery, uint mt_discovery_degree, bool atomic_discovery, - BoolObjectClosure* is_alive_non_header, - bool discovered_list_needs_post_barrier) : + BoolObjectClosure* is_alive_non_header) : _discovering_refs(false), _enqueuing_is_done(false), _is_alive_non_header(is_alive_non_header), - _discovered_list_needs_post_barrier(discovered_list_needs_post_barrier), _processing_is_mt(mt_processing), _next_id(0) { @@ -340,10 +338,18 @@ void ReferenceProcessor::enqueue_discovered_reflist(DiscoveredList& refs_list, // (java.lang.ref.Reference.discovered), self-loop their "next" field // thus distinguishing them from active References, then // prepend them to the pending list. + // + // The Java threads will see the Reference objects linked together through + // the discovered field. Instead of trying to do the write barrier updates + // in all places in the reference processor where we manipulate the discovered + // field we make sure to do the barrier here where we anyway iterate through + // all linked Reference objects. Note that it is important to not dirty any + // cards during reference processing since this will cause card table + // verification to fail for G1. + // // BKWRD COMPATIBILITY NOTE: For older JDKs (prior to the fix for 4956777), // the "next" field is used to chain the pending list, not the discovered // field. - if (TraceReferenceGC && PrintGCDetails) { gclog_or_tty->print_cr("ReferenceProcessor::enqueue_discovered_reflist list " INTPTR_FORMAT, (address)refs_list.head()); @@ -365,15 +371,15 @@ void ReferenceProcessor::enqueue_discovered_reflist(DiscoveredList& refs_list, assert(java_lang_ref_Reference::next(obj) == NULL, "Reference not active; should not be discovered"); // Self-loop next, so as to make Ref not active. - // Post-barrier not needed when looping to self. java_lang_ref_Reference::set_next_raw(obj, obj); - if (next_d == obj) { // obj is last + if (next_d != obj) { + oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(obj), next_d); + } else { + // This is the last object. // Swap refs_list into pending_list_addr and // set obj's discovered to what we read from pending_list_addr. oop old = oopDesc::atomic_exchange_oop(refs_list.head(), pending_list_addr); - // Need post-barrier on pending_list_addr above; - // see special post-barrier code at the end of - // enqueue_discovered_reflists() further below. + // Need post-barrier on pending_list_addr. See enqueue_discovered_ref_helper() above. java_lang_ref_Reference::set_discovered_raw(obj, old); // old may be NULL oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(obj), old); } @@ -496,20 +502,15 @@ void DiscoveredListIterator::remove() { // pre-barrier here because we know the Reference has already been found/marked, // that's how it ended up in the discovered list in the first place. oop_store_raw(_prev_next, new_next); - if (_discovered_list_needs_post_barrier && _prev_next != _refs_list.adr_head()) { - // Needs post-barrier and this is not the list head (which is not on the heap) - oopDesc::bs()->write_ref_field(_prev_next, new_next); - } NOT_PRODUCT(_removed++); _refs_list.dec_length(1); } // Make the Reference object active again. void DiscoveredListIterator::make_active() { - // For G1 we don't want to use set_next - it - // will dirty the card for the next field of - // the reference object and will fail - // CT verification. + // The pre barrier for G1 is probably just needed for the old + // reference processing behavior. Should we guard this with + // ReferenceProcessor::pending_list_uses_discovered_field() ? if (UseG1GC) { HeapWord* next_addr = java_lang_ref_Reference::next_addr(_ref); if (UseCompressedOops) { @@ -517,10 +518,8 @@ void DiscoveredListIterator::make_active() { } else { oopDesc::bs()->write_ref_field_pre((oop*)next_addr, NULL); } - java_lang_ref_Reference::set_next_raw(_ref, NULL); - } else { - java_lang_ref_Reference::set_next(_ref, NULL); } + java_lang_ref_Reference::set_next_raw(_ref, NULL); } void DiscoveredListIterator::clear_referent() { @@ -546,7 +545,7 @@ ReferenceProcessor::process_phase1(DiscoveredList& refs_list, OopClosure* keep_alive, VoidClosure* complete_gc) { assert(policy != NULL, "Must have a non-NULL policy"); - DiscoveredListIterator iter(refs_list, keep_alive, is_alive, _discovered_list_needs_post_barrier); + DiscoveredListIterator iter(refs_list, keep_alive, is_alive); // Decide which softly reachable refs should be kept alive. while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(!discovery_is_atomic() /* allow_null_referent */)); @@ -586,7 +585,7 @@ ReferenceProcessor::pp2_work(DiscoveredList& refs_list, BoolObjectClosure* is_alive, OopClosure* keep_alive) { assert(discovery_is_atomic(), "Error"); - DiscoveredListIterator iter(refs_list, keep_alive, is_alive, _discovered_list_needs_post_barrier); + DiscoveredListIterator iter(refs_list, keep_alive, is_alive); while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */)); DEBUG_ONLY(oop next = java_lang_ref_Reference::next(iter.obj());) @@ -623,7 +622,7 @@ ReferenceProcessor::pp2_work_concurrent_discovery(DiscoveredList& refs_list, OopClosure* keep_alive, VoidClosure* complete_gc) { assert(!discovery_is_atomic(), "Error"); - DiscoveredListIterator iter(refs_list, keep_alive, is_alive, _discovered_list_needs_post_barrier); + DiscoveredListIterator iter(refs_list, keep_alive, is_alive); while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); HeapWord* next_addr = java_lang_ref_Reference::next_addr(iter.obj()); @@ -666,7 +665,7 @@ ReferenceProcessor::process_phase3(DiscoveredList& refs_list, OopClosure* keep_alive, VoidClosure* complete_gc) { ResourceMark rm; - DiscoveredListIterator iter(refs_list, keep_alive, is_alive, _discovered_list_needs_post_barrier); + DiscoveredListIterator iter(refs_list, keep_alive, is_alive); while (iter.has_next()) { iter.update_discovered(); iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */)); @@ -782,13 +781,6 @@ private: bool _clear_referent; }; -void ReferenceProcessor::set_discovered(oop ref, oop value) { - java_lang_ref_Reference::set_discovered_raw(ref, value); - if (_discovered_list_needs_post_barrier) { - oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(ref), value); - } -} - // Balances reference queues. // Move entries from all queues[0, 1, ..., _max_num_q-1] to // queues[0, 1, ..., _num_q-1] because only the first _num_q @@ -846,9 +838,9 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[]) // Add the chain to the to list. if (ref_lists[to_idx].head() == NULL) { // to list is empty. Make a loop at the end. - set_discovered(move_tail, move_tail); + java_lang_ref_Reference::set_discovered_raw(move_tail, move_tail); } else { - set_discovered(move_tail, ref_lists[to_idx].head()); + java_lang_ref_Reference::set_discovered_raw(move_tail, ref_lists[to_idx].head()); } ref_lists[to_idx].set_head(move_head); ref_lists[to_idx].inc_length(refs_to_move); @@ -982,7 +974,7 @@ void ReferenceProcessor::clean_up_discovered_references() { void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) { assert(!discovery_is_atomic(), "Else why call this method?"); - DiscoveredListIterator iter(refs_list, NULL, NULL, _discovered_list_needs_post_barrier); + DiscoveredListIterator iter(refs_list, NULL, NULL); while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); oop next = java_lang_ref_Reference::next(iter.obj()); @@ -1071,16 +1063,6 @@ ReferenceProcessor::add_to_discovered_list_mt(DiscoveredList& refs_list, // The last ref must have its discovered field pointing to itself. oop next_discovered = (current_head != NULL) ? current_head : obj; - // Note: In the case of G1, this specific pre-barrier is strictly - // not necessary because the only case we are interested in - // here is when *discovered_addr is NULL (see the CAS further below), - // so this will expand to nothing. As a result, we have manually - // elided this out for G1, but left in the test for some future - // collector that might have need for a pre-barrier here, e.g.:- - // oopDesc::bs()->write_ref_field_pre((oop* or narrowOop*)discovered_addr, next_discovered); - assert(!_discovered_list_needs_post_barrier || UseG1GC, - "Need to check non-G1 collector: " - "may need a pre-write-barrier for CAS from NULL below"); oop retest = oopDesc::atomic_compare_exchange_oop(next_discovered, discovered_addr, NULL); if (retest == NULL) { @@ -1089,9 +1071,6 @@ ReferenceProcessor::add_to_discovered_list_mt(DiscoveredList& refs_list, // is necessary. refs_list.set_head(obj); refs_list.inc_length(1); - if (_discovered_list_needs_post_barrier) { - oopDesc::bs()->write_ref_field((void*)discovered_addr, next_discovered); - } if (TraceReferenceGC) { gclog_or_tty->print_cr("Discovered reference (mt) (" INTPTR_FORMAT ": %s)", @@ -1242,24 +1221,14 @@ bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) { if (_discovery_is_mt) { add_to_discovered_list_mt(*list, obj, discovered_addr); } else { - // If "_discovered_list_needs_post_barrier", we do write barriers when - // updating the discovered reference list. Otherwise, we do a raw store - // here: the field will be visited later when processing the discovered - // references. + // We do a raw store here: the field will be visited later when processing + // the discovered references. oop current_head = list->head(); // The last ref must have its discovered field pointing to itself. oop next_discovered = (current_head != NULL) ? current_head : obj; - // As in the case further above, since we are over-writing a NULL - // pre-value, we can safely elide the pre-barrier here for the case of G1. - // e.g.:- oopDesc::bs()->write_ref_field_pre((oop* or narrowOop*)discovered_addr, next_discovered); assert(discovered == NULL, "control point invariant"); - assert(!_discovered_list_needs_post_barrier || UseG1GC, - "For non-G1 collector, may need a pre-write-barrier for CAS from NULL below"); oop_store_raw(discovered_addr, next_discovered); - if (_discovered_list_needs_post_barrier) { - oopDesc::bs()->write_ref_field((void*)discovered_addr, next_discovered); - } list->set_head(obj); list->inc_length(1); @@ -1353,7 +1322,7 @@ ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list, OopClosure* keep_alive, VoidClosure* complete_gc, YieldClosure* yield) { - DiscoveredListIterator iter(refs_list, keep_alive, is_alive, _discovered_list_needs_post_barrier); + DiscoveredListIterator iter(refs_list, keep_alive, is_alive); while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); oop obj = iter.obj(); diff --git a/hotspot/src/share/vm/memory/referenceProcessor.hpp b/hotspot/src/share/vm/memory/referenceProcessor.hpp index f9f69f07142..26ac9f1c5d4 100644 --- a/hotspot/src/share/vm/memory/referenceProcessor.hpp +++ b/hotspot/src/share/vm/memory/referenceProcessor.hpp @@ -99,7 +99,6 @@ private: oop _referent; OopClosure* _keep_alive; BoolObjectClosure* _is_alive; - bool _discovered_list_needs_post_barrier; DEBUG_ONLY( oop _first_seen; // cyclic linked list check @@ -113,8 +112,7 @@ private: public: inline DiscoveredListIterator(DiscoveredList& refs_list, OopClosure* keep_alive, - BoolObjectClosure* is_alive, - bool discovered_list_needs_post_barrier = false): + BoolObjectClosure* is_alive): _refs_list(refs_list), _prev_next(refs_list.adr_head()), _prev(NULL), @@ -128,8 +126,7 @@ public: #endif _next(NULL), _keep_alive(keep_alive), - _is_alive(is_alive), - _discovered_list_needs_post_barrier(discovered_list_needs_post_barrier) + _is_alive(is_alive) { } // End Of List. @@ -230,14 +227,6 @@ class ReferenceProcessor : public CHeapObj { // other collectors in configuration bool _discovery_is_mt; // true if reference discovery is MT. - // If true, setting "next" field of a discovered refs list requires - // write post barrier. (Must be true if used in a collector in which - // elements of a discovered list may be moved during discovery: for - // example, a collector like Garbage-First that moves objects during a - // long-term concurrent marking phase that does weak reference - // discovery.) - bool _discovered_list_needs_post_barrier; - bool _enqueuing_is_done; // true if all weak references enqueued bool _processing_is_mt; // true during phases when // reference processing is MT. @@ -382,11 +371,6 @@ class ReferenceProcessor : public CHeapObj { void enqueue_discovered_reflists(HeapWord* pending_list_addr, AbstractRefProcTaskExecutor* task_executor); protected: - // Set the 'discovered' field of the given reference to - // the given value - emitting post barriers depending upon - // the value of _discovered_list_needs_post_barrier. - void set_discovered(oop ref, oop value); - // "Preclean" the given discovered reference list // by removing references with strongly reachable referents. // Currently used in support of CMS only. @@ -427,8 +411,7 @@ class ReferenceProcessor : public CHeapObj { bool mt_processing = false, uint mt_processing_degree = 1, bool mt_discovery = false, uint mt_discovery_degree = 1, bool atomic_discovery = true, - BoolObjectClosure* is_alive_non_header = NULL, - bool discovered_list_needs_post_barrier = false); + BoolObjectClosure* is_alive_non_header = NULL); // RefDiscoveryPolicy values enum DiscoveryPolicy { From 65cf6a8edc40772e189bb212877e8e1170b3159b Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Thu, 29 May 2014 14:31:28 +0200 Subject: [PATCH 09/18] 8042933: assert(capacity_until_gc >= committed_bytes) failed Reviewed-by: stefank, jmasa --- hotspot/src/share/vm/memory/metaspace.cpp | 44 +++++++++++------ hotspot/src/share/vm/memory/metaspace.hpp | 4 +- hotspot/src/share/vm/runtime/thread.cpp | 2 + .../TestMetaspaceInitialization.java | 48 +++++++++++++++++++ 4 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 hotspot/test/gc/metaspace/TestMetaspaceInitialization.java diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index cd5fceff2d0..d2d1ba7992e 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -1423,6 +1423,17 @@ size_t MetaspaceGC::dec_capacity_until_GC(size_t v) { return (size_t)Atomic::add_ptr(-(intptr_t)v, &_capacity_until_GC); } +void MetaspaceGC::initialize() { + // Set the high-water mark to MaxMetapaceSize during VM initializaton since + // we can't do a GC during initialization. + _capacity_until_GC = MaxMetaspaceSize; +} + +void MetaspaceGC::post_initialize() { + // Reset the high-water mark once the VM initialization is done. + _capacity_until_GC = MAX2(MetaspaceAux::committed_bytes(), MetaspaceSize); +} + bool MetaspaceGC::can_expand(size_t word_size, bool is_class) { // Check if the compressed class space is full. if (is_class && Metaspace::using_class_space()) { @@ -1443,21 +1454,13 @@ bool MetaspaceGC::can_expand(size_t word_size, bool is_class) { size_t MetaspaceGC::allowed_expansion() { size_t committed_bytes = MetaspaceAux::committed_bytes(); - - size_t left_until_max = MaxMetaspaceSize - committed_bytes; - - // Always grant expansion if we are initiating the JVM, - // or if the GC_locker is preventing GCs. - if (!is_init_completed() || GC_locker::is_active_and_needs_gc()) { - return left_until_max / BytesPerWord; - } - size_t capacity_until_gc = capacity_until_GC(); - if (capacity_until_gc <= committed_bytes) { - return 0; - } + assert(capacity_until_gc >= committed_bytes, + err_msg("capacity_until_gc: " SIZE_FORMAT " < committed_bytes: " SIZE_FORMAT, + capacity_until_gc, committed_bytes)); + size_t left_until_max = MaxMetaspaceSize - committed_bytes; size_t left_until_GC = capacity_until_gc - committed_bytes; size_t left_to_commit = MIN2(left_until_GC, left_until_max); @@ -1469,7 +1472,15 @@ void MetaspaceGC::compute_new_size() { uint current_shrink_factor = _shrink_factor; _shrink_factor = 0; - const size_t used_after_gc = MetaspaceAux::capacity_bytes(); + // Using committed_bytes() for used_after_gc is an overestimation, since the + // chunk free lists are included in committed_bytes() and the memory in an + // un-fragmented chunk free list is available for future allocations. + // However, if the chunk free lists becomes fragmented, then the memory may + // not be available for future allocations and the memory is therefore "in use". + // Including the chunk free lists in the definition of "in use" is therefore + // necessary. Not including the chunk free lists can cause capacity_until_GC to + // shrink below committed_bytes() and this has caused serious bugs in the past. + const size_t used_after_gc = MetaspaceAux::committed_bytes(); const size_t capacity_until_GC = MetaspaceGC::capacity_until_GC(); const double minimum_free_percentage = MinMetaspaceFreeRatio / 100.0; @@ -3094,6 +3105,8 @@ void Metaspace::ergo_initialize() { } void Metaspace::global_initialize() { + MetaspaceGC::initialize(); + // Initialize the alignment for shared spaces. int max_alignment = os::vm_allocation_granularity(); size_t cds_total = 0; @@ -3201,10 +3214,13 @@ void Metaspace::global_initialize() { } } - MetaspaceGC::initialize(); _tracer = new MetaspaceTracer(); } +void Metaspace::post_initialize() { + MetaspaceGC::post_initialize(); +} + Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, size_t chunk_word_size, size_t chunk_bunch) { diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index 22e21b80d3d..baa25cd6d35 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -208,6 +208,7 @@ class Metaspace : public CHeapObj { static void ergo_initialize(); static void global_initialize(); + static void post_initialize(); static size_t first_chunk_word_size() { return _first_chunk_word_size; } static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; } @@ -398,7 +399,8 @@ class MetaspaceGC : AllStatic { public: - static void initialize() { _capacity_until_GC = MetaspaceSize; } + static void initialize(); + static void post_initialize(); static size_t capacity_until_GC(); static size_t inc_capacity_until_GC(size_t v); diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 3591b35ece9..1716ed5e572 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -3543,6 +3543,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // debug stuff, that does not work until all basic classes have been initialized. set_init_completed(); + Metaspace::post_initialize(); + HOTSPOT_VM_INIT_END(); // record VM initialization completion time diff --git a/hotspot/test/gc/metaspace/TestMetaspaceInitialization.java b/hotspot/test/gc/metaspace/TestMetaspaceInitialization.java new file mode 100644 index 00000000000..c7bbcec0829 --- /dev/null +++ b/hotspot/test/gc/metaspace/TestMetaspaceInitialization.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +import java.util.ArrayList; + +/* @test TestMetaspaceInitialization + * @bug 8042933 + * @summary Tests to initialize metaspace with a very low MetaspaceSize + * @library /testlibrary + * @run main/othervm -XX:MetaspaceSize=2m TestMetaspaceInitialization + */ +public class TestMetaspaceInitialization { + private class Internal { + public int x; + public Internal(int x) { + this.x = x; + } + } + + private void test() { + ArrayList l = new ArrayList<>(); + l.add(new Internal(17)); + } + + public static void main(String[] args) { + new TestMetaspaceInitialization().test(); + } +} From 5ff7186a1c768a898f696602d052c907fdd433cd Mon Sep 17 00:00:00 2001 From: Lois Foltan Date: Thu, 29 May 2014 08:58:51 -0400 Subject: [PATCH 10/18] 8041623: Solaris Studio 12.4 C++ 5.13, CHECK_UNHANDLED_OOPS use of class oop's copy constructor definitions causing error level diagnostic Fix several minor compilation issues with volatile oops for CHECK_UNHANDLED_OOPS support. Reviewed-by: coleenp, hseigel --- hotspot/src/share/vm/classfile/javaClasses.hpp | 2 +- hotspot/src/share/vm/oops/oopsHierarchy.hpp | 10 +++------- hotspot/src/share/vm/runtime/thread.cpp | 2 +- hotspot/src/share/vm/services/memoryManager.cpp | 4 ++-- hotspot/src/share/vm/services/memoryPool.cpp | 4 ++-- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index b4da42c423d..60c65fe968a 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1181,7 +1181,7 @@ public: static oop target( oop site) { return site->obj_field( _target_offset); } static void set_target( oop site, oop target) { site->obj_field_put( _target_offset, target); } - static volatile oop target_volatile(oop site) { return site->obj_field_volatile( _target_offset); } + static volatile oop target_volatile(oop site) { return oop((oopDesc *)(site->obj_field_volatile(_target_offset))); } static void set_target_volatile(oop site, oop target) { site->obj_field_put_volatile(_target_offset, target); } // Testers diff --git a/hotspot/src/share/vm/oops/oopsHierarchy.hpp b/hotspot/src/share/vm/oops/oopsHierarchy.hpp index ef0d2ed2bba..cd63547c38c 100644 --- a/hotspot/src/share/vm/oops/oopsHierarchy.hpp +++ b/hotspot/src/share/vm/oops/oopsHierarchy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -112,9 +112,7 @@ public: // Assignment oop& operator=(const oop& o) { _o = o.obj(); return *this; } -#ifndef SOLARIS volatile oop& operator=(const oop& o) volatile { _o = o.obj(); return *this; } -#endif volatile oop& operator=(const volatile oop& o) volatile { _o = o.obj(); return *this; } // Explict user conversions @@ -123,11 +121,10 @@ public: operator void* () const volatile { return (void *)obj(); } #endif operator HeapWord* () const { return (HeapWord*)obj(); } - operator oopDesc* () const { return obj(); } + operator oopDesc* () const volatile { return obj(); } operator intptr_t* () const { return (intptr_t*)obj(); } operator PromotedObject* () const { return (PromotedObject*)obj(); } operator markOop () const { return markOop(obj()); } - operator address () const { return (address)obj(); } // from javaCalls.cpp @@ -161,11 +158,10 @@ public: oop::operator=(o); \ return *this; \ } \ - NOT_SOLARIS( \ volatile type##Oop& operator=(const type##Oop& o) volatile { \ (void)const_cast(oop::operator=(o)); \ return *this; \ - }) \ + } \ volatile type##Oop& operator=(const volatile type##Oop& o) volatile {\ (void)const_cast(oop::operator=(o)); \ return *this; \ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index e6d9eee7927..dffe1fe85f8 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -1434,7 +1434,7 @@ void JavaThread::initialize() { _in_deopt_handler = 0; _doing_unsafe_access = false; _stack_guard_state = stack_guard_unused; - (void)const_cast(_exception_oop = NULL); + (void)const_cast(_exception_oop = oop(NULL)); _exception_pc = 0; _exception_handler_pc = 0; _is_method_handle_return = 0; diff --git a/hotspot/src/share/vm/services/memoryManager.cpp b/hotspot/src/share/vm/services/memoryManager.cpp index 646b5e12ebb..0469c937013 100644 --- a/hotspot/src/share/vm/services/memoryManager.cpp +++ b/hotspot/src/share/vm/services/memoryManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -39,7 +39,7 @@ MemoryManager::MemoryManager() { _num_pools = 0; - (void)const_cast(_memory_mgr_obj = NULL); + (void)const_cast(_memory_mgr_obj = instanceOop(NULL)); } void MemoryManager::add_pool(MemoryPool* pool) { diff --git a/hotspot/src/share/vm/services/memoryPool.cpp b/hotspot/src/share/vm/services/memoryPool.cpp index 1510cd596b4..2d686cbdc9a 100644 --- a/hotspot/src/share/vm/services/memoryPool.cpp +++ b/hotspot/src/share/vm/services/memoryPool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -46,7 +46,7 @@ MemoryPool::MemoryPool(const char* name, _name = name; _initial_size = init_size; _max_size = max_size; - (void)const_cast(_memory_pool_obj = NULL); + (void)const_cast(_memory_pool_obj = instanceOop(NULL)); _available_for_allocation = true; _num_managers = 0; _type = type; From ad6d8d6abd2be9aaf7f966258f1f8974523600ef Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Fri, 30 May 2014 07:20:51 -0700 Subject: [PATCH 11/18] 8036823: Stack trace sometimes shows 'locked' instead of 'waiting to lock' Add a !owner check for 'waiting to lock' to catch current_pending_monitor corner cases. Co-authored-by: Krystal Mok Co-authored-by: Zhengyu Gu Reviewed-by: dholmes, sspitsyn, kmo, zgu --- .../src/share/vm/runtime/objectMonitor.cpp | 9 + hotspot/src/share/vm/runtime/vframe.cpp | 7 +- hotspot/test/TEST.groups | 1 + .../TestThreadDumpMonitorContention.java | 405 ++++++++++++++++++ 4 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/runtime/Thread/TestThreadDumpMonitorContention.java diff --git a/hotspot/src/share/vm/runtime/objectMonitor.cpp b/hotspot/src/share/vm/runtime/objectMonitor.cpp index 1f16ee4ad1c..6f2323c8668 100644 --- a/hotspot/src/share/vm/runtime/objectMonitor.cpp +++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp @@ -385,6 +385,15 @@ void ATTR ObjectMonitor::enter(TRAPS) { jt->java_suspend_self(); } Self->set_current_pending_monitor(NULL); + + // We cleared the pending monitor info since we've just gotten past + // the enter-check-for-suspend dance and we now own the monitor free + // and clear, i.e., it is no longer pending. The ThreadBlockInVM + // destructor can go to a safepoint at the end of this block. If we + // do a thread dump during that safepoint, then this thread will show + // as having "-locked" the monitor, but the OS and java.lang.Thread + // states will still report that the thread is blocked trying to + // acquire it. } Atomic::dec_ptr(&_count); diff --git a/hotspot/src/share/vm/runtime/vframe.cpp b/hotspot/src/share/vm/runtime/vframe.cpp index 8b4d72f728e..a32d03a7b21 100644 --- a/hotspot/src/share/vm/runtime/vframe.cpp +++ b/hotspot/src/share/vm/runtime/vframe.cpp @@ -199,6 +199,7 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { continue; } if (monitor->owner() != NULL) { + // the monitor is associated with an object, i.e., it is locked // First, assume we have the monitor locked. If we haven't found an // owned monitor before and this is the first frame, then we need to @@ -209,7 +210,11 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { if (!found_first_monitor && frame_count == 0) { markOop mark = monitor->owner()->mark(); if (mark->has_monitor() && - mark->monitor() == thread()->current_pending_monitor()) { + ( // we have marked ourself as pending on this monitor + mark->monitor() == thread()->current_pending_monitor() || + // we are not the owner of this monitor + !mark->monitor()->is_entered(thread()) + )) { lock_state = "waiting to lock"; } } diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index 2982e82b694..69f771130a0 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -81,6 +81,7 @@ needs_jdk = \ runtime/NMT/ThreadedVirtualAllocTestType.java \ runtime/NMT/VirtualAllocTestType.java \ runtime/RedefineObject/TestRedefineObject.java \ + runtime/Thread/TestThreadDumpMonitorContention.java \ runtime/XCheckJniJsig/XCheckJSig.java \ serviceability/attach/AttachWithStalePidFile.java \ serviceability/jvmti/8036666/GetObjectLockCount.java \ diff --git a/hotspot/test/runtime/Thread/TestThreadDumpMonitorContention.java b/hotspot/test/runtime/Thread/TestThreadDumpMonitorContention.java new file mode 100644 index 00000000000..06b2274d823 --- /dev/null +++ b/hotspot/test/runtime/Thread/TestThreadDumpMonitorContention.java @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2014, 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 8036823 + * @summary Creates two threads contending for the same lock and checks + * whether jstack reports "locked" by more than one thread. + * + * @library /testlibrary + * @run main/othervm TestThreadDumpMonitorContention + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.oracle.java.testlibrary.*; + +public class TestThreadDumpMonitorContention { + // jstack tends to be closely bound to the VM that we are running + // so use getTestJDKTool() instead of getCompileJDKTool() or even + // getJDKTool() which can fall back to "compile.jdk". + final static String JSTACK = JDKToolFinder.getTestJDKTool("jstack"); + final static String PID = getPid(); + + // looking for header lines with these patterns: + // "ContendingThread-1" #19 prio=5 os_prio=64 tid=0x000000000079c000 nid=0x23 runnable [0xffff80ffb8b87000] + // "ContendingThread-2" #21 prio=5 os_prio=64 tid=0x0000000000780000 nid=0x2f waiting for monitor entry [0xfffffd7fc1111000] + final static Pattern HEADER_PREFIX_PATTERN = Pattern.compile( + "^\"ContendingThread-.*"); + final static Pattern HEADER_WAITING_PATTERN = Pattern.compile( + "^\"ContendingThread-.* waiting for monitor entry .*"); + final static Pattern HEADER_RUNNABLE_PATTERN = Pattern.compile( + "^\"ContendingThread-.* runnable .*"); + + // looking for thread state lines with these patterns: + // java.lang.Thread.State: RUNNABLE + // java.lang.Thread.State: BLOCKED (on object monitor) + final static Pattern THREAD_STATE_PREFIX_PATTERN = Pattern.compile( + " *java\\.lang\\.Thread\\.State: .*"); + final static Pattern THREAD_STATE_BLOCKED_PATTERN = Pattern.compile( + " *java\\.lang\\.Thread\\.State: BLOCKED \\(on object monitor\\)"); + final static Pattern THREAD_STATE_RUNNABLE_PATTERN = Pattern.compile( + " *java\\.lang\\.Thread\\.State: RUNNABLE"); + + // looking for duplicates of this pattern: + // - locked <0x000000076ac59e20> (a TestThreadDumpMonitorContention$1) + final static Pattern LOCK_PATTERN = Pattern.compile( + ".* locked \\<.*\\(a TestThreadDumpMonitorContention.*"); + + // sanity checking header and thread state lines associated + // with this pattern: + // - waiting to lock <0x000000076ac59e20> (a TestThreadDumpMonitorContention$1) + final static Pattern WAITING_PATTERN = Pattern.compile( + ".* waiting to lock \\<.*\\(a TestThreadDumpMonitorContention.*"); + + volatile static boolean done = false; + + static int error_cnt = 0; + static String header_line = null; + static boolean have_header_line = false; + static boolean have_thread_state_line = false; + static int match_cnt = 0; + static String[] match_list = new String[2]; + static int n_samples = 15; + static String thread_state_line = null; + static boolean verbose = false; + + public static void main(String[] args) throws Exception { + if (args.length != 0) { + int arg_i = 0; + if (args[arg_i].equals("-v")) { + verbose = true; + arg_i++; + } + + try { + n_samples = Integer.parseInt(args[arg_i]); + } catch (NumberFormatException nfe) { + System.err.println(nfe); + usage(); + } + } + + Runnable runnable = new Runnable() { + public void run() { + while (!done) { + synchronized (this) { } + } + } + }; + Thread[] thread_list = new Thread[2]; + thread_list[0] = new Thread(runnable, "ContendingThread-1"); + thread_list[1] = new Thread(runnable, "ContendingThread-2"); + thread_list[0].start(); + thread_list[1].start(); + + doSamples(); + + done = true; + + thread_list[0].join(); + thread_list[1].join(); + + if (error_cnt == 0) { + System.out.println("Test PASSED."); + } else { + System.out.println("Test FAILED."); + throw new AssertionError("error_cnt=" + error_cnt); + } + } + + // Reached a blank line which is the end of the + // stack trace without matching either LOCK_PATTERN + // or WAITING_PATTERN. Rare, but it's not an error. + // + // Example: + // "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f runnable [0xfffffd7fc1111000] + // java.lang.Thread.State: RUNNABLE + // at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:67) + // at java.lang.Thread.run(Thread.java:745) + // + static boolean checkBlankLine(String line) { + if (line.length() == 0) { + have_header_line = false; + have_thread_state_line = false; + return true; + } + + return false; + } + + // Process the locked line here if we found one. + // + // Example 1: + // "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f runnable [0xfffffd7fc1111000] + // java.lang.Thread.State: RUNNABLE + // at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:67) + // - locked <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1) + // at java.lang.Thread.run(Thread.java:745) + // + // Example 2: + // "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f waiting for monitor entry [0xfffffd7fc1111000] + // java.lang.Thread.State: BLOCKED (on object monitor) + // at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:67) + // - locked <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1) + // at java.lang.Thread.run(Thread.java:745) + // + static boolean checkLockedLine(String line) { + Matcher matcher = LOCK_PATTERN.matcher(line); + if (matcher.matches()) { + if (verbose) { + System.out.println("locked_line='" + line + "'"); + } + match_list[match_cnt] = new String(line); + match_cnt++; + + matcher = HEADER_RUNNABLE_PATTERN.matcher(header_line); + if (!matcher.matches()) { + // It's strange, but a locked line can also + // match the HEADER_WAITING_PATTERN. + matcher = HEADER_WAITING_PATTERN.matcher(header_line); + if (!matcher.matches()) { + System.err.println(); + System.err.println("ERROR: header line does " + + "not match runnable or waiting patterns."); + System.err.println("ERROR: header_line='" + + header_line + "'"); + System.err.println("ERROR: locked_line='" + line + "'"); + error_cnt++; + } + } + + matcher = THREAD_STATE_RUNNABLE_PATTERN.matcher(thread_state_line); + if (!matcher.matches()) { + // It's strange, but a locked line can also + // match the THREAD_STATE_BLOCKED_PATTERN. + matcher = THREAD_STATE_BLOCKED_PATTERN.matcher( + thread_state_line); + if (!matcher.matches()) { + System.err.println(); + System.err.println("ERROR: thread state line does not " + + "match runnable or waiting patterns."); + System.err.println("ERROR: " + "thread_state_line='" + + thread_state_line + "'"); + System.err.println("ERROR: locked_line='" + line + "'"); + error_cnt++; + } + } + + // Have everything we need from this thread stack + // that matches the LOCK_PATTERN. + have_header_line = false; + have_thread_state_line = false; + return true; + } + + return false; + } + + // Process the waiting line here if we found one. + // + // Example: + // "ContendingThread-2" #22 prio=5 os_prio=64 tid=0x00000000007b9800 nid=0x30 waiting for monitor entry [0xfffffd7fc1010000] + // java.lang.Thread.State: BLOCKED (on object monitor) + // at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:67) + // - waiting to lock <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1) + // at java.lang.Thread.run(Thread.java:745) + // + static boolean checkWaitingLine(String line) { + Matcher matcher = WAITING_PATTERN.matcher(line); + if (matcher.matches()) { + if (verbose) { + System.out.println("waiting_line='" + line + "'"); + } + + matcher = HEADER_WAITING_PATTERN.matcher(header_line); + if (!matcher.matches()) { + System.err.println(); + System.err.println("ERROR: header line does " + + "not match a waiting pattern."); + System.err.println("ERROR: header_line='" + header_line + "'"); + System.err.println("ERROR: waiting_line='" + line + "'"); + error_cnt++; + } + + matcher = THREAD_STATE_BLOCKED_PATTERN.matcher(thread_state_line); + if (!matcher.matches()) { + System.err.println(); + System.err.println("ERROR: thread state line " + + "does not match a waiting pattern."); + System.err.println("ERROR: thread_state_line='" + + thread_state_line + "'"); + System.err.println("ERROR: waiting_line='" + line + "'"); + error_cnt++; + } + + // Have everything we need from this thread stack + // that matches the WAITING_PATTERN. + have_header_line = false; + have_thread_state_line = false; + return true; + } + + return false; + } + + static void doSamples() throws Exception { + for (int count = 0; count < n_samples; count++) { + match_cnt = 0; + // verbose mode or an error has a lot of output so add more space + if (verbose || error_cnt > 0) System.out.println(); + System.out.println("Sample #" + count); + + // We don't use the ProcessTools, OutputBuffer or + // OutputAnalyzer classes from the testlibrary because + // we have a complicated multi-line parse to perform + // on a narrow subset of the JSTACK output. + // + // - we only care about stack traces that match + // HEADER_PREFIX_PATTERN; only two should match + // - we care about at most three lines from each stack trace + // - if both stack traces match LOCKED_PATTERN, then that's + // a failure and we report it + // - for a stack trace that matches LOCKED_PATTERN, we verify: + // - the header line matches HEADER_RUNNABLE_PATTERN + // or HEADER_WAITING_PATTERN + // - the thread state line matches THREAD_STATE_BLOCKED_PATTERN + // or THREAD_STATE_RUNNABLE_PATTERN + // - we report any mismatches as failures + // - for a stack trace that matches WAITING_PATTERN, we verify: + // - the header line matches HEADER_WAITING_PATTERN + // - the thread state line matches THREAD_STATE_BLOCKED_PATTERN + // - we report any mismatches as failures + // - the stack traces that match HEADER_PREFIX_PATTERN may + // not match either LOCKED_PATTERN or WAITING_PATTERN + // because we might observe the thread outside of + // monitor operations; this is not considered a failure + // + // When we do observe LOCKED_PATTERN or WAITING_PATTERN, + // then we are checking the header and thread state patterns + // that occurred earlier in the current stack trace that + // matched HEADER_PREFIX_PATTERN. We don't use data from + // stack traces that don't match HEADER_PREFIX_PATTERN and + // we don't mix data between the two stack traces that do + // match HEADER_PREFIX_PATTERN. + // + Process process = new ProcessBuilder(JSTACK, PID) + .redirectErrorStream(true).start(); + + BufferedReader reader = new BufferedReader(new InputStreamReader( + process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + Matcher matcher = null; + + // process the header line here + if (!have_header_line) { + matcher = HEADER_PREFIX_PATTERN.matcher(line); + if (matcher.matches()) { + if (verbose) { + System.out.println(); + System.out.println("header='" + line + "'"); + } + header_line = new String(line); + have_header_line = true; + continue; + } + continue; // skip until have a header line + } + + // process the thread state line here + if (!have_thread_state_line) { + matcher = THREAD_STATE_PREFIX_PATTERN.matcher(line); + if (matcher.matches()) { + if (verbose) { + System.out.println("thread_state='" + line + "'"); + } + thread_state_line = new String(line); + have_thread_state_line = true; + continue; + } + continue; // skip until we have a thread state line + } + + // process the locked line here if we find one + if (checkLockedLine(line)) { + continue; + } + + // process the waiting line here if we find one + if (checkWaitingLine(line)) { + continue; + } + + // process the blank line here if we find one + if (checkBlankLine(line)) { + continue; + } + } + process.waitFor(); + + if (match_cnt == 2) { + if (match_list[0].equals(match_list[1])) { + System.err.println(); + System.err.println("ERROR: matching lock lines:"); + System.err.println("ERROR: line[0]'" + match_list[0] + "'"); + System.err.println("ERROR: line[1]'" + match_list[1] + "'"); + error_cnt++; + } + } + + // slight delay between jstack launches + Thread.sleep(500); + } + } + + // This helper relies on RuntimeMXBean.getName() returning a string + // that looks like this: 5436@mt-haku + // + // The testlibrary has tryFindJvmPid(), but that uses a separate + // process which is much more expensive for finding out your own PID. + // + static String getPid() { + RuntimeMXBean runtimebean = ManagementFactory.getRuntimeMXBean(); + String vmname = runtimebean.getName(); + int i = vmname.indexOf('@'); + if (i != -1) { + vmname = vmname.substring(0, i); + } + return vmname; + } + + static void usage() { + System.err.println("Usage: " + + "java TestThreadDumpMonitorContention [-v] [n_samples]"); + System.exit(1); + } +} From 7142b60efc2f5d9f398d416897127d7d5f144e6a Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Fri, 30 May 2014 19:13:07 +0200 Subject: [PATCH 12/18] 8044398: Attach code should propagate errors in Diagnostic Commands as errors Reviewed-by: dcubed, mgronlun --- hotspot/src/share/vm/services/attachListener.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/services/attachListener.cpp b/hotspot/src/share/vm/services/attachListener.cpp index 9d68175518a..2321f084dc5 100644 --- a/hotspot/src/share/vm/services/attachListener.cpp +++ b/hotspot/src/share/vm/services/attachListener.cpp @@ -162,10 +162,7 @@ static jint jcmd(AttachOperation* op, outputStream* out) { java_lang_Throwable::print(PENDING_EXCEPTION, out); out->cr(); CLEAR_PENDING_EXCEPTION; - // The exception has been printed on the output stream - // If the JVM returns JNI_ERR, the attachAPI throws a generic I/O - // exception and the content of the output stream is not processed. - // By returning JNI_OK, the exception will be displayed on the client side + return JNI_ERR; } return JNI_OK; } From d48bda2c524b80515f4a7bbf6aec581b2116cfb1 Mon Sep 17 00:00:00 2001 From: Katja Kantserova Date: Mon, 2 Jun 2014 11:20:14 +0200 Subject: [PATCH 13/18] 8043915: Tests get ClassNotFoundException: com.oracle.java.testlibrary.StreamPumper Reviewed-by: sla, allwin --- hotspot/test/serviceability/ParserTest.java | 4 ++-- .../test/serviceability/attach/AttachWithStalePidFile.java | 2 +- hotspot/test/serviceability/dcmd/DynLibDcmdTest.java | 2 +- hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java | 2 +- .../serviceability/jvmti/TestRedefineWithUnresolvedClass.java | 2 +- hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java | 1 + .../serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java | 2 +- hotspot/test/testlibrary/ctw/test/ClassesDirTest.java | 4 ++-- hotspot/test/testlibrary/ctw/test/ClassesListTest.java | 4 ++-- hotspot/test/testlibrary/ctw/test/JarDirTest.java | 4 ++-- hotspot/test/testlibrary/ctw/test/JarsTest.java | 4 ++-- 11 files changed, 16 insertions(+), 15 deletions(-) diff --git a/hotspot/test/serviceability/ParserTest.java b/hotspot/test/serviceability/ParserTest.java index 63ee9210e40..8db151f4d3f 100644 --- a/hotspot/test/serviceability/ParserTest.java +++ b/hotspot/test/serviceability/ParserTest.java @@ -22,10 +22,10 @@ */ /* - * @test ParserTest + * @test * @summary Test that the diagnostic command arguemnt parser works * @library /testlibrary /testlibrary/whitebox - * @build ParserTest + * @build ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.parser.* * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ParserTest */ diff --git a/hotspot/test/serviceability/attach/AttachWithStalePidFile.java b/hotspot/test/serviceability/attach/AttachWithStalePidFile.java index fa74379b3a7..69dff6d9888 100644 --- a/hotspot/test/serviceability/attach/AttachWithStalePidFile.java +++ b/hotspot/test/serviceability/attach/AttachWithStalePidFile.java @@ -27,7 +27,7 @@ * @key regression * @summary Regression test for attach issue where stale pid files in /tmp lead to connection issues * @library /testlibrary - * @compile AttachWithStalePidFileTarget.java + * @build com.oracle.java.testlibrary.* AttachWithStalePidFileTarget * @run main AttachWithStalePidFile */ diff --git a/hotspot/test/serviceability/dcmd/DynLibDcmdTest.java b/hotspot/test/serviceability/dcmd/DynLibDcmdTest.java index a5c71839952..069b06f1937 100644 --- a/hotspot/test/serviceability/dcmd/DynLibDcmdTest.java +++ b/hotspot/test/serviceability/dcmd/DynLibDcmdTest.java @@ -29,7 +29,7 @@ import com.oracle.java.testlibrary.Platform; * @test * @summary Test of VM.dynlib diagnostic command via MBean * @library /testlibrary - * @compile DcmdUtil.java + * @build com.oracle.java.testlibrary.* DcmdUtil * @run main DynLibDcmdTest */ diff --git a/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java b/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java index ec33d813541..9acefe511f5 100644 --- a/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java +++ b/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java @@ -29,7 +29,7 @@ import com.oracle.java.testlibrary.*; * @test * @bug 8027230 * @library /testlibrary - * @build GetObjectSizeOverflowAgent + * @build ClassFileInstaller com.oracle.java.testlibrary.* GetObjectSizeOverflowAgent * @run main ClassFileInstaller GetObjectSizeOverflowAgent * @run main GetObjectSizeOverflow */ diff --git a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java index 4f929c49af6..14ffea90bd5 100644 --- a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java +++ b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java @@ -26,7 +26,7 @@ * @summary Redefine a class with an UnresolvedClass reference in the constant pool. * @bug 8035150 * @library /testlibrary - * @build UnresolvedClassAgent com.oracle.java.testlibrary.ProcessTools com.oracle.java.testlibrary.OutputAnalyzer + * @build com.oracle.java.testlibrary.* UnresolvedClassAgent * @run main TestRedefineWithUnresolvedClass */ diff --git a/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java b/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java index bd743ab1c1f..6f4b2fd689a 100644 --- a/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java +++ b/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java @@ -26,6 +26,7 @@ * @bug 8028623 * @summary Test hashing of extended characters in Serviceability Agent. * @library /testlibrary + * @build com.oracle.java.testlibrary.* * @compile -encoding utf8 Test8028623.java * @run main Test8028623 */ diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java index df6ecb28f14..eeeecba0da4 100644 --- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java +++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java @@ -44,7 +44,7 @@ import com.oracle.java.testlibrary.ProcessTools; * @key regression * @summary Regression test for hprof export issue due to large heaps (>2G) * @library /testlibrary - * @compile JMapHProfLargeHeapProc.java + * @build com.oracle.java.testlibrary.* JMapHProfLargeHeapProc * @run main JMapHProfLargeHeapTest */ diff --git a/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java b/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java index ae5eaf0f2e4..cc28d403400 100644 --- a/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java +++ b/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java @@ -22,10 +22,10 @@ */ /* - * @test ClassesDirTest + * @test * @bug 8012447 * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src - * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesDirTest Foo Bar + * @build ClassFileInstaller sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar * @run main ClassesDirTest prepare * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes diff --git a/hotspot/test/testlibrary/ctw/test/ClassesListTest.java b/hotspot/test/testlibrary/ctw/test/ClassesListTest.java index a98cd53a3f6..64c5203cf10 100644 --- a/hotspot/test/testlibrary/ctw/test/ClassesListTest.java +++ b/hotspot/test/testlibrary/ctw/test/ClassesListTest.java @@ -22,10 +22,10 @@ */ /* - * @test ClassesListTest + * @test * @bug 8012447 * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src - * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesListTest Foo Bar + * @build ClassFileInstaller sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar * @run main ClassesListTest prepare * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst diff --git a/hotspot/test/testlibrary/ctw/test/JarDirTest.java b/hotspot/test/testlibrary/ctw/test/JarDirTest.java index 76f682fd755..abc5a0843d2 100644 --- a/hotspot/test/testlibrary/ctw/test/JarDirTest.java +++ b/hotspot/test/testlibrary/ctw/test/JarDirTest.java @@ -22,10 +22,10 @@ */ /* - * @test JarDirTest + * @test * @bug 8012447 * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src - * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarDirTest Foo Bar + * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar * @run main JarDirTest prepare * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/* diff --git a/hotspot/test/testlibrary/ctw/test/JarsTest.java b/hotspot/test/testlibrary/ctw/test/JarsTest.java index 04792729f4e..c9bfb303132 100644 --- a/hotspot/test/testlibrary/ctw/test/JarsTest.java +++ b/hotspot/test/testlibrary/ctw/test/JarsTest.java @@ -22,10 +22,10 @@ */ /* - * @test JarsTest + * @test * @bug 8012447 * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src - * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarsTest Foo Bar + * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar * @run main JarsTest prepare * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar From 870bec251ca6c600c4365c40553ea0dda6d9ded7 Mon Sep 17 00:00:00 2001 From: Ron Durbin Date: Mon, 2 Jun 2014 09:30:08 -0700 Subject: [PATCH 14/18] 8038132: jprt bundles have libjsig.dylib in different place on OSX The build of Hotspot should not remove the symlinks for libjsig. Reviewed-by: dcubed, dholmes --- hotspot/make/bsd/makefiles/universal.gmk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hotspot/make/bsd/makefiles/universal.gmk b/hotspot/make/bsd/makefiles/universal.gmk index d1136a86806..44d57d963aa 100644 --- a/hotspot/make/bsd/makefiles/universal.gmk +++ b/hotspot/make/bsd/makefiles/universal.gmk @@ -74,19 +74,21 @@ $(UNIVERSAL_COPY_LIST): # Replace arch specific binaries with universal binaries +# Do not touch jre/lib/{client,server}/libjsig.$(LIBRARY_SUFFIX) +# That symbolic link belongs to the 'jdk' build. export_universal: $(RM) -r $(EXPORT_PATH)/jre/lib/{i386,amd64} $(RM) -r $(JDK_IMAGE_DIR)/jre/lib/{i386,amd64} - $(RM) $(JDK_IMAGE_DIR)/jre/lib/{client,server}/libjsig.$(LIBRARY_SUFFIX) ($(CD) $(EXPORT_PATH) && \ $(TAR) -cf - *) | \ ($(CD) $(JDK_IMAGE_DIR) && $(TAR) -xpf -) # Overlay universal binaries +# Do not touch jre/lib/{client,server}/libjsig.$(LIBRARY_SUFFIX) +# That symbolic link belongs to the 'jdk' build. copy_universal: $(RM) -r $(JDK_IMAGE_DIR)$(COPY_SUBDIR)/jre/lib/{i386,amd64} - $(RM) $(JDK_IMAGE_DIR)$(COPY_SUBDIR)/jre/lib/{client,server}/libjsig.$(LIBRARY_SUFFIX) ($(CD) $(EXPORT_PATH)$(COPY_SUBDIR) && \ $(TAR) -cf - *) | \ ($(CD) $(JDK_IMAGE_DIR)$(COPY_SUBDIR) && $(TAR) -xpf -) From fd282f6e9ac62360eb783e59e19fa6dcc26e840b Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Mon, 2 Jun 2014 19:08:18 +0200 Subject: [PATCH 15/18] 8044364: runtime/RedefineFinalizer test fails on windows Rewrote the test in pure Java, added RedefineClassHelper utility class Reviewed-by: coleenp, allwin, gtriantafill, dsamersoff --- .../test/runtime/RedefineFinalizer/Agent.java | 94 ------------------- .../runtime/RedefineFinalizer/MartyrSon.java | 28 ------ .../{Main.java => RedefineFinalizer.java} | 48 ++++++++-- .../runtime/RedefineFinalizer/manifest.mf | 5 - .../test/runtime/RedefineFinalizer/testme.sh | 49 ---------- .../test/testlibrary/RedefineClassHelper.java | 79 ++++++++++++++++ .../RedefineClassTest.java} | 33 +++++-- 7 files changed, 145 insertions(+), 191 deletions(-) delete mode 100644 hotspot/test/runtime/RedefineFinalizer/Agent.java delete mode 100644 hotspot/test/runtime/RedefineFinalizer/MartyrSon.java rename hotspot/test/runtime/RedefineFinalizer/{Main.java => RedefineFinalizer.java} (52%) delete mode 100644 hotspot/test/runtime/RedefineFinalizer/manifest.mf delete mode 100644 hotspot/test/runtime/RedefineFinalizer/testme.sh create mode 100644 hotspot/test/testlibrary/RedefineClassHelper.java rename hotspot/test/{runtime/RedefineFinalizer/Martyr.java => testlibrary_tests/RedefineClassTest.java} (55%) diff --git a/hotspot/test/runtime/RedefineFinalizer/Agent.java b/hotspot/test/runtime/RedefineFinalizer/Agent.java deleted file mode 100644 index 92b274ab02c..00000000000 --- a/hotspot/test/runtime/RedefineFinalizer/Agent.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2014, 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. - */ - -import java.lang.instrument.Instrumentation; -import java.lang.instrument.ClassDefinition; - -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Label; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; - -public class Agent implements Opcodes { - - private static byte[] makeNewMartyr() { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - - cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "Martyr", null, "java/lang/Object", null); - cw.visitSource(null, null); - - { - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - Label lab0 = new Label(); - mv.visitLabel(lab0); - mv.visitLineNumber(1, lab0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - mv = cw.visitMethod(ACC_PUBLIC, "getName", "()Ljava/lang/String;", null, null); - mv.visitCode(); - Label lab0 = new Label(); - mv.visitLabel(lab0); - mv.visitLineNumber(6, lab0); - mv.visitLdcInsn("Redefinition done"); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - mv = cw.visitMethod(ACC_PROTECTED, "finalize", "()V", null, null); - mv.visitCode(); - Label lab0 = new Label(); - mv.visitLabel(lab0); - mv.visitLineNumber(8, lab0); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("Finalizer called"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 1); - mv.visitEnd(); - } - - cw.visitEnd(); - return cw.toByteArray(); - } - - - public static void premain(String args, Instrumentation inst) throws Exception { - agentmain(args, inst); - } - - public static void agentmain(String args, Instrumentation inst) throws Exception { - ClassDefinition martyrDef = - new ClassDefinition(Class.forName("Martyr"), makeNewMartyr()); - inst.redefineClasses(martyrDef); - } -} diff --git a/hotspot/test/runtime/RedefineFinalizer/MartyrSon.java b/hotspot/test/runtime/RedefineFinalizer/MartyrSon.java deleted file mode 100644 index 22fd4e3e275..00000000000 --- a/hotspot/test/runtime/RedefineFinalizer/MartyrSon.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2014, 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. - */ - -class MartyrSon extends Martyr { - public String getName() { - return super.getName(); - } -} diff --git a/hotspot/test/runtime/RedefineFinalizer/Main.java b/hotspot/test/runtime/RedefineFinalizer/RedefineFinalizer.java similarity index 52% rename from hotspot/test/runtime/RedefineFinalizer/Main.java rename to hotspot/test/runtime/RedefineFinalizer/RedefineFinalizer.java index 77f9f926d75..227b9e8186e 100644 --- a/hotspot/test/runtime/RedefineFinalizer/Main.java +++ b/hotspot/test/runtime/RedefineFinalizer/RedefineFinalizer.java @@ -21,14 +21,44 @@ * questions. */ -public class Main { - public static void main(String[] args) { - try { - MartyrSon m = new MartyrSon(); - System.out.println(m.getName()); - System.runFinalization(); - } catch (Throwable e) { - e.printStackTrace(); - } +/* + * @test + * @bug 6904403 + * @summary Don't assert if we redefine finalize method + * @library /testlibrary + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineFinalizer + */ + +/* + * Regression test for hitting: + * + * assert(f == k->has_finalizer()) failed: inconsistent has_finalizer + * + * when redefining finalizer method + */ +public class RedefineFinalizer { + + public static String newB = + "class RedefineFinalizer$B {" + + " protected void finalize() { " + + " System.out.println(\"Finalizer called\");" + + " }" + + "}"; + + public static void main(String[] args) throws Exception { + RedefineClassHelper.redefineClass(B.class, newB); + + A a = new A(); + } + + static class A extends B { + } + + static class B { + protected void finalize() { + // should be empty + } } } diff --git a/hotspot/test/runtime/RedefineFinalizer/manifest.mf b/hotspot/test/runtime/RedefineFinalizer/manifest.mf deleted file mode 100644 index e337a65c01a..00000000000 --- a/hotspot/test/runtime/RedefineFinalizer/manifest.mf +++ /dev/null @@ -1,5 +0,0 @@ -Main-Class: Main -Agent-Class: Agent -Can-Redefine-Classes: true -Can-Retransform-Classes: true -Premain-Class: Agent diff --git a/hotspot/test/runtime/RedefineFinalizer/testme.sh b/hotspot/test/runtime/RedefineFinalizer/testme.sh deleted file mode 100644 index 3b50f5050db..00000000000 --- a/hotspot/test/runtime/RedefineFinalizer/testme.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2014 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 6904403 -# @summary Don't assert if we redefine finalize method -# @run shell testme.sh - -# This test shouldn't provoke and assert(f == k->has_finalizer()) failed: inconsistent has_finalizer - -. ${TESTSRC}/../../test_env.sh - -JAVAC=${COMPILEJAVA}${FS}bin${FS}javac -JAR=${COMPILEJAVA}${FS}bin${FS}jar -JAVA=${TESTJAVA}${FS}bin${FS}java - -TOOLS_JAR=${TESTJAVA}${FS}lib${FS}tools.jar - -cp ${TESTSRC}${FS}*.java . -${JAVAC} -XDignore.symbol.file -classpath ${TOOLS_JAR} -sourcepath ${TESTSRC} *.java -if [ $? -eq 1 ] - then - echo "Compilation failed" - exit -fi - -${JAR} cvfm testcase.jar ${TESTSRC}/manifest.mf . -${JAVA} -Xbootclasspath/a:${TOOLS_JAR} -javaagent:${PWD}/testcase.jar Main diff --git a/hotspot/test/testlibrary/RedefineClassHelper.java b/hotspot/test/testlibrary/RedefineClassHelper.java new file mode 100644 index 00000000000..accc5447a67 --- /dev/null +++ b/hotspot/test/testlibrary/RedefineClassHelper.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, 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. + */ + +import java.io.PrintWriter; +import java.lang.instrument.*; +import com.oracle.java.testlibrary.*; + +/* + * Helper class to write tests that redefine classes. + * When main method is run, it will create a redefineagent.jar that can be used + * with the -javaagent option to support redefining classes in jtreg tests. + * + * See sample test in test/testlibrary_tests/RedefineClassTest.java + */ +public class RedefineClassHelper { + + public static Instrumentation instrumentation; + public static void premain(String agentArgs, Instrumentation inst) { + instrumentation = inst; + } + + /** + * Redefine a class + * + * @param clazz Class to redefine + * @param javacode String with the new java code for the class to be redefined + */ + public static void redefineClass(Class clazz, String javacode) throws Exception { + byte[] bytecode = InMemoryJavaCompiler.compile(clazz.getName(), javacode); + redefineClass(clazz, bytecode); + } + + /** + * Redefine a class + * + * @param clazz Class to redefine + * @param bytecode byte[] with the new class + */ + public static void redefineClass(Class clazz, byte[] bytecode) throws Exception { + instrumentation.redefineClasses(new ClassDefinition(clazz, bytecode)); + } + + /** + * Main method to be invoked before test to create the redefineagent.jar + */ + public static void main(String[] args) throws Exception { + ClassFileInstaller.main("RedefineClassHelper"); + + PrintWriter pw = new PrintWriter("MANIFEST.MF"); + pw.println("Premain-Class: RedefineClassHelper"); + pw.println("Can-Redefine-Classes: true"); + pw.close(); + + sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); + if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineClassHelper.class" })) { + throw new Exception("jar operation failed"); + } + } +} diff --git a/hotspot/test/runtime/RedefineFinalizer/Martyr.java b/hotspot/test/testlibrary_tests/RedefineClassTest.java similarity index 55% rename from hotspot/test/runtime/RedefineFinalizer/Martyr.java rename to hotspot/test/testlibrary_tests/RedefineClassTest.java index 95f8ff2e056..e812e43cded 100644 --- a/hotspot/test/runtime/RedefineFinalizer/Martyr.java +++ b/hotspot/test/testlibrary_tests/RedefineClassTest.java @@ -21,13 +21,34 @@ * questions. */ -public class Martyr { - public String getName() { - return "Redefinition NOT done"; +/* + * @test + * @library /testlibrary + * @summary Proof of concept test for RedefineClassHelper + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineClassTest + */ + +import static com.oracle.java.testlibrary.Asserts.*; +import com.oracle.java.testlibrary.*; + +/* + * Proof of concept test for the test utility class RedefineClassHelper + */ +public class RedefineClassTest { + + public static String newClass = "class RedefineClassTest$A { public int Method() { return 2; } }"; + public static void main(String[] args) throws Exception { + A a = new A(); + assertTrue(a.Method() == 1); + RedefineClassHelper.redefineClass(A.class, newClass); + assertTrue(a.Method() == 2); } - protected void finalize() { - // should be empty + static class A { + public int Method() { + return 1; + } } - } From 489a26ec8e8fc0c5afd0a871b6df0749176767ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 3 Jun 2014 09:44:54 +0200 Subject: [PATCH 16/18] 8044531: Event based tracing locks to rank as leafs where possible Reviewed-by: dcubed, dholmes --- hotspot/src/share/vm/runtime/mutexLocker.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 136bc4d28fe..439bb40c7d4 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -280,10 +280,10 @@ void mutex_init() { #ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true); - def(JfrBuffer_lock , Mutex, nonleaf+1, true); - def(JfrThreadGroups_lock , Mutex, nonleaf+1, true); - def(JfrStream_lock , Mutex, nonleaf+2, true); - def(JfrStacktrace_lock , Mutex, special, true ); + def(JfrBuffer_lock , Mutex, leaf, true); + def(JfrThreadGroups_lock , Mutex, leaf, true); + def(JfrStream_lock , Mutex, nonleaf, true); + def(JfrStacktrace_lock , Mutex, special, true); #endif } From 36d332413dc3b86743f46fe5872acbb877773633 Mon Sep 17 00:00:00 2001 From: Mikhailo Seledtsov Date: Mon, 2 Jun 2014 21:36:59 -0400 Subject: [PATCH 17/18] 8038587: [TESTBUG] Create CDS tests to exercise region sizes and base address Added new tests to cover missing CDS basic funtions Reviewed-by: coleenp, ctornqvi --- .../SharedArchiveFile/LimitSharedSizes.java | 93 ++++++++++++++++++ .../SharedArchiveFile/SharedBaseAddress.java | 77 +++++++++++++++ .../SpaceUtilizationCheck.java | 96 +++++++++++++++++++ 3 files changed, 266 insertions(+) create mode 100644 hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/SharedBaseAddress.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/SpaceUtilizationCheck.java diff --git a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java new file mode 100644 index 00000000000..dff619248ec --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* @ignore JDK-8043896 + * @test LimitSharedSizes + * @summary Test handling of limits on shared space size + * @library /testlibrary + * @run main LimitSharedSizes + */ + +import com.oracle.java.testlibrary.*; + +public class LimitSharedSizes { + private static class SharedSizeTestData { + public String optionName; + public String optionValue; + public String expectedErrorMsg; + + public SharedSizeTestData(String name, String value, String msg) { + optionName = name; + optionValue = value; + expectedErrorMsg = msg; + } + } + + private static final SharedSizeTestData[] testTable = { + // values in this part of the test table should cause failure + // (shared space sizes are deliberately too small) + new SharedSizeTestData("-XX:SharedReadOnlySize", "4M", "read only"), + new SharedSizeTestData("-XX:SharedReadWriteSize","4M", "read write"), + + // Known issue, JDK-8038422 (assert() on Windows) + // new SharedSizeTestData("-XX:SharedMiscDataSize", "500k", "miscellaneous data"), + + // This will cause a VM crash; commenting out for now; see bug JDK-8038268 + // @ignore JDK-8038268 + // new SharedSizeTestData("-XX:SharedMiscCodeSize", "20k", "miscellaneous code"), + + // these values are larger than default ones, but should + // be acceptable and not cause failure + new SharedSizeTestData("-XX:SharedReadOnlySize", "20M", null), + new SharedSizeTestData("-XX:SharedReadWriteSize", "20M", null), + new SharedSizeTestData("-XX:SharedMiscDataSize", "20M", null), + new SharedSizeTestData("-XX:SharedMiscCodeSize", "20M", null) + }; + + public static void main(String[] args) throws Exception { + String fileName = "test.jsa"; + + for (SharedSizeTestData td : testTable) { + String option = td.optionName + "=" + td.optionValue; + System.out.println("testing option <" + option + ">"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./" + fileName, + option, + "-Xshare:dump"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + if (td.expectedErrorMsg != null) { + output.shouldContain("The shared " + td.expectedErrorMsg + + " space is not large enough"); + + output.shouldHaveExitValue(2); + } else { + output.shouldNotContain("space is not large enough"); + output.shouldHaveExitValue(0); + } + } + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/SharedBaseAddress.java b/hotspot/test/runtime/SharedArchiveFile/SharedBaseAddress.java new file mode 100644 index 00000000000..388fe7d0659 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/SharedBaseAddress.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, 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 SharedBaseAddress + * @summary Test variety of values for SharedBaseAddress, making sure + * VM handles normal values as well as edge values w/o a crash. + * @library /testlibrary + * @run main SharedBaseAddress + */ + +import com.oracle.java.testlibrary.*; + +public class SharedBaseAddress { + + // shared base address test table + private static final String[] testTable = { + "1g", "8g", "64g","512g", "4t", + "32t", "128t", "0", + "1", "64k", "64M" + }; + + public static void main(String[] args) throws Exception { + // Known issue on Solaris-Sparc + // @ignore JDK-8044600 + if (Platform.isSolaris() && Platform.isSparc()) + return; + + for (String testEntry : testTable) { + System.out.println("sharedBaseAddress = " + testEntry); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=test.jsa", + "-XX:SharedBaseAddress=" + testEntry, + "-Xshare:dump"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldContain("Loading classes to share"); + + try { + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=test.jsa", + "-Xshare:on", + "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("sharing"); + output.shouldHaveExitValue(0); + } catch (RuntimeException e) { + output.shouldContain("Unable to use shared archive"); + output.shouldHaveExitValue(1); + } + } + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/SpaceUtilizationCheck.java b/hotspot/test/runtime/SharedArchiveFile/SpaceUtilizationCheck.java new file mode 100644 index 00000000000..a95979f355c --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/SpaceUtilizationCheck.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014, 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 SpaceUtilizationCheck + * @summary Check if the space utilization for shared spaces is adequate + * @library /testlibrary + * @run main SpaceUtilizationCheck + */ + +import com.oracle.java.testlibrary.*; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.ArrayList; +import java.lang.Integer; + +public class SpaceUtilizationCheck { + // Minimum allowed utilization value (percent) + // The goal is to have this number to be 50% for RO and RW regions + // Once that feature is implemented, increase the MIN_UTILIZATION to 50 + private static final int MIN_UTILIZATION = 30; + + // Only RO and RW regions are considered for this check, since they + // currently account for the bulk of the shared space + private static final int NUMBER_OF_CHECKED_SHARED_REGIONS = 2; + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./test.jsa", + "-Xshare:dump"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + String stdout = output.getStdout(); + ArrayList utilization = findUtilization(stdout); + + if (utilization.size() != NUMBER_OF_CHECKED_SHARED_REGIONS ) + throw new RuntimeException("The output format of sharing summary has changed"); + + for(String str : utilization) { + int value = Integer.parseInt(str); + if (value < MIN_UTILIZATION) { + System.out.println(stdout); + throw new RuntimeException("Utilization for one of the regions" + + "is below a threshold of " + MIN_UTILIZATION + "%"); + } + } + } + + public static ArrayList findUtilization(String input) { + ArrayList regions = filterRegionsOfInterest(input.split("\n")); + return filterByPattern(filterByPattern(regions, "bytes \\[.*% used\\]"), "\\d+"); + } + + private static ArrayList filterByPattern(Iterable input, String pattern) { + ArrayList result = new ArrayList(); + for (String str : input) { + Matcher matcher = Pattern.compile(pattern).matcher(str); + if (matcher.find()) { + result.add(matcher.group()); + } + } + return result; + } + + private static ArrayList filterRegionsOfInterest(String[] inputLines) { + ArrayList result = new ArrayList(); + for (String str : inputLines) { + if (str.contains("ro space:") || str.contains("rw space:")) { + result.add(str); + } + } + return result; + } +} From 9c1843a7c34fb09a125307bc7b613309f154b6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Wed, 4 Jun 2014 14:16:20 +0200 Subject: [PATCH 18/18] 8044768: Backout fix for JDK-8040807 Reviewed-by: brutisso, ehelin --- .../vm/gc_implementation/g1/concurrentMark.cpp | 4 ++-- .../vm/gc_implementation/g1/concurrentMark.hpp | 4 +--- .../vm/gc_implementation/g1/g1CollectedHeap.cpp | 16 +++++++++++----- hotspot/src/share/vm/runtime/java.cpp | 9 +++++++-- hotspot/src/share/vm/runtime/thread.cpp | 10 ++++++++-- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 7478a1e163c..24c62d775bd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -901,7 +901,7 @@ void ConcurrentMark::checkpointRootsInitialPre() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectorPolicy* g1p = g1h->g1_policy(); - clear_has_aborted(); + _has_aborted = false; #ifndef PRODUCT if (G1PrintReachableAtInitialMark) { @@ -3261,7 +3261,7 @@ void ConcurrentMark::abort() { } _first_overflow_barrier_sync.abort(); _second_overflow_barrier_sync.abort(); - set_has_aborted(); + _has_aborted = true; SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); satb_mq_set.abandon_partial_marking(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index c4dbcda557f..9d049a2a255 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -822,9 +822,7 @@ public: // Called to abort the marking cycle after a Full GC takes place. void abort(); - bool has_aborted() { return _has_aborted; } - void set_has_aborted() { _has_aborted = true; } - void clear_has_aborted() { _has_aborted = false; } + bool has_aborted() { return _has_aborted; } // This prints the global/local fingers. It is used for debugging. NOT_PRODUCT(void print_finger();) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 6e565c11d99..83f819b3919 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -2174,14 +2174,20 @@ jint G1CollectedHeap::initialize() { } void G1CollectedHeap::stop() { - // Abort any ongoing concurrent mark and stop all concurrent threads. - // We do this to make sure these threads do not continue to execute - // and access resources (e.g. gclog_or_tty) that are destroyed during - // shutdown. - _cm->set_has_aborted(); +#if 0 + // Stopping concurrent worker threads is currently disabled until + // some bugs in concurrent mark has been resolve. Without fixing + // those bugs first we risk haning during VM exit when trying to + // stop these threads. + + // Abort any ongoing concurrent root region scanning and stop all + // concurrent threads. We do this to make sure these threads do + // not continue to execute and access resources (e.g. gclog_or_tty) + // that are destroyed during shutdown. _cm->root_regions()->abort(); _cm->root_regions()->wait_until_scan_finished(); stop_conc_gc_threads(); +#endif } size_t G1CollectedHeap::conservative_max_heap_alignment() { diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 3a075117afe..e852b56ef54 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -501,6 +501,9 @@ void before_exit(JavaThread * thread) { os::infinite_sleep(); } + // Stop any ongoing concurrent GC work + Universe::heap()->stop(); + // Terminate watcher thread - must before disenrolling any periodic task if (PeriodicTask::num_tasks() > 0) WatcherThread::stop(); @@ -515,8 +518,10 @@ void before_exit(JavaThread * thread) { StatSampler::disengage(); StatSampler::destroy(); - // Stop concurrent GC threads - Universe::heap()->stop(); + // We do not need to explicitly stop concurrent GC threads because the + // JVM will be taken down at a safepoint when such threads are inactive -- + // except for some concurrent G1 threads, see (comment in) + // Threads::destroy_vm(). // Print GC/heap related information. if (PrintGCDetails) { diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 1716ed5e572..1a0849a29d1 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -3968,8 +3968,14 @@ bool Threads::destroy_vm() { // GC vm_operations can get caught at the safepoint, and the // heap is unparseable if they are caught. Grab the Heap_lock // to prevent this. The GC vm_operations will not be able to - // queue until after the vm thread is dead. After this point, - // we'll never emerge out of the safepoint before the VM exits. + // queue until after the vm thread is dead. + // After this point, we'll never emerge out of the safepoint before + // the VM exits, so concurrent GC threads do not need to be explicitly + // stopped; they remain inactive until the process exits. + // Note: some concurrent G1 threads may be running during a safepoint, + // but these will not be accessing the heap, just some G1-specific side + // data structures that are not accessed by any other threads but them + // after this point in a terminal safepoint. MutexLocker ml(Heap_lock);