8241807: JDWP needs update for hidden classes

Introduce test coverage for hidden class events

Reviewed-by: lmesnik, amenkov
This commit is contained in:
Serguei Spitsyn 2020-04-29 06:33:10 +00:00
parent 7f49c9167a
commit 0783dd69a5
6 changed files with 872 additions and 0 deletions

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2020, 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.
*/
package nsk.jdi.HiddenClass.events;
import nsk.share.Log;
import nsk.jdi.HiddenClass.events.DebuggerBase;
import nsk.share.jdi.ArgumentHandler;
import nsk.share.jpda.IOPipe;
/* Debuggee base class. */
class DebuggeeBase {
private final IOPipe pipe;
private final Log log;
protected void logMsg(String msg) { log.display(msg); }
protected DebuggeeBase(ArgumentHandler argHandler) {
pipe = argHandler.createDebugeeIOPipe();
log = argHandler.createDebugeeLog();
}
protected void syncWithDebugger() {
// Notify debugger that debuggee is ready.
logMsg("Debuggee: Sending command: " + DebuggerBase.COMMAND_READY);
pipe.println(DebuggerBase.COMMAND_READY);
// Wait for COMMAND_RUN from debugger to continue execution.
logMsg("Debuggee: Waiting for command: " + DebuggerBase.COMMAND_RUN);
String command = pipe.readln();
if (command == null || !command.equals(DebuggerBase.COMMAND_RUN)) {
logMsg("FAIL: Debugee: unknown command: " + command);
throw new RuntimeException("Failed in sync with debugger. ");
}
}
protected void quitSyncWithDebugger() {
// Notify debugger about debuggee completed status.
logMsg("Debuggee: Sending command: " + DebuggerBase.COMMAND_DONE);
pipe.println(DebuggerBase.COMMAND_DONE);
// Wait for command QUIT from debugger to release started threads and exit.
logMsg("Debuggee: Waiting for command: " + DebuggerBase.COMMAND_QUIT);
String command = pipe.readln();
if (command == null || !command.equals(DebuggerBase.COMMAND_QUIT)) {
logMsg("FAIL: Debugee: unknown command: " + command);
throw new RuntimeException("Failed in sync with debugger. ");
}
}
}

View File

