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