1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @bug 8193879 8193801 8129348
  27  * @summary Invokes static and instance methods when debugger trace
  28  * mode is on.
  29  * @library /test/lib
  30  * @run build TestScaffold VMConnection TargetListener TargetAdapter
  31  * @run compile -g MethodInvokeWithTraceOnTest.java
  32  * @run driver MethodInvokeWithTraceOnTest
  33  */
  34 
  35 import com.sun.jdi.*;
  36 import com.sun.jdi.event.*;
  37 import com.sun.jdi.request.*;
  38 
  39 import java.util.*;
  40 
  41 import static lib.jdb.JdbTest.*;
  42 
  43 /********** target program **********/
  44 
  45 class MethodInvokeWithTraceOnTestTarg {
  46     public static void main(String[] args) {
  47         new MethodInvokeWithTraceOnTestTarg().test();
  48     }
  49 
  50     private void test() {
  51         Thread thread = Thread.currentThread();
  52         print(thread); // @1 breakpoint
  53         String str = "test";
  54         printStatic(str); // @2 breakpoint
  55 
  56     }
  57 
  58     public void print(Object obj) {
  59         System.out.println(obj);
  60     }
  61 
  62     public static void printStatic(Object obj) {
  63         System.out.println(obj);
  64     }
  65 
  66 }
  67 
  68 
  69 /********** test program **********/
  70 
  71 public class MethodInvokeWithTraceOnTest extends TestScaffold {
  72 
  73     MethodInvokeWithTraceOnTest(String args[]) {
  74         super(args);
  75     }
  76 
  77     public static void main(String[] args)
  78             throws Exception {
  79         new MethodInvokeWithTraceOnTest(args).startTests();
  80     }
  81 
  82     /********** test core **********/
  83 
  84     protected void runTests() throws Exception {
  85         init();
  86 
  87         // Test with suspend policy set to SUSPEND_EVENT_THREAD
  88         BreakpointEvent be = resumeToBreakpoint(true, 1);
  89         System.out.println("Breakpoint 1 is hit, suspendPolicy:" + be.request().suspendPolicy());
  90         testMethods(be);
  91 
  92         // Test with suspend policy set to SUSPEND_ALL
  93         be = resumeToBreakpoint(false, 2);
  94         System.out.println("Breakpoint 2 is hit, suspendPolicy:" + be.request().suspendPolicy());
  95         testMethods(be);
  96 
  97         listenUntilVMDisconnect();
  98     }
  99 
 100     private void init() throws Exception {
 101         startToMain("MethodInvokeWithTraceOnTestTarg");
 102         vm().setDebugTraceMode(VirtualMachine.TRACE_ALL);
 103     }
 104 
 105     private BreakpointEvent resumeToBreakpoint(boolean suspendThread, int breakpointId) throws Exception {
 106         int bkpLine = parseBreakpoints(getTestSourcePath("MethodInvokeWithTraceOnTest.java"), breakpointId).get(0);
 107         System.out.println("Running to line: " + bkpLine);
 108         return resumeTo("MethodInvokeWithTraceOnTestTarg", bkpLine, suspendThread);
 109     }
 110 
 111     private void testMethods(BreakpointEvent be) throws Exception {
 112         System.out.println("Testing  methods...");
 113         ThreadReference thread = be.thread();
 114         StackFrame frame = thread.frame(0);
 115         ObjectReference thisObj = frame.thisObject();
 116         LocalVariable threadVar = frame.visibleVariableByName("thread");
 117         ThreadReference threadObj = (ThreadReference) frame.getValue(threadVar);
 118         StringReference stringObj = vm().mirrorOf("test string");
 119         int invokeOptions = getMethodInvokeOptions(be);
 120 
 121         testInstanceMethod1(thread, thisObj, stringObj, threadObj, invokeOptions);
 122         testStaticMethod1(thread, thisObj, stringObj, threadObj, invokeOptions);
 123         testStaticMethod2(thread, invokeOptions);
 124     }
 125 
 126     private void testInstanceMethod1(ThreadReference thread, ObjectReference thisObj, StringReference stringObj,
 127                                      ThreadReference threadObj, int invokeOptions) throws Exception {
 128         ClassType classType = (ClassType) thisObj.referenceType();
 129         Method printMethod = classType.methodsByName("print",
 130                 "(Ljava/lang/Object;)V").get(0);
 131 
 132         System.out.println("Passing StringReference to instance method...");
 133         thisObj.invokeMethod(thread, printMethod, Collections.singletonList(stringObj), invokeOptions);
 134 
 135         System.out.println("Passing ThreadReference to instance method...");
 136         thisObj.invokeMethod(thread, printMethod, Collections.singletonList(threadObj), invokeOptions);
 137     }
 138 
 139     private void testStaticMethod1(ThreadReference thread, ObjectReference thisObj, StringReference stringObj,
 140                                    ThreadReference threadObj, int invokeOptions) throws Exception {
 141         ClassType classType = (ClassType) thisObj.referenceType();
 142         Method printMethod = classType.methodsByName("printStatic",
 143                 "(Ljava/lang/Object;)V").get(0);
 144 
 145         System.out.println("Passing StringReference to static method...");
 146         classType.invokeMethod(thread, printMethod, Collections.singletonList(stringObj), invokeOptions);
 147 
 148         System.out.println("Passing ThreadReference to static method...");
 149         classType.invokeMethod(thread, printMethod, Collections.singletonList(threadObj), invokeOptions);
 150     }
 151 
 152     private void testStaticMethod2(ThreadReference thread, int invokeOptions) throws Exception {
 153         ClassType classType = getClassType("java.lang.Class");
 154         Method forNameMethod = classType.methodsByName("forName",
 155                 "(Ljava/lang/String;)Ljava/lang/Class;").get(0);
 156         StringReference classNameParam = vm().mirrorOf("java.lang.String");
 157         classType.invokeMethod(thread, forNameMethod, Collections.singletonList(classNameParam), invokeOptions);
 158     }
 159 
 160     private ClassType getClassType(String className) {
 161         List classes = vm().classesByName(className);
 162         return (ClassType) classes.get(0);
 163     }
 164 
 165     private int getMethodInvokeOptions(BreakpointEvent be) {
 166         return be.request().suspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD ?
 167                 ObjectReference.INVOKE_SINGLE_THREADED : 0;
 168     }
 169 }