Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/GetLocalVariable/GetLocalWithoutSuspendTest.java
41153 views
/*1* Copyright (c) 2020 SAP SE. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 824929326*27* @summary Test if stack walk to get local variable in the JVMTI implementation is safe if the28* target thread is not suspended.29*30* @comment The main/target thread uses recursion to build a large stack, then31* calls a native method to notify the JVMTI agent thread to get a32* local variable deep in the stack. This prolongs the stack walk. The33* target thread's stack is walkable while in native. After sending the34* notification it waits a while to give the agent time to reach the35* stack walk, then it returns from native. This is when its stack36* becomes not walkable again.37*38* @library /test/lib39* @compile GetLocalWithoutSuspendTest.java40* @run main/othervm/native41* -agentlib:GetLocalWithoutSuspendTest42* -Xbatch43* GetLocalWithoutSuspendTest44*/4546public class GetLocalWithoutSuspendTest {4748public static final int M = 1 << 20;4950public static final int TEST_ITERATIONS = 200;5152/**53* Native method to notify the agent thread to call GetLocalObject() on this thread.54*55* @param depth Depth of target frame for GetLocalObject() call. Should be56* large value to prolong the unsafe stack walk.57* @param waitTime Time to wait after notify with58* walkable stack before returning an becoming unsafe again.59* @return Dummy value.60*/61public static native void notifyAgentToGetLocal(int depth, int waitTime);6263/**64* Notify agent thread that we are shutting down and wait for it to terminate.65*/66public static native void shutDown();6768/**69* Provide agent thread with reference to target thread.70* @param target The target thread71*/72public static native void setTargetThread(Thread target);7374public static void main(String[] args) throws Exception {75new GetLocalWithoutSuspendTest().runTest();76}7778/**79* Wait cycles in native, i.e. with walkable stack, after notifying agent80* thread to do GetLocalObject() call.81*/82public int waitCycles = 1;8384public void runTest() throws Exception {85log("Set target thread for get local variable calls by agent.");86setTargetThread(Thread.currentThread());8788log("Test how many frames fit on the stack by performing recursive calls until");89log("StackOverflowError is thrown");90int targetDepth = recursiveMethod(0, M);91log("Testing with target depth: " + targetDepth);9293log("Begin Test.");94long start = System.currentTimeMillis();95for (int iterations = 0; iterations < TEST_ITERATIONS; iterations++) {96long now = System.currentTimeMillis();97log((now - start) + " ms Iteration : " + iterations +98" waitTime : " + waitCycles);99int newTargetDepth = recursiveMethod(0, targetDepth);100if (newTargetDepth < targetDepth) {101// A StackOverflowError can occur due to (re-)compilation. We102// don't reach the native method notifyAgentToGetLocal() then103// which is a prerequisite to trigger the problematic race104// condition. So we reduce the targetDepth to avoid stack105// overflow.106log("StackOverflowError during test.");107log("Old target depth: " + targetDepth);108log("Retry with new target depth: " + newTargetDepth);109targetDepth = newTargetDepth;110}111iterations++;112// Double wait time, but limit to roughly 10^6 cycles.113waitCycles = (waitCycles << 1) & (M - 1);114waitCycles = waitCycles == 0 ? 1 : waitCycles;115}116117// Notify agent thread that we are shutting down and wait for it to terminate.118shutDown();119120log("Successfully finished test");121}122123/**124* Perform recursive calls until the target stack depth is reached or the stack overflows.125* Call {@link #notifyAgentToGetLocal(int, int)} if the target depth is reached.126*127* @param depth Current recursion depth128* @param targetStackDepth Target recursion depth129* @return Depth at which the recursion was ended130*/131public int recursiveMethod(int depth, int targetStackDepth) {132int maxDepth = depth;133try {134if (depth == targetStackDepth) {135notifyAgentToGetLocal(depth - 100, waitCycles);136} else {137maxDepth = recursiveMethod(depth + 1, targetStackDepth);138}139} catch (StackOverflowError e) {140// Don't print message here, because this would likely trigger a new StackOverflowError141}142return maxDepth;143}144145public static void log(String m) {146System.out.println("### Java-Test: " + m);147}148}149150151