/* * Copyright (c) 2002, 2015, 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 4628726 * @summary Test class redefinition - method data line numbers and local vars, * @author Robert Field * * @library .. * * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g RedefineTest.java * @run shell RedefineSetUp.sh * @run driver RedefineTest -repeat 3 * @run driver RedefineTest */ import com.sun.jdi.*; import com.sun.jdi.event.*; import com.sun.jdi.request.*; import java.util.*; import java.io.*; /********** target program **********/ class RedefineTarg { public static void main(String[] args){ RedefineSubTarg.stemcp(); RedefineSubTarg sub = new RedefineSubTarg(); sub.bottom(); RedefineSubTarg.stnemcp(); RedefineSubTarg.stemcp(); } } /********** test program **********/ public class RedefineTest extends TestScaffold { static int redefineRepeat = 1; int bpCnt = 0; // isObsolete, linenumber, lv name, lv value, lv isArg String[] before = { "+ 3", "+ 6 eights 888 T", "+ 11 rot 4 F", "+ 15", "+ 20 myArg 56 T paramy 12 F", "+ 24", "+ 28", "+ 33" }; String[] after = { "+ 5", "O", "O", "+ 16", "+ 21 whoseArg 56 T parawham 12 F", "+ 25", "O", "+ 34" }; String[] shorter = { "+ 5", "+ 9 eights 88 T", "+ 13", "+ 16", "+ 21 whoseArg 56 T parawham 12 F", "+ 25" }; String[] refresh = { "+ 5", "+ 9 eights 88 T", "+ 13", "+ 16", "+ 21 whoseArg 56 T parawham 12 F", "+ 25", "+ 29", "+ 34" }; int[] bps = {7, 12, 16, 21, 25, 30, 34}; String[][] bpPlaces = { {"+ 16"}, {"+ 21 myArg 56 T paramy 12 F"}, {"+ 25"}, {"+ 34"} }; static String[] processArgs(String args[]) { if (args.length > 0 && args[0].equals("-repeat")) { redefineRepeat = Integer.decode(args[1]).intValue(); String[] args2 = new String[args.length - 2]; System.arraycopy(args, 2, args2, 0, args.length - 2); return args2; } else { return args; } } RedefineTest (String args[]) { super(args); } public static void main(String[] args) throws Exception { new RedefineTest(processArgs(args)).startTests(); } /********** event handlers **********/ public void breakpointReached(BreakpointEvent event) { println("Got BreakpointEvent - " + event); try { checkFrames(event.thread(), bpPlaces[bpCnt++]); if (bpCnt >= bpPlaces.length) { eventRequestManager().deleteAllBreakpoints(); } } catch (Exception exc) { failure("FAIL: breakpoint checking threw " + exc); } } /********** test assists **********/ // isObsolete, linenumber, lv name, lv value, lv isArg // equals: ref type (always), method (not obsolete) void checkFrames(ThreadReference thread, String[] matchList) throws Exception { for (int i = 0; i < matchList.length; ++i) { String match = matchList[i]; StackFrame frame = thread.frame(i); Location loc = frame.location(); ReferenceType refType = loc.declaringType(); Method meth = loc.method(); String errInfo = "\nframe " + i + ": " + loc + "\n match: " + match; if (!findReferenceType("RedefineSubTarg").equals(refType)) { failure("FAIL: Bad reference type - " + errInfo); return; // might be bad class, but might have run past bottom } StringTokenizer st = new StringTokenizer(match); boolean expectObs = st.nextToken().equals("O"); println("Frame " + i + ": " + meth); if (meth.isObsolete()) { if (!expectObs) { failure("FAIL: Method should NOT be obsolete - " + errInfo); } } else { if (expectObs) { failure("FAIL: Method should be obsolete - " + errInfo); break; // no more data to read } if (!findMethod(refType, meth.name(), meth.signature()).equals(meth)) { failure("FAIL: Non matching method - " + errInfo); } int line = loc.lineNumber(); if (line != Integer.parseInt(st.nextToken())) { failure("FAIL: Unexpected line number: " + errInfo); } // local var matching int lvCnt = 0; while (st.hasMoreTokens()) { ++lvCnt; String lvName = st.nextToken(); int lvValue = Integer.parseInt(st.nextToken()); boolean isArg = st.nextToken().equals("T"); LocalVariable lv = frame.visibleVariableByName(lvName); if (lv == null) { failure("FAIL: local var not found: '" + lvName + "' -- " + errInfo); } else { Value val = frame.getValue(lv); int ival = ((IntegerValue)val).value(); if (ival != lvValue) { failure("FAIL: expected value: '" + lvValue + "' got: '" + ival + "' -- " + errInfo); } if (lv.isArgument() != isArg) { failure("FAIL: expected argument: '" + isArg + "' got: '" + lv.isArgument() + "' -- " + errInfo); } } } List locals = frame.visibleVariables(); if (locals.size() != lvCnt) { failure("FAIL: expected '" + lvCnt + "' locals were '" + locals.size() + "' -- " + errInfo + "' -- " + locals); } } } } void doRedefine(String fileName) throws Exception { File phyl = new File(fileName); byte[] bytes = new byte[(int)phyl.length()]; InputStream in = new FileInputStream(phyl); in.read(bytes); in.close(); Map map = new HashMap(); map.put(findReferenceType("RedefineSubTarg"), bytes); try { for (int i = 0; i < redefineRepeat; ++i) { vm().redefineClasses(map); } } catch (Exception thr) { failure("FAIL: unexpected exception: " + thr); } } ThreadReference toTop() { BreakpointEvent bpe = resumeTo("RedefineSubTarg", "top", "()V"); return bpe.thread(); } void setBP(int line) { try { Location loc = findLocation(findReferenceType("RedefineSubTarg"), line); final BreakpointRequest request = eventRequestManager().createBreakpointRequest(loc); request.enable(); } catch (Exception exc) { failure("FAIL: Attempt to set BP at line " + line + " threw " + exc); } } /********** test core **********/ protected void runTests() throws Exception { startToMain("RedefineTarg"); ThreadReference thread = toTop(); println("------ Before Redefine ------"); checkFrames(thread, before); println("------ After Redefine ------"); doRedefine("Different_RedefineSubTarg.class"); checkFrames(thread, after); println("------ Static 2 ------"); toTop(); checkFrames(thread, shorter); println("------ Instance ------"); toTop(); checkFrames(thread, shorter); println("------ Re-entered ------"); toTop(); checkFrames(thread, refresh); println("------ Breakpoints ------"); doRedefine("RedefineSubTarg.class"); for (int i = 0; i < bps.length; ++i) { setBP(bps[i]); } /* * resume the target listening for events */ listenUntilVMDisconnect(); if (bpCnt != bpPlaces.length) { failure("FAIL: Wrong number of breakpoints encountered: " + bpCnt); } /* * deal with results of test * if anything has called failure("foo") testFailed will be true */ if (!testFailed) { println("RedefineTest(method): passed"); } else { throw new Exception("RedefineTest(method): failed"); } } }