# HG changeset patch # User coleenp # Date 1401638175 14400 # Node ID e996b2983c830b0636531a275509ab1a09c2c753 # Parent e6c4b47cd5e48d72b842b693daa69a5aaf7f74d9# Parent c55a7c2888f61ebbc4b46ef52ed7183ed9c6a4ca Merge diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -4359,9 +4359,15 @@ Method* m = k->lookup_method(vmSymbols::finalize_method_name(), vmSymbols::void_method_signature()); if (m != NULL && !m->is_empty_method()) { - f = true; + f = true; } - assert(f == k->has_finalizer(), "inconsistent has_finalizer"); + + // 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"); + } #endif // Check if this klass supports the java.lang.Cloneable interface diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Sun Jun 01 11:56:15 2014 -0400 @@ -1181,7 +1181,7 @@ 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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/memory/allocation.cpp --- a/hotspot/src/share/vm/memory/allocation.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/memory/allocation.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -563,6 +563,7 @@ _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 diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -1501,6 +1501,21 @@ 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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Sun Jun 01 11:56:15 2014 -0400 @@ -754,6 +754,11 @@ 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 @@ // 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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/oops/oopsHierarchy.hpp --- a/hotspot/src/share/vm/oops/oopsHierarchy.hpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/oops/oopsHierarchy.hpp Sun Jun 01 11:56:15 2014 -0400 @@ -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 @@ // 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 @@ 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 @@ 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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/runtime/objectMonitor.cpp --- a/hotspot/src/share/vm/runtime/objectMonitor.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -385,6 +385,15 @@ 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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/runtime/thread.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -1434,7 +1434,7 @@ _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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/runtime/vframe.cpp --- a/hotspot/src/share/vm/runtime/vframe.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/runtime/vframe.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -199,6 +199,7 @@ 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 @@ 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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/services/attachListener.cpp --- a/hotspot/src/share/vm/services/attachListener.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/services/attachListener.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -162,10 +162,7 @@ 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; } diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/services/memoryManager.cpp --- a/hotspot/src/share/vm/services/memoryManager.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/services/memoryManager.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/services/memoryPool.cpp --- a/hotspot/src/share/vm/services/memoryPool.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/services/memoryPool.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -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 @@ _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; diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/src/share/vm/utilities/debug.cpp --- a/hotspot/src/share/vm/utilities/debug.cpp Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/src/share/vm/utilities/debug.cpp Sun Jun 01 11:56:15 2014 -0400 @@ -263,13 +263,11 @@ 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" diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/TEST.groups --- a/hotspot/test/TEST.groups Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/test/TEST.groups Sun Jun 01 11:56:15 2014 -0400 @@ -81,6 +81,7 @@ 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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/runtime/CommandLine/TestHexArguments.java --- a/hotspot/test/runtime/CommandLine/TestHexArguments.java Fri May 30 13:46:02 2014 -0700 +++ b/hotspot/test/runtime/CommandLine/TestHexArguments.java Sun Jun 01 11:56:15 2014 -0400 @@ -35,14 +35,14 @@ 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"); } diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/runtime/RedefineFinalizer/Agent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineFinalizer/Agent.java Sun Jun 01 11:56:15 2014 -0400 @@ -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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/runtime/RedefineFinalizer/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineFinalizer/Main.java Sun Jun 01 11:56:15 2014 -0400 @@ -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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/runtime/RedefineFinalizer/Martyr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineFinalizer/Martyr.java Sun Jun 01 11:56:15 2014 -0400 @@ -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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/runtime/RedefineFinalizer/MartyrSon.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineFinalizer/MartyrSon.java Sun Jun 01 11:56:15 2014 -0400 @@ -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 -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/runtime/RedefineFinalizer/manifest.mf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineFinalizer/manifest.mf Sun Jun 01 11:56:15 2014 -0400 @@ -0,0 +1,5 @@ +Main-Class: Main +Agent-Class: Agent +Can-Redefine-Classes: true +Can-Retransform-Classes: true +Premain-Class: Agent diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/runtime/RedefineFinalizer/testme.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineFinalizer/testme.sh Sun Jun 01 11:56:15 2014 -0400 @@ -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 diff -r e6c4b47cd5e4 -r e996b2983c83 hotspot/test/runtime/Thread/TestThreadDumpMonitorContention.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/Thread/TestThreadDumpMonitorContention.java Sun Jun 01 11:56:15 2014 -0400 @@ -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); + } +}