@ -0,0 +1,260 @@
/*
* Copyright (c) 2020, 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.
*/
package nsk.jdi.HiddenClass.events;
import com.sun.jdi.ClassType;
import com.sun.jdi.ClassObjectReference;
import com.sun.jdi.Field;
import com.sun.jdi.Method;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.ClassPrepareRequest;
import com.sun.jdi.request.ClassUnloadRequest;
import com.sun.jdi.request.ModificationWatchpointRequest;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import jdk.test.lib.Asserts;
import nsk.share.Log;
import nsk.share.jdi.ArgumentHandler;
import nsk.share.jdi.Binder;
import nsk.share.jdi.Debugee;
import nsk.share.jpda.IOPipe;
// This class is the test debugger base class
public class DebuggerBase {
public static final int PASSED = 0;
public static final int FAILED = 2;
public static final int JCK_STATUS_BASE = 95;
public static final String COMMAND_READY = "ready";
public static final String COMMAND_RUN = "run";
public static final String COMMAND_DONE = "done";
public static final String COMMAND_ERROR = "error";
public static final String COMMAND_QUIT = "quit";
public final Log log;
private VirtualMachine vm;
private Debugee debuggee = null;
private IOPipe pipe = null;
private EventRequestManager erManager = null;
protected DebuggerBase(ArgumentHandler argHandler) {
log = new Log(System.out, argHandler);
}
VirtualMachine vm() {
return vm;
}
// Find a ReferenceType by a given type name.
ReferenceType getReferenceType(String typeName) {
List<ReferenceType> list = vm.classesByName(typeName);
Asserts.assertFalse(list.size() == 0, "FAIL: type not found: " + typeName);
Asserts.assertFalse(list.size() > 1, "FAIL: multiple types found: " + typeName);
log.display(" Found type: " + typeName);
return list.get(0);
}
// Find a Field by a given ReferenceType and a field name.
Field findField(ReferenceType refType, String fieldName) {
Field field = refType.fieldByName(fieldName);
String fullName = refType.name() + "::" + fieldName;
Asserts.assertNotNull(field, "FAIL: field not found: " + fullName);
log.display(" Found field: " + fullName);
return field;
}
// Find a Method by a given ReferenceType and a method name.
Method findMethod(ReferenceType refType, String methodName) {
List<Method> list = refType.methodsByName(methodName);
String fullName = refType.name() + "::" + methodName;
Asserts.assertFalse(list.size() == 0, "FAIL: method not found: " + fullName);
Asserts.assertFalse(list.size() > 1, "FAIL: multiple methods found: " + fullName);
log.display(" Found method: " + fullName);
return list.get(0);
}
// Invoke a given static method in debuggee VM at an eventpoint.
boolean invokeStaticMethod(ThreadReference thread, Method methodToInvoke) {
boolean failedStatus = false;
List<? extends Value> args = new ArrayList<>();
int flags = (ClassObjectReference.INVOKE_NONVIRTUAL |
ClassObjectReference.INVOKE_SINGLE_THREADED);
try {
log.display(" invoking method: " + methodToInvoke);
ClassType type = (ClassType)methodToInvoke.declaringType();
Value val = type.invokeMethod(thread, methodToInvoke, args, flags);
log.display(" method getHCField returned result: " + val);
} catch (Exception ex) {
log.complain("Exception in HC::getHCField method invocation: " + ex);
failedStatus = true;
}
return failedStatus;
}
protected void launchDebuggee(ArgumentHandler argHandler, String debuggeeName) {
Binder binder = new Binder(argHandler, log);
log.display("\n# Connecting to debuggee");
debuggee = binder.bindToDebugee(debuggeeName);
debuggee.redirectStderr(log, "debuggee >");
pipe = debuggee.createIOPipe();
vm = debuggee.VM();
erManager = vm.eventRequestManager();
log.display("# Resuming debuggee");
debuggee.resume();
}
protected boolean shutdownDebuggee() {
boolean debuggeeFailed = false;
log.display("\n# Shutting down debuggee");
// wait for debuggee exits and analize its exit code
log.display("# Waiting for debuggee terminating");
int debuggeeStatus = debuggee.endDebugee();
if (debuggeeStatus == PASSED + JCK_STATUS_BASE) {
log.display("# Debuggee PASSED with exit code: " + debuggeeStatus);
} else {
log.complain("# Debuggee FAILED with exit code: " + debuggeeStatus);
debuggeeFailed = true;
}
return debuggeeFailed;
}
protected EventRequest enableBreakpointRequest(Method method) {
log.display("\n# Creating BreakpointRequest");
BreakpointRequest request = erManager.createBreakpointRequest(method.location());
Asserts.assertNotNull(request, "FAIL: unable to create BreakpointRequest");
// enable event request
request.enable();
log.display(" Enabled BreakpointRequest");
return request;
}
protected EventRequest enableClassPrepareRequest(String classFilter) {
log.display("\n# Creating ClassPrepareRequest");
ClassPrepareRequest request = erManager.createClassPrepareRequest();
Asserts.assertNotNull(request, "FAIL: unable to create ClassPrepareRequest");
if (classFilter != null) {
log.display(" Adding filter to ClassPrepareRequest: " + classFilter);
request.addClassFilter(classFilter);
}
// enable event request
request.enable();
log.display(" Enabled ClassPrepareRequest");
return request;
}
protected EventRequest enableClassUnloadRequest(String classFilter) {
log.display("\n# Creating request for ClassUnloadEvent");
ClassUnloadRequest request = erManager.createClassUnloadRequest();
Asserts.assertNotNull(request, "FAIL: unable to create ClassUnloadRequest");
if (classFilter != null) {
log.display(" Adding filter to ClassUnloadRequest: " + classFilter);
request.addClassFilter(classFilter);
}
// enable event request
request.enable();
log.display(" Enabled ClassUnloadRequest");
return request;
}
protected EventRequest enableModificationWatchpointRequest(Field field, String classFilter) {
log.display("\n# Creating request for ModificationWatchpointRequest");
ModificationWatchpointRequest request = erManager.createModificationWatchpointRequest(field);
Asserts.assertNotNull(request, "FAIL: unable to create ModificationWatchpointRequest");
if (classFilter != null) {
log.display(" Adding filter to ModificationWatchpointRequest: " + classFilter);
request.addClassFilter(classFilter);
}
// enable event request
request.enable();
log.display(" Enabled ModificationWatchpointRequest");
return request;
}
protected void disableRequest(EventRequest eq, String reqestName) {
// disable event requests to prevent appearance of further events
if (eq != null && eq.isEnabled()) {
log.display(" Disabling " + reqestName);
eq.disable();
}
}
// sync on the COMMAND_READY
protected void readyCmdSync() {
// wait for READY signal from debugee
log.display("\n# Waiting for command: " + COMMAND_READY);
String command = pipe.readln();
Asserts.assertFalse(command == null || !command.equals(COMMAND_READY),
"FAIL: unexpected debuggee's command: " + command);
log.display("\n# Got command: " + COMMAND_READY);
}
// sync on the COMMAND_RUN
protected void runCmdSync() {
// activate debugee
log.display("\n# Sending command: " + COMMAND_RUN);
pipe.println(COMMAND_RUN);
}
// sync on the COMMAND_DONE
protected void doneCmdSync() {
// wait for DONE signal from debugee
log.display("\n# Waiting for command: " + COMMAND_DONE);
String command = pipe.readln();
Asserts.assertFalse(command == null || !command.equals(COMMAND_DONE),
"FAIL: unexpected debuggee's command: " + command);
log.display("\n# Got command: " + COMMAND_DONE);
}
// sync on the COMMAND_QUIT
protected void quitCmdSync() {
// force debugee to exit
log.display("\n# Sending command: " + COMMAND_QUIT);
pipe.println(COMMAND_QUIT);
}
}

