/*
* Copyright (c) 2002, 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 main RedefineTest -repeat 3
* @run main 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");
}
}
}