1 /*
   2  * Copyright (c) 2002, 2015, 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 4628726
  27  * @summary Test class redefinition - method data line numbers and local vars,
  28  * @author Robert Field
  29  *
  30  * @library ..
  31  *
  32  * @run build TestScaffold VMConnection TargetListener TargetAdapter
  33  * @run compile -g RedefineTest.java
  34  * @run shell RedefineSetUp.sh
  35  * @run driver RedefineTest -repeat 3
  36  * @run driver RedefineTest
  37  */
  38 import com.sun.jdi.*;
  39 import com.sun.jdi.event.*;
  40 import com.sun.jdi.request.*;
  41 import java.util.*;
  42 import java.io.*;
  43 
  44     /********** target program **********/
  45 
  46 class RedefineTarg {
  47     public static void main(String[] args){
  48         RedefineSubTarg.stemcp();
  49         RedefineSubTarg sub = new RedefineSubTarg();
  50         sub.bottom();
  51         RedefineSubTarg.stnemcp();
  52         RedefineSubTarg.stemcp();
  53     }
  54 }
  55 
  56     /********** test program **********/
  57 
  58 public class RedefineTest extends TestScaffold {
  59     static int redefineRepeat = 1;
  60     int bpCnt = 0;
  61 
  62     // isObsolete, linenumber, lv name, lv value, lv isArg
  63     String[] before = {
  64     "+ 3",
  65     "+ 6 eights 888 T",
  66     "+ 11 rot 4 F",
  67     "+ 15",
  68     "+ 20 myArg 56 T paramy 12 F",
  69     "+ 24",
  70     "+ 28",
  71     "+ 33" };
  72     String[] after = {
  73     "+ 5",
  74     "O",
  75     "O",
  76     "+ 16",
  77     "+ 21 whoseArg 56 T parawham 12 F",
  78     "+ 25",
  79     "O",
  80     "+ 34" };
  81     String[] shorter = {
  82     "+ 5",
  83     "+ 9 eights 88 T",
  84     "+ 13",
  85     "+ 16",
  86     "+ 21 whoseArg 56 T parawham 12 F",
  87     "+ 25" };
  88     String[] refresh = {
  89     "+ 5",
  90     "+ 9 eights 88 T",
  91     "+ 13",
  92     "+ 16",
  93     "+ 21 whoseArg 56 T parawham 12 F",
  94     "+ 25",
  95     "+ 29",
  96     "+ 34" };
  97     int[] bps = {7, 12, 16, 21, 25, 30, 34};
  98     String[][] bpPlaces = {
  99         {"+ 16"},
 100         {"+ 21 myArg 56 T paramy 12 F"},
 101         {"+ 25"},
 102         {"+ 34"} };
 103 
 104     static String[] processArgs(String args[]) {
 105         if (args.length > 0 && args[0].equals("-repeat")) {
 106             redefineRepeat = Integer.decode(args[1]).intValue();
 107             String[] args2 = new String[args.length - 2];
 108             System.arraycopy(args, 2, args2, 0, args.length - 2);
 109             return args2;
 110         } else {
 111             return args;
 112         }
 113     }
 114 
 115     RedefineTest (String args[]) {
 116         super(args);
 117     }
 118 
 119     public static void main(String[] args)      throws Exception {
 120         new RedefineTest(processArgs(args)).startTests();
 121     }
 122 
 123 
 124     /********** event handlers **********/
 125 
 126     public void breakpointReached(BreakpointEvent event) {
 127         println("Got BreakpointEvent - " + event);
 128         try {
 129             checkFrames(event.thread(), bpPlaces[bpCnt++]);
 130             if (bpCnt >= bpPlaces.length) {
 131                 eventRequestManager().deleteAllBreakpoints();
 132             }
 133         } catch (Exception exc) {
 134             failure("FAIL: breakpoint checking threw " + exc);
 135         }
 136     }
 137 
 138     /********** test assists **********/
 139 
 140     // isObsolete, linenumber, lv name, lv value, lv isArg
 141     // equals: ref type (always), method (not obsolete)
 142     void checkFrames(ThreadReference thread, String[] matchList) throws Exception {
 143         for (int i = 0; i < matchList.length; ++i) {
 144             String match = matchList[i];
 145             StackFrame frame = thread.frame(i);
 146             Location loc = frame.location();
 147             ReferenceType refType = loc.declaringType();
 148             Method meth = loc.method();
 149             String errInfo = "\nframe " + i + ": " + loc + "\n  match: " + match;
 150             if (!findReferenceType("RedefineSubTarg").equals(refType)) {
 151                  failure("FAIL: Bad reference type - " + errInfo);
 152                  return; // might be bad class, but might have run past bottom
 153             }
 154             StringTokenizer st = new StringTokenizer(match);
 155             boolean expectObs = st.nextToken().equals("O");
 156             println("Frame " + i + ": " + meth);
 157             if (meth.isObsolete()) {
 158                 if (!expectObs) {
 159                     failure("FAIL: Method should NOT be obsolete - " + errInfo);
 160                 }
 161             } else {
 162                 if (expectObs) {
 163                     failure("FAIL: Method should be obsolete - " + errInfo);
 164                     break; // no more data to read
 165                 }
 166                 if (!findMethod(refType, meth.name(), meth.signature()).equals(meth)) {
 167                     failure("FAIL: Non matching method - " + errInfo);
 168                 }
 169                 int line = loc.lineNumber();
 170                 if (line != Integer.parseInt(st.nextToken())) {
 171                     failure("FAIL: Unexpected line number: " + errInfo);
 172                 }
 173                 // local var matching
 174                 int lvCnt = 0;
 175                 while (st.hasMoreTokens()) {
 176                     ++lvCnt;
 177                     String lvName = st.nextToken();
 178                     int lvValue = Integer.parseInt(st.nextToken());
 179                     boolean isArg = st.nextToken().equals("T");
 180                     LocalVariable lv = frame.visibleVariableByName(lvName);
 181                     if (lv == null) {
 182                         failure("FAIL: local var not found: '" + lvName +
 183                                 "' -- " + errInfo);
 184                     } else {
 185                         Value val = frame.getValue(lv);
 186                         int ival = ((IntegerValue)val).value();
 187                         if (ival != lvValue) {
 188                             failure("FAIL: expected value: '" + lvValue +
 189                                     "' got: '" + ival + "' -- " + errInfo);
 190                         }
 191                         if (lv.isArgument() != isArg) {
 192                             failure("FAIL: expected argument: '" + isArg +
 193                                     "' got: '" + lv.isArgument() + "' -- " + errInfo);
 194                         }
 195                     }
 196                 }
 197                 List locals = frame.visibleVariables();
 198                 if (locals.size() != lvCnt) {
 199                         failure("FAIL: expected '" + lvCnt +
 200                                 "' locals were '" + locals.size() +
 201                                 "' -- " + errInfo + "' -- " + locals);
 202                 }
 203             }
 204         }
 205     }
 206 
 207 
 208     void doRedefine(String fileName) throws Exception {
 209         File phyl = new File(fileName);
 210         byte[] bytes = new byte[(int)phyl.length()];
 211         InputStream in = new FileInputStream(phyl);
 212         in.read(bytes);
 213         in.close();
 214 
 215         Map map = new HashMap();
 216         map.put(findReferenceType("RedefineSubTarg"), bytes);
 217 
 218         try {
 219             for (int i = 0; i < redefineRepeat; ++i) {
 220                 vm().redefineClasses(map);
 221             }
 222         } catch (Exception thr) {
 223             failure("FAIL: unexpected exception: " + thr);
 224         }
 225     }
 226 
 227     ThreadReference toTop() {
 228         BreakpointEvent bpe = resumeTo("RedefineSubTarg", "top", "()V");
 229         return bpe.thread();
 230     }
 231 
 232     void setBP(int line) {
 233         try {
 234             Location loc = findLocation(findReferenceType("RedefineSubTarg"), line);
 235             final BreakpointRequest request =
 236                 eventRequestManager().createBreakpointRequest(loc);
 237             request.enable();
 238         } catch (Exception exc) {
 239             failure("FAIL: Attempt to set BP at line " + line + " threw " + exc);
 240         }
 241     }
 242 
 243     /********** test core **********/
 244 
 245     protected void runTests() throws Exception {
 246 
 247         startToMain("RedefineTarg");
 248 
 249         ThreadReference thread = toTop();
 250 
 251         println("------ Before Redefine ------");
 252         checkFrames(thread, before);
 253 
 254         println("------ After Redefine ------");
 255         doRedefine("Different_RedefineSubTarg.class");
 256         checkFrames(thread, after);
 257 
 258         println("------ Static 2 ------");
 259         toTop();
 260         checkFrames(thread, shorter);
 261 
 262         println("------ Instance ------");
 263         toTop();
 264         checkFrames(thread, shorter);
 265 
 266         println("------ Re-entered ------");
 267         toTop();
 268         checkFrames(thread, refresh);
 269 
 270         println("------ Breakpoints ------");
 271         doRedefine("RedefineSubTarg.class");
 272         for (int i = 0; i < bps.length; ++i) {
 273             setBP(bps[i]);
 274         }
 275 
 276         /*
 277          * resume the target listening for events
 278          */
 279         listenUntilVMDisconnect();
 280 
 281         if (bpCnt != bpPlaces.length) {
 282             failure("FAIL: Wrong number of breakpoints encountered: " + bpCnt);
 283         }
 284 
 285         /*
 286          * deal with results of test
 287          * if anything has called failure("foo") testFailed will be true
 288          */
 289         if (!testFailed) {
 290             println("RedefineTest(method): passed");
 291         } else {
 292             throw new Exception("RedefineTest(method): failed");
 293         }
 294     }
 295 }