# HG changeset patch # User alanb # Date 1572540358 0 # Node ID ca70299778b9ecc99fa62022046b4d13c142f7e8 # Parent 27c2d2a4b6953a15ee86c1d8ca5edf74524d543e 8205132: Degrade Thread.countStackFrames() to throw UOE Reviewed-by: mchung, dholmes, dcubed diff -r 27c2d2a4b695 -r ca70299778b9 make/hotspot/symbols/symbols-unix --- a/make/hotspot/symbols/symbols-unix Mon Oct 28 15:03:36 2019 +0100 +++ b/make/hotspot/symbols/symbols-unix Thu Oct 31 16:45:58 2019 +0000 @@ -46,7 +46,6 @@ JVM_ConstantPoolGetStringAt JVM_ConstantPoolGetTagAt JVM_ConstantPoolGetUTF8At -JVM_CountStackFrames JVM_CurrentThread JVM_CurrentTimeMillis JVM_DefineClass diff -r 27c2d2a4b695 -r ca70299778b9 src/hotspot/share/include/jvm.h --- a/src/hotspot/share/include/jvm.h Mon Oct 28 15:03:36 2019 +0100 +++ b/src/hotspot/share/include/jvm.h Thu Oct 31 16:45:58 2019 +0000 @@ -248,9 +248,6 @@ JNIEXPORT jobject JNICALL JVM_CurrentThread(JNIEnv *env, jclass threadClass); -JNIEXPORT jint JNICALL -JVM_CountStackFrames(JNIEnv *env, jobject thread); - JNIEXPORT void JNICALL JVM_Interrupt(JNIEnv *env, jobject thread); diff -r 27c2d2a4b695 -r ca70299778b9 src/hotspot/share/prims/jvm.cpp --- a/src/hotspot/share/prims/jvm.cpp Mon Oct 28 15:03:36 2019 +0100 +++ b/src/hotspot/share/prims/jvm.cpp Thu Oct 31 16:45:58 2019 +0000 @@ -3052,50 +3052,6 @@ return JNIHandles::make_local(env, jthread); JVM_END -class CountStackFramesTC : public ThreadClosure { - int _count; - bool _suspended; - public: - CountStackFramesTC() : _count(0), _suspended(false) {} - virtual void do_thread(Thread* thread) { - JavaThread* jt = (JavaThread*)thread; - if (!jt->is_external_suspend()) { - // To keep same behavior we fail this operation, - // even if it would work perfectly. - return; - } - _suspended = true; - // Count all java activation, i.e., number of vframes. - for (vframeStream vfst(jt); !vfst.at_end(); vfst.next()) { - // Native frames are not counted. - if (!vfst.method()->is_native()) _count++; - } - } - int count() { return _count; } - int suspended() { return _suspended; } -}; - -JVM_ENTRY(jint, JVM_CountStackFrames(JNIEnv* env, jobject jthread)) - JVMWrapper("JVM_CountStackFrames"); - - ThreadsListHandle tlh(thread); - JavaThread* receiver = NULL; - bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL); - if (is_alive) { - // jthread refers to a live JavaThread. - CountStackFramesTC csf; - Handshake::execute(&csf, receiver); - if (!csf.suspended()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalThreadStateException(), - "this thread is not suspended"); - } - return csf.count(); - } - // Implied else: if JavaThread is not alive simply return a count of 0. - return 0; -JVM_END - - JVM_ENTRY(void, JVM_Interrupt(JNIEnv* env, jobject jthread)) JVMWrapper("JVM_Interrupt"); diff -r 27c2d2a4b695 -r ca70299778b9 src/java.base/share/classes/java/lang/Thread.java --- a/src/java.base/share/classes/java/lang/Thread.java Mon Oct 28 15:03:36 2019 +0100 +++ b/src/java.base/share/classes/java/lang/Thread.java Thu Oct 31 16:45:58 2019 +0000 @@ -1251,20 +1251,20 @@ } /** - * Counts the number of stack frames in this thread. The thread must - * be suspended. + * Throws {@code UnsupportedOperationException}. + * + * @return nothing * - * @return the number of stack frames in this thread. - * @throws IllegalThreadStateException if this thread is not - * suspended. - * @deprecated The definition of this call depends on {@link #suspend}, - * which is deprecated. Further, the results of this call - * were never well-defined. + * @deprecated This method was originally designed to count the number of + * stack frames but the results were never well-defined and it + * depended on thread-suspension. * This method is subject to removal in a future version of Java SE. * @see StackWalker */ @Deprecated(since="1.2", forRemoval=true) - public native int countStackFrames(); + public int countStackFrames() { + throw new UnsupportedOperationException(); + } /** * Waits at most {@code millis} milliseconds for this thread to diff -r 27c2d2a4b695 -r ca70299778b9 src/java.base/share/native/libjava/Thread.c --- a/src/java.base/share/native/libjava/Thread.c Mon Oct 28 15:03:36 2019 +0100 +++ b/src/java.base/share/native/libjava/Thread.c Thu Oct 31 16:45:58 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2019, 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 @@ -50,7 +50,6 @@ {"yield", "()V", (void *)&JVM_Yield}, {"sleep", "(J)V", (void *)&JVM_Sleep}, {"currentThread", "()" THD, (void *)&JVM_CurrentThread}, - {"countStackFrames", "()I", (void *)&JVM_CountStackFrames}, {"interrupt0", "()V", (void *)&JVM_Interrupt}, {"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted}, {"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock}, diff -r 27c2d2a4b695 -r ca70299778b9 test/hotspot/jtreg/runtime/Thread/CountStackFramesAtExit.java --- a/test/hotspot/jtreg/runtime/Thread/CountStackFramesAtExit.java Mon Oct 28 15:03:36 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2017, 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 8167108 - * @summary Stress test java.lang.Thread.countStackFrames() at thread exit. - * @run main/othervm -Xlog:thread+smr=debug CountStackFramesAtExit - */ - -import java.util.concurrent.CountDownLatch; - -public class CountStackFramesAtExit extends Thread { - final static int N_THREADS = 32; - final static int N_LATE_CALLS = 1000; - - public CountDownLatch exitSyncObj = new CountDownLatch(1); - public CountDownLatch startSyncObj = new CountDownLatch(1); - - @Override - public void run() { - // Tell main thread we have started. - startSyncObj.countDown(); - try { - // Wait for main thread to interrupt us so we - // can race to exit. - exitSyncObj.await(); - } catch (InterruptedException e) { - // ignore because we expect one - } - } - - public static void main(String[] args) { - CountStackFramesAtExit threads[] = new CountStackFramesAtExit[N_THREADS]; - - for (int i = 0; i < N_THREADS; i++ ) { - threads[i] = new CountStackFramesAtExit(); - int late_count = 1; - threads[i].start(); - try { - // Wait for the worker thread to get going. - threads[i].startSyncObj.await(); - - // This interrupt() call will break the worker out of - // the exitSyncObj.await() call and the countStackFrames() - // calls will come in during thread exit. - threads[i].interrupt(); - for (; late_count <= N_LATE_CALLS; late_count++) { - try { - threads[i].countStackFrames(); - } catch (IllegalThreadStateException itse) { - // ignore because we expect it - } - - if (!threads[i].isAlive()) { - // Done with Thread.countStackFrames() calls since - // thread is not alive. - break; - } - } - } catch (InterruptedException e) { - throw new Error("Unexpected: " + e); - } - - System.out.println("INFO: thread #" + i + ": made " + late_count + - " late calls to java.lang.Thread.countStackFrames()"); - System.out.println("INFO: thread #" + i + ": N_LATE_CALLS==" + - N_LATE_CALLS + " value is " + - ((late_count >= N_LATE_CALLS) ? "NOT " : "") + - "large enough to cause a Thread.countStackFrames() " + - "call after thread exit."); - - try { - threads[i].join(); - } catch (InterruptedException e) { - throw new Error("Unexpected: " + e); - } - threads[i].countStackFrames(); - if (threads[i].isAlive()) { - throw new Error("Expected !Thread.isAlive() after thread #" + - i + " has been join()'ed"); - } - } - - String cmd = System.getProperty("sun.java.command"); - if (cmd != null && !cmd.startsWith("com.sun.javatest.regtest.agent.MainWrapper")) { - // Exit with success in a non-JavaTest environment: - System.exit(0); - } - } -} diff -r 27c2d2a4b695 -r ca70299778b9 test/jdk/java/lang/Thread/CountStackFrames.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/Thread/CountStackFrames.java Thu Oct 31 16:45:58 2019 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019, 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 8205132 + * @summary Test Thread.countStackFrames() + * @run testng CountStackFrames + */ + +import org.testng.annotations.Test; + +public class CountStackFrames { + + // current thread + @Test(expectedExceptions = UnsupportedOperationException.class) + public void testCurrentThread() { + Thread.currentThread().countStackFrames(); + } + + // unstarted thread + @Test(expectedExceptions = UnsupportedOperationException.class) + public void testUnstartedThread() { + Thread thread = new Thread(() -> { }); + thread.countStackFrames(); + } + + // terminated thread + @Test(expectedExceptions = UnsupportedOperationException.class) + public void testTerminatedThread() throws Exception { + Thread thread = new Thread(() -> { }); + thread.start(); + thread.join(); + thread.countStackFrames(); + } + +}