View File

@ -0,0 +1,229 @@
/*
* Copyright (c) 2020, 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.
*/
package nsk.jdi.HiddenClass.events;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.Method;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.ClassUnloadEvent;
import com.sun.jdi.event.ModificationWatchpointEvent;
import com.sun.jdi.request.EventRequest;
import jdk.test.lib.Asserts;
import nsk.jdi.HiddenClass.events.DebuggerBase;
import nsk.share.Log;
/* This is a special thread to handle hidden class related events.
* The thread is looping on accepting events until all the expected
* event types are received. */
public class EventHandler extends Thread {
private static final int TIMEOUT_DELTA = 1000; // milliseconds
private final DebuggerBase debuggerBase;
private final Log log;
private volatile boolean testFailed = false;
private boolean breakpointEventRecieived = false;
private boolean classPrepareEventRecieived = false;
private boolean classUnloadEventRecieived = false;
private boolean modificationWatchpointEventRecieived = false;
// Hidden class ReferenceType which is saved for debugger.
private ReferenceType hcRefType = null;
// This method is called by the debugger main thread.
static EventHandler createAndStart(DebuggerBase debuggerBase) {
// start EventHandler thread
EventHandler handler = new EventHandler(debuggerBase);
handler.start();
return handler;
}
// Constructor
private EventHandler(DebuggerBase debuggerBase) {
this.debuggerBase = debuggerBase;
this.log = debuggerBase.log;
log.display("\n# EventHandler is started");
}
// This method is called by the debugger main thread.
void waitForCompleteness() {
log.display("\n# Waiting for EventHandler to complete");
// wait for all expected events received or timeout exceeds
try {
super.join();
if (isAlive()) {
log.complain("FAILURE: Timeout for waiting event was exceeded");
interrupt();
testFailed = true;
} else {
log.display("# EventHandler completed");
}
} catch (InterruptedException ie) {
log.complain("FAIL: InterruptedException caught while waiting for eventHandler's death");
testFailed = true;
}
}
// This method is called by the debugger main thread to wait and get
// the hidden class reference type from its ClassPrepare event.
// The readyCmdSync with the debuggeee is not enough because a
// ClassPrepare event is delivered over JDWP protocol with a delay.
// A wait/notify sync is to ensure the debugger gets non-null value.
synchronized ReferenceType waitAndGetHCRefType() throws InterruptedException {
while (hcRefType == null) {
wait();
}
return hcRefType;
}
// This method is called by the debugger main thread.
boolean failedStatus() { return testFailed; }
// Save hidden class ReferenceType when its ClassPrepare event is received.
private synchronized void setHCRefType(ReferenceType type) {
hcRefType = type;
notifyAll();
}
private EventSet getNextEventSet() throws InterruptedException {
EventSet eventSet = debuggerBase.vm().eventQueue().remove(TIMEOUT_DELTA);
return eventSet;
}
// Breakpoint event handler.
private void checkBreakpointEvent(BreakpointEvent event) {
Method method = event.location().method();
ClassType type = (ClassType)method.declaringType();
// got expected event in a hidden class method
log.display("\nBreakpointEvent: " + event.toString());
log.display("BreakpointEvent: " + type.name() + "::" + method.name());
breakpointEventRecieived = true;
// find another method in the same hidden class
ThreadReference thread = event.thread();
Method methodToInvoke = debuggerBase.findMethod(type, "getHCField");
// invoke hidden class static method getNCField in debuggee VM
testFailed |= debuggerBase.invokeStaticMethod(thread, methodToInvoke);
}
// ClassPrepare event handler.
private void checkClassPrepareEvent(ClassPrepareEvent event) {
ReferenceType type = event.referenceType();
String name = type.name();
String sign = type.signature();
// set hidden class ReferenceType object for debugger
setHCRefType(type);
log.display("\nClassPrepareEvent: " + event.toString());
log.display("ClassPrepareEvent class name: " + name);
log.display("ClassPrepareEvent class sign: " + sign);
classPrepareEventRecieived = true;
Asserts.assertTrue(name.indexOf("HiddenClass") > 0 && name.indexOf("/0x") > 0,
"FAIL: unexpected class in ClassPrepareEvent");
}
// ClassUnload event handler.
private void checkClassUnloadEvent(ClassUnloadEvent event) {
EventRequest request = event.request();
String name = event.className();
log.display("\nClassUnloadEvent class name: " + name);
log.display("ClassUnloadEvent class sign: " + event.classSignature());
classUnloadEventRecieived = true;
Asserts.assertTrue(name.indexOf("HiddenClass") > 0 && name.indexOf("/0x") > 0,
"FAIL: unexpected class in ClassUnloadEvent");
}
// ModificationWatchpoint event handler.
private void checkModificationWatchpointEvent(ModificationWatchpointEvent event) {
EventRequest request = event.request();
Field field = event.field();
ReferenceType type = field.declaringType();
log.display("\nModificationWatchpointEvent: " + event.toString());
log.display("ModificationWatchpointEvent: field: " + type.name() + "::" + field.name());
log.display("ModificationWatchpointEvent: value: " + event.valueToBe().toString());
modificationWatchpointEventRecieived = true;
}
private void processEventSet(EventSet eventSet) throws InterruptedException {
// handle each event from the event set
EventIterator eventIterator = eventSet.eventIterator();
while (eventIterator.hasNext()) {
Event event = eventIterator.nextEvent();
if (!breakpointEventRecieived &&
event instanceof BreakpointEvent) {
checkBreakpointEvent((BreakpointEvent)event);
}
if (!classPrepareEventRecieived &&
event instanceof ClassPrepareEvent) {
checkClassPrepareEvent((ClassPrepareEvent)event);
}
if (!classUnloadEventRecieived &&
event instanceof ClassUnloadEvent) {
checkClassUnloadEvent((ClassUnloadEvent)event);
}
if (!modificationWatchpointEventRecieived &&
event instanceof ModificationWatchpointEvent) {
checkModificationWatchpointEvent((ModificationWatchpointEvent)event);
}
// ignore all other events
}
}
public void run() {
log.display("\nEventHandler started");
try {
// Handle events until all expected events are received.
while (!breakpointEventRecieived ||
!classPrepareEventRecieived ||
!classUnloadEventRecieived ||
!modificationWatchpointEventRecieived
) {
EventSet eventSet = getNextEventSet();
if (eventSet == null) {
continue;
}
processEventSet(eventSet);
eventSet.resume();
}
} catch (Throwable t) {
log.complain("Throwable in EventHandler: " + t);
testFailed = true;
}
log.display("\nEventHandler finished");
}
} // class EventHandler

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2020, 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.
*/
package nsk.jdi.HiddenClass.events;
import java.io.File;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.nio.file.Files;
import java.nio.file.Paths;
import nsk.share.classload.ClassLoadUtils;
/* Interface for tested hidden class to implement. */
interface HCInterf {
void hcMethod();
}
/* Hidden class definition used to define tested hidden class
* with lookup.defineHiddenClass. */
public class HiddenClass implements HCInterf {
static String hcField = "<Not initialized>";
static String getHCField() { return hcField; }
private String getClassName() {
return this.getClass().getName();
}
public void hcMethod() {
hcField = getClassName();
if (hcField.indexOf("HiddenClass") == -1) {
throw new RuntimeException("Debuggee: Unexpected HiddenClass name: " + hcField);
}
}
public static Class<?> defineHiddenClass() throws Exception {
final String HC_NAME = HiddenClass.class.getName();
final String HC_PATH = ClassLoadUtils.getClassPath(HC_NAME) + File.separator +
HC_NAME.replace(".", File.separator) + ".class";
Class<?> hc = defineHiddenClass(HC_PATH);
return hc;
}
private static Class<?> defineHiddenClass(String classFileName) throws Exception {
try {
Lookup lookup = MethodHandles.lookup();
byte[] bytes = Files.readAllBytes(Paths.get(classFileName));
Class<?> hc = lookup.defineHiddenClass(bytes, false).lookupClass();
return hc;
} catch (Exception ex) {
throw ex;
}
}
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2020, 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
* @summary JDI test for hidden classes
*
* @library /vmTestbase
* /test/lib
* @modules java.base/jdk.internal.misc:+open
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
*
* @run driver jdk.test.lib.FileInstaller . .
* @build nsk.jdi.HiddenClass.events.*
*
* @run main/othervm PropertyResolvingWrapper
* nsk.jdi.HiddenClass.events.events001
* -verbose
* -arch=${os.family}-${os.simpleArch}
* -waittime=5
* -debugee.vmkind=java
* -transport.address=dynamic
* "-debugee.vmkeys=-Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI ${test.vm.opts} ${test.java.opts}"
*/
package nsk.jdi.HiddenClass.events;
import com.sun.jdi.Field;
import com.sun.jdi.Method;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.request.EventRequest;
import nsk.jdi.HiddenClass.events.DebuggerBase;
import nsk.jdi.HiddenClass.events.EventHandler;
import nsk.share.Log;
import nsk.share.jdi.ArgumentHandler;
// This class is the test debugger
public class events001 extends DebuggerBase {
static final String PACKAGE_NAME = "nsk.jdi.HiddenClass.events";
static final String DEBUGGEE_NAME = PACKAGE_NAME + ".events001a";
static final String CHECKED_CLASS = PACKAGE_NAME + ".HiddenClass";
static final String HC_FILTER = CHECKED_CLASS + "/0x*";
private events001(ArgumentHandler argHandler) {
super(argHandler);
}
public static void main (String args[]) {
ArgumentHandler argHandler = new ArgumentHandler(args);
events001 debugger = new events001(argHandler);
System.exit(debugger.run(argHandler) + JCK_STATUS_BASE);
}
public int run(ArgumentHandler argHandler) {
boolean testFailed = false;
EventRequest breakpointRequest = null;
EventRequest classPrepareRequest = null;
EventRequest classUnloadRequest = null;
EventRequest modWatchpointRequest = null;
launchDebuggee(argHandler, DEBUGGEE_NAME);
try {
EventHandler eventHandler = EventHandler.createAndStart(this);
// sync with debuggee
readyCmdSync();
// request a ClassPrepare event for the hidden class "HiddenClass/0x*"
classPrepareRequest = enableClassPrepareRequest(HC_FILTER);
// request a ClassUnload event for the hidden class "HiddenClass/0x*"
classUnloadRequest = enableClassUnloadRequest(HC_FILTER);
// sync with debuggee
runCmdSync();
readyCmdSync();
// There is a latency in getting events from the debuggee
// on the debugger side over the wire protocol, so we may
// need to wait for ClassPrepareEvent to be posted.
ReferenceType hcRefType = eventHandler.waitAndGetHCRefType();
/* Hidden class has to be prepared at this point. */
// request a Breakpoint event in the hidden class method "hcMethod"
Method method = findMethod(hcRefType, "hcMethod");
breakpointRequest = enableBreakpointRequest(method);
// request a ModificationWatchpoint event on the hidden class field "hcField"
Field field = findField(hcRefType, "hcField");
modWatchpointRequest = enableModificationWatchpointRequest(field, HC_FILTER);
// sync with debuggee
runCmdSync();
doneCmdSync();
eventHandler.waitForCompleteness();
testFailed |= eventHandler.failedStatus();
} catch (Throwable t) {
log.complain("FAIL: " + t.getMessage());
t.printStackTrace(log.getOutStream());
testFailed = true;
} finally {
// disable event requests
disableRequest(breakpointRequest, "BreakpointRequest");
disableRequest(classPrepareRequest, "ClassPrepareRequest");
disableRequest(classUnloadRequest, "ClassUnloadRequest");
disableRequest(modWatchpointRequest, "ModificationWatchpointRequest");
// sync with debuggee
quitCmdSync();
testFailed |= shutdownDebuggee();
}
// check test results
if (testFailed) {
log.complain("# TEST FAILED");
return FAILED;
}
log.display("# TEST PASSED");
return PASSED;
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2020, 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.
*/
package nsk.jdi.HiddenClass.events;
import nsk.jdi.HiddenClass.events.DebuggeeBase;
import nsk.jdi.HiddenClass.events.HiddenClass;
import nsk.jdi.HiddenClass.events.HCInterf;
import nsk.share.jdi.ArgumentHandler;
import sun.hotspot.WhiteBox;
/* Debuggee class. */
class events001a extends DebuggeeBase {
private final WhiteBox WB = WhiteBox.getWhiteBox();
private events001a(ArgumentHandler argHandler) {
super(argHandler);
}
public static void main(String args[]) {
ArgumentHandler argHandler = new ArgumentHandler(args);
events001a testApp = new events001a(argHandler);
int status = testApp.runIt();
System.exit(DebuggerBase.JCK_STATUS_BASE + status);
}
public int runIt() {
int status = DebuggerBase.PASSED;
logMsg("\nDebuggee: started");
try {
testHiddenClass();
} catch (Throwable t) {
status = DebuggerBase.FAILED;
logMsg("FAIL: Throwable was caught in debuggee main: " + t);
}
logMsg("\nDebuggee: finished");
return status;
}
public void testHiddenClass() throws Exception {
syncWithDebugger();
// Define a hidden class.
Class<?> hc = HiddenClass.defineHiddenClass();
logMsg("Debuggee: defined a hidden class: " + hc.getName());
// It is impossible to use a hidden class name to define a variable,
// so we use the interface which the tested hidden class implements.
HCInterf hcObj = (HCInterf)hc.newInstance();
logMsg("Debuggee: created an instance of a hidden class: " + hc.getName());
syncWithDebugger();
// Invoke a hidden class method.
logMsg("Debuggee: invoking a method of a hidden class: " + hc.getName());
hcObj.hcMethod();
// Provoke a hidden class unload event.
// One more hidden class has to be defined to provoke class unload.
// The first hidden class can not be unloaded. There are some JDI Field's
// or Method's associated with the hidden class which keep it alive.
logMsg("Debuggee: started provoking class unload events");
Class<?> hcForUnload = HiddenClass.defineHiddenClass();
hcForUnload = null;
WB.fullGC(); // force full GC with WB to get hidden class unloaded
logMsg("Debuggee: finished provoking class unload events");
quitSyncWithDebugger();
}
}