--- old/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java 2018-10-03 20:25:55.000000000 -0700 +++ new/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java 2018-10-03 20:25:55.000000000 -0700 @@ -100,6 +100,12 @@ public void breakpointEvent(BreakpointEvent be) { Thread.yield(); // fetch output MessageOutput.lnprint("Breakpoint hit:"); + // Print the prompt if suspend policy is SUSPEND_EVENT_THREAD. In case of + // SUSPEND_ALL policy this is handled by vmInterrupted() method. + if (be.request().suspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) { + MessageOutput.println(); + MessageOutput.printPrompt(); + } } @Override --- old/src/jdk.jdi/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java 2018-10-03 20:25:56.000000000 -0700 +++ new/src/jdk.jdi/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java 2018-10-03 20:25:56.000000000 -0700 @@ -236,15 +236,7 @@ final MethodImpl method, final ValueImpl[] args, final int options) { - /* - * Cache the values of args when TRACE_SENDS is enabled, for later printing. - * If not cached, printing causes a remote call while synchronized, and deadlock. - */ - if ((vm.traceFlags & VirtualMachine.TRACE_SENDS) != 0) { - for (ValueImpl arg: args) { - arg.toString(); - } - } + CommandSender sender = getInvokeMethodSender(thread, method, args, options); PacketStream stream; if ((options & ClassType.INVOKE_SINGLE_THREADED) != 0) { --- old/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMState.java 2018-10-03 20:25:57.000000000 -0700 +++ new/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMState.java 2018-10-03 20:25:57.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, 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 @@ -26,10 +26,7 @@ package com.sun.tools.jdi; import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; +import java.util.*; import com.sun.jdi.ThreadGroupReference; import com.sun.jdi.ThreadReference; @@ -44,12 +41,10 @@ /* * Certain information can be cached only when the entire VM is - * suspended and there are no pending resumes. The fields below - * are used to track whether there are pending resumes. (There - * is an assumption that JDWP command ids are increasing over time.) + * suspended and there are no pending resumes. The field below + * is used to track whether there are pending resumes. */ - private int lastCompletedCommandId = 0; // synchronized (this) - private int lastResumeCommandId = 0; // synchronized (this) + private final Set pendingResumeCommands = Collections.synchronizedSet(new HashSet<>()); // This is cached only while the VM is suspended private static class Cache { @@ -97,12 +92,12 @@ * A JDWP command has been completed (reply has been received). * Update data that tracks pending resume commands. */ - synchronized void notifyCommandComplete(int id) { - lastCompletedCommandId = id; + void notifyCommandComplete(int id) { + pendingResumeCommands.remove(id); } synchronized void freeze() { - if (cache == null && (lastCompletedCommandId >= lastResumeCommandId)) { + if (cache == null && (pendingResumeCommands.isEmpty())) { /* * No pending resumes to worry about. The VM is suspended * and additional state can be cached. Notify all @@ -115,7 +110,7 @@ synchronized PacketStream thawCommand(CommandSender sender) { PacketStream stream = sender.send(); - lastResumeCommandId = stream.id(); + pendingResumeCommands.add(stream.id()); thaw(); return stream; } --- old/test/jdk/com/sun/jdi/lib/jdb/Jdb.java 2018-10-03 20:25:59.000000000 -0700 +++ new/test/jdk/com/sun/jdi/lib/jdb/Jdb.java 2018-10-03 20:25:58.000000000 -0700 @@ -29,6 +29,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -40,9 +41,14 @@ import jdk.test.lib.process.StreamPumper; public class Jdb implements AutoCloseable { + public Jdb(String... args) { + this(Arrays.asList(args)); + } + + public Jdb(Collection args) { ProcessBuilder pb = new ProcessBuilder(JDKToolFinder.getTestJDKTool("jdb")); - pb.command().addAll(Arrays.asList(args)); + pb.command().addAll(args); try { jdb = pb.start(); } catch (IOException ex) { @@ -207,6 +213,10 @@ } public List command(JdbCommand cmd) { + return command(cmd, false); + } + + public List command(JdbCommand cmd, boolean waitForSimplePrompt) { if (!jdb.isAlive()) { if (cmd.allowExit) { // return remaining output @@ -223,7 +233,7 @@ throw new RuntimeException("Unexpected IO error while writing command '" + cmd.cmd + "' to jdb stdin stream"); } - return waitForPrompt(1, cmd.allowExit); + return waitForSimplePrompt ? waitForSimplePrompt(1, cmd.allowExit) : waitForPrompt(1, cmd.allowExit); } public List command(String cmd) { --- old/test/jdk/com/sun/jdi/lib/jdb/JdbTest.java 2018-10-03 20:26:00.000000000 -0700 +++ new/test/jdk/com/sun/jdi/lib/jdb/JdbTest.java 2018-10-03 20:25:59.000000000 -0700 @@ -45,6 +45,8 @@ public final String debuggeeClass; public final List debuggeeOptions = new LinkedList<>(); public String sourceFilename; + public final List debuggerOptions = new LinkedList<>(); + public LaunchOptions(String debuggeeClass) { this.debuggeeClass = debuggeeClass; @@ -61,6 +63,17 @@ sourceFilename = name; return this; } + + public LaunchOptions addDebuggerOptions(String[] options) { + debuggerOptions.addAll(Arrays.asList(options)); + return this; + } + + public LaunchOptions addDebuggerOption(String option) { + debuggerOptions.add(option); + return this; + } + } public JdbTest(LaunchOptions launchOptions) { @@ -141,7 +154,12 @@ // launch jdb try { - jdb = new Jdb("-connect", "com.sun.jdi.SocketAttach:port=" + debuggeeListen[1]); + List jdbOptions = new LinkedList<>(); + jdbOptions.add("-connect"); + jdbOptions.add("com.sun.jdi.SocketAttach:port=" + debuggeeListen[1]); + jdbOptions.addAll(launchOptions.debuggerOptions); + + jdb = new Jdb(jdbOptions); } catch (Throwable ex) { // terminate debuggee if something went wrong debuggee.destroy(); @@ -238,7 +256,7 @@ } // gets full test source path for the given test filename - protected static String getTestSourcePath(String fileName) { + public static String getTestSourcePath(String fileName) { return Paths.get(System.getProperty("test.src")).resolve(fileName).toString(); } --- /dev/null 2018-10-03 20:26:01.000000000 -0700 +++ new/test/jdk/com/sun/jdi/JdbStopThreadWithTraceOnTest.java 2018-10-03 20:26:01.000000000 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, 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 8193879 + * @summary Stops the thread at the breakpoint and invokes methods + * when debugger trace mode is on. + * + * @library /test/lib + * @run compile -g JdbStopThreadWithTraceOnTest.java + * @run main/othervm JdbStopThreadWithTraceOnTest + */ + +import jdk.test.lib.process.OutputAnalyzer; +import lib.jdb.JdbCommand; +import lib.jdb.JdbTest; + +class JdbStopThreadWithTraceOnTestTarg { + public static void main(String[] args) { + test(); + } + + private static void test() { + Thread thread = Thread.currentThread(); + print(thread); // @1 breakpoint + } + + public static void print(Object obj) { + System.out.println(obj); + } +} + +public class JdbStopThreadWithTraceOnTest extends JdbTest { + public static void main(String argv[]) { + new JdbStopThreadWithTraceOnTest().run(); + } + + private JdbStopThreadWithTraceOnTest() { + super(new LaunchOptions(DEBUGGEE_CLASS).addDebuggerOptions(DEBUGGER_TRACE_OPTIONS)); + } + + private static final String DEBUGGEE_CLASS = JdbStopThreadWithTraceOnTestTarg.class.getName(); + private static final String[] DEBUGGER_TRACE_OPTIONS = {"-dbgtrace", "0x00ffffff"}; + + + @Override + protected void runCases() { + int bpLine = parseBreakpoints(getTestSourcePath("JdbStopThreadWithTraceOnTest.java"), 1).get(0); + jdb.command("stop thread at " + DEBUGGEE_CLASS + ":" + bpLine); + // Run to breakpoint #1 + jdb.command(JdbCommand.run(), true); + + // Set the current thread + jdb.command("thread 1"); + + // Invoke the method + jdb.command(JdbCommand.eval(DEBUGGEE_CLASS + ".print(thread)")); + + jdb.command(JdbCommand.quit()); + + new OutputAnalyzer(jdb.getJdbOutput()) + .shouldContain(DEBUGGEE_CLASS + ".print(thread)"); + } +} --- /dev/null 2018-10-03 20:26:02.000000000 -0700 +++ new/test/jdk/com/sun/jdi/MethodInvokeWithTraceOnTest.java 2018-10-03 20:26:02.000000000 -0700 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2018, 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 8193801 8129348 + * @summary Invokes static and instance methods when debugger trace + * mode is on. + * + * @library /test/lib + * @run build TestScaffold VMConnection TargetListener TargetAdapter + * @run compile -g MethodInvokeWithTraceOnTest.java + * @run driver MethodInvokeWithTraceOnTest + */ + +import com.sun.jdi.*; +import com.sun.jdi.event.*; + +import java.util.*; + +import static lib.jdb.JdbTest.*; + +/********** target program **********/ + +class MethodInvokeWithTraceOnTestTarg { + public static void main(String[] args) { + new MethodInvokeWithTraceOnTestTarg().test(); + } + + private void test() { + Thread thread = Thread.currentThread(); + print(thread); // @1 breakpoint + } + + public void print(Object obj) { + System.out.println(obj); + } +} + + +/********** test program **********/ + +public class MethodInvokeWithTraceOnTest extends TestScaffold { + + MethodInvokeWithTraceOnTest(String args[]) { + super(args); + } + + public static void main(String[] args) + throws Exception { + new MethodInvokeWithTraceOnTest(args).startTests(); + } + + /********** test core **********/ + + protected void runTests() + throws Exception { + BreakpointEvent be = init(); + testStaticMethod(be); + testInstanceMethod(be); + + /* + * resume the target listening for events + */ + listenUntilVMDisconnect(); + } + + private BreakpointEvent init() throws Exception{ + startToMain("MethodInvokeWithTraceOnTestTarg"); + vm().setDebugTraceMode(VirtualMachine.TRACE_ALL); + int bkpLine = parseBreakpoints(getTestSourcePath("MethodInvokeWithTraceOnTest.java"), 1).get(0); + System.out.println("Running to line: " + bkpLine); + return resumeTo("MethodInvokeWithTraceOnTestTarg", bkpLine); + } + + private void testStaticMethod( BreakpointEvent be) throws Exception { + System.out.println("Testing static method..."); + ClassType classType = getClassType("java.lang.Class"); + Method forName = classType.methodsByName("forName", + "(Ljava/lang/String;)Ljava/lang/Class;").get(0); + StringReference classNameParam = vm().mirrorOf("java.lang.String"); + classType.invokeMethod(be.thread(), forName, Collections.singletonList(classNameParam), 0); + + } + + private void testInstanceMethod( BreakpointEvent be) throws Exception { + System.out.println("Testing instance method..."); + ThreadReference thread = be.thread(); + StackFrame frame = thread.frame(0); + ObjectReference thisObj = frame.thisObject(); + LocalVariable threadVar = frame.visibleVariableByName("thread"); + ThreadReference threadObj = (ThreadReference)frame.getValue(threadVar); + + ClassType classType = (ClassType)thisObj.referenceType(); + for(Method m: classType.methods()){ + System.out.println(m.signature() + ":" + m.name()); + } + Method printMethod = classType.methodsByName("print", + "(Ljava/lang/Object;)V").get(0); + StringReference objectToPrint = vm().mirrorOf("test string"); + System.out.println("Passing StringReference to instance method..."); + thisObj.invokeMethod(thread, printMethod, Collections.singletonList(objectToPrint), 0); + System.out.println("Passing ThreadReference to instance method..."); + thisObj.invokeMethod(thread, printMethod, Collections.singletonList(threadObj), 0); + + } + + private ClassType getClassType(String className) throws Exception { + List classes = vm().classesByName(className); + return (ClassType) classes.get(0); + } + +}