/* * Copyright (c) 2002, 2024, 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.Method.isObsolete; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdi.*; import com.sun.jdi.*; import com.sun.jdi.connect.*; import com.sun.jdi.request.*; import com.sun.jdi.event.*; import java.io.*; import java.util.*; /** */ public class isobsolete003 { private final static String prefix = "nsk.jdi.Method.isObsolete"; private final static String className = ".isobsolete003"; private final static String debuggerName = prefix + className; private final static String debuggeeName = debuggerName + "a"; private final static int brkpMainLineNumber = 48; private final static int brkpFooLineNumber = 33; private static int waitTime; private static int exitStatus; private static ArgumentHandler argHandler; private static Log log; private static Debugee debuggee; private static VirtualMachine vm; private static ReferenceType debuggeeClass; private static EventRequestManager eventRManager; private static EventSet eventSet; private static EventIterator eventIterator; public static void main(String argv[]) { int result = run(argv,System.out); if (result != 0) { throw new RuntimeException("TEST FAILED with result " + result); } } public static int run(String argv[], PrintStream out) { exitStatus = Consts.TEST_PASSED; argHandler = new ArgumentHandler(argv); log = new Log(out, argHandler); waitTime = argHandler.getWaitTime() * 60000; try { Binder binder = new Binder(argHandler, log); debuggee = binder.bindToDebugee(debuggeeName); debuggee.redirectStderr(log, "debuggee > "); debuggee.createIOPipe(); eventRManager = debuggee.getEventRequestManager(); vm = debuggee.VM(); eventRManager = vm.eventRequestManager(); waitForDebuggeeClassPrepared(); if (vm.canRedefineClasses()) { execTest(); debuggee.resume(); getEventSet(); if (eventIterator.nextEvent() instanceof VMDeathEvent) { display("Waiting for the debuggee's finish..."); debuggee.waitFor(); display("Getting the debuggee's exit status."); int status = debuggee.getStatus(); if (status != (Consts.TEST_PASSED + Consts.JCK_STATUS_BASE)) { complain("Debuggee returned UNEXPECTED exit status: " + status); exitStatus = Consts.TEST_FAILED; } } else { throw new TestBug("Last event is not the VMDeathEvent"); } } else { display("vm.canRedefineClasses() == false : test is cancelled"); vm.exit(Consts.TEST_PASSED + Consts.JCK_STATUS_BASE); } } catch (VMDisconnectedException e) { exitStatus = Consts.TEST_FAILED; complain("The test cancelled due to VMDisconnectedException."); e.printStackTrace(out); display("Trying: vm.process().destroy();"); if (vm != null) { Process vmProcess = vm.process(); if (vmProcess != null) { vmProcess.destroy(); } } } catch (Exception e) { exitStatus = Consts.TEST_FAILED; complain("Unexpected Exception: " + e.getMessage()); e.printStackTrace(out); complain("The test has not finished normally. Forcing: vm.exit()."); if (vm != null) { vm.exit(Consts.TEST_PASSED + Consts.JCK_STATUS_BASE); } debuggee.resume(); getEventSet(); } return exitStatus; } private static void execTest() { ThreadReference mainThread = debuggee.threadByName("main"); // Set first breakpoint to have isobsolete003b class loaded. BreakpointRequest bpRequest = debuggee.makeBreakpoint(debuggeeClass, "main", brkpMainLineNumber); bpRequest.addThreadFilter(mainThread); bpRequest.addCountFilter(1); bpRequest.enable(); waitForEvent(bpRequest); bpRequest.disable(); // At this point isobsolete003b class should be loaded in debuggee. String redefName = prefix + ".isobsolete003b"; ReferenceType redefClass = debuggee.classByName(redefName); if (redefClass == null) { throw new TestBug(redefName + "is not found in debuggee."); } String methodName = "foo"; Method method = (Method) redefClass.methodsByName(methodName).get(0); // save some values for check in future Method oldMethod = method; Location oldLocation = method.location(); long oldCodeIndex = oldLocation.codeIndex(); String oldRetTypeName = method.returnTypeName(); int oldHashCode = method.hashCode(); // Set new breakpoint to have isobsolete003b.foo() method on stack before redefinition. bpRequest = debuggee.makeBreakpoint(redefClass, methodName, brkpFooLineNumber); bpRequest.addThreadFilter(mainThread); bpRequest.addCountFilter(1); bpRequest.enable(); waitForEvent(bpRequest); bpRequest.disable(); display("requested BreakpointEvent for foo() method received;"); try { if (!mainThread.frame(0).location().method().equals(method)) { throw new TestBug("foo() method is not on the top of the main thread stack"); } } catch (IncompatibleThreadStateException e) { throw new Failure("Unexpected IncompatibleThreadStateException while comparing mainThread.frame(0).location().method(): " + e.getMessage()); } display("Making redefineClasses(mapClassToBytes())."); vm.redefineClasses(mapClassToBytes()); // Check isObsolete after redefinition try { method = mainThread.frame(0).location().method(); } catch (IncompatibleThreadStateException e) { throw new Failure("Unexpected IncompatibleThreadStateException while getting mainThread.frame(0).location().method(): " + e.getMessage()); } if (!method.isObsolete()) { complain("method.isObsolete() == true for foo() method after redefineClasses()"); exitStatus = Consts.TEST_FAILED; } else { // Do other checks for obsolete method. if (method.equals(oldMethod)) { complain("equals(oldMethod) returned true for obsolete method."); exitStatus = Consts.TEST_FAILED; } List l = null; Location loc = null; try { l = method.allLineLocations(); if (l.size() > 0) { complain("allLineLocations() returned a list with non-zero size for obsolete method." + "Number of Locations :" + l.size()); exitStatus = Consts.TEST_FAILED; } } catch (AbsentInformationException e) { // it is expected } try { l = method.allLineLocations(vm.getDefaultStratum(), null); if (l.size() > 0) { complain("allLineLocations(vm.getDefaultStratum(), null) returned a list with non-zero size for obsolete method." + "Number of Locations :" + l.size()); exitStatus = Consts.TEST_FAILED; } } catch (AbsentInformationException e) { // it is expected } try { l = method.locationsOfLine(1); if (l.size() > 0) { complain("locationsOfLine(1) returned a list with non-zero size for obsolete method." + "Number of Locations :" + l.size()); exitStatus = Consts.TEST_FAILED; } } catch (AbsentInformationException e) { // it is expected } try { l = method.locationsOfLine(vm.getDefaultStratum(), null, 1); if (l.size() > 0) { complain("locationsOfLine(vm.getDefaultStratum(), null, 1) returned a list with non-zero size for obsolete method." + "Number of Locations :" + l.size()); exitStatus = Consts.TEST_FAILED; } } catch (AbsentInformationException e) { // it is expected } try { l = method.arguments(); if (l.size() > 0) { complain("arguments() returned a list with non-zero size for obsolete method." + "Size of list :" + l.size()); exitStatus = Consts.TEST_FAILED; } } catch (AbsentInformationException e) { // it is expected } l = method.argumentTypeNames(); if (l.size() > 0) { complain("argumentTypeNames() returned a list with non-zero size for obsolete method." + "Size of list :" + l.size()); exitStatus = Consts.TEST_FAILED; } try { l = method.argumentTypes(); if (l.size() > 0) { complain("argumentsTypes() returned a list with non-zero size for obsolete method." + "Size of list :" + l.size()); exitStatus = Consts.TEST_FAILED; } } catch (ClassNotLoadedException e) { // it is expected } try { l = method.variables(); if (l.size() > 0) { complain("variables() returned a list with non-zero size for obsolete method." + "Size of list :" + l.size()); exitStatus = Consts.TEST_FAILED; } } catch (AbsentInformationException e) { // it is expected } try { l = method.variablesByName("dummyInt"); if (l.size() > 0) { complain("variablesByName(oldVar.name()) returned a list with non-zero size for obsolete method." + "Size of list :" + l.size()); exitStatus = Consts.TEST_FAILED; } } catch (AbsentInformationException e) { // it is expected } byte[] b = method.bytecodes(); if (b.length > 0) { complain("bytecodes() returned an array with non-zero length for obsolete method." + "Number of bytes :" + b.length); exitStatus = Consts.TEST_FAILED; } loc = method.location(); if (loc != null && loc == oldLocation) { complain("location() returned old location for obsolete method."); exitStatus = Consts.TEST_FAILED; } loc = method.locationOfCodeIndex(oldCodeIndex); if (loc != null) { complain("locationOfCodeIndex(oldCodeIndex) returned not-null location for obsolete method."); exitStatus = Consts.TEST_FAILED; } String rtName = method.returnTypeName(); if (rtName.equals(oldRetTypeName)) { complain("returnTypeName() returned an old string for obsolete method: " + rtName); exitStatus = Consts.TEST_FAILED; } try { Type rType = method.returnType(); if (rType != null) { complain("returnType() returned not-null Type for obsolete method: " + rType.name()); exitStatus = Consts.TEST_FAILED; } } catch (ClassNotLoadedException e) { // it is expected } int hashCode = method.hashCode(); if (hashCode == oldHashCode) { complain("hashCode() returned old value for obsolete method: " + hashCode); exitStatus = Consts.TEST_FAILED; } } } private static void display(String msg) { log.display("debugger > " + msg); } private static void complain(String msg) { log.complain("debugger FAILURE > " + msg); } /** * Returns Map object for redefinition. * */ private static Map mapClassToBytes() { String[] args = argHandler.getArguments(); if (args.length <= 0) { throw new Failure("mapClassToBytes(): Test arguments are not found."); } String testDir = args[0]; display("Test current dir = " + testDir); String filePrefix = File.separator + "nsk" + File.separator + "jdi" + File.separator + "Method" + File.separator + "isObsolete"; String fileToRedefineName = testDir + File.separator + "newclass" + filePrefix + File.separator + "isobsolete003b.class"; display("fileToRedefineName : " + fileToRedefineName); byte[] arrayToRedefine; try { File fileToRedefine = new File(fileToRedefineName); if (!fileToRedefine.exists()) { throw new Failure("mapClassToBytes(): fileToRedefine does not exist"); } FileInputStream inputFile = new FileInputStream(fileToRedefine); arrayToRedefine = new byte [(int) fileToRedefine.length()]; inputFile.read(arrayToRedefine); inputFile.close(); } catch (IOException e) { complain("unexpected IOException: " + e); throw new Failure(e); } String testClassName = prefix + ".isobsolete003b"; ReferenceType testClass = debuggee.classByName(testClassName); HashMap mapForClass = new HashMap(); mapForClass.put(testClass, arrayToRedefine); return mapForClass; } private static Event waitForEvent (EventRequest evRequest) { vm.resume(); Event resultEvent = null; try { eventSet = null; eventIterator = null; eventSet = vm.eventQueue().remove(waitTime); if (eventSet == null) { throw new Failure("TIMEOUT while waiting for an event"); } eventIterator = eventSet.eventIterator(); while (eventIterator.hasNext()) { Event curEvent = eventIterator.nextEvent(); if (curEvent instanceof VMDisconnectEvent) { throw new Failure("Unexpected VMDisconnectEvent received."); } else if (curEvent.request().equals(evRequest)) { display("Requested event received."); resultEvent = curEvent; break; } else { throw new TestBug("Unexpected Event received: " + curEvent.toString()); } } } catch (Exception e) { throw new Failure("Unexpected exception while waiting for an event: " + e); } return resultEvent; } private static void getEventSet() { try { eventSet = vm.eventQueue().remove(waitTime); if (eventSet == null) { throw new Failure("TIMEOUT while waiting for an event"); } eventIterator = eventSet.eventIterator(); } catch (Exception e) { throw new Failure("getEventSet(): Unexpected exception while waiting for an event: " + e); } } private static void waitForDebuggeeClassPrepared () { display("Creating request for ClassPrepareEvent for debuggee."); ClassPrepareRequest cpRequest = eventRManager.createClassPrepareRequest(); cpRequest.addClassFilter(debuggeeName); cpRequest.addCountFilter(1); cpRequest.enable(); ClassPrepareEvent event = (ClassPrepareEvent) waitForEvent(cpRequest); cpRequest.disable(); debuggeeClass = event.referenceType(); if (!debuggeeClass.name().equals(debuggeeName)) throw new Failure("Unexpected class name for ClassPrepareEvent : " + debuggeeClass.name()); } }