1 /* 2 * Copyright (c) 2001, 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 4287595 27 * @bug 4462989 28 * @bug 4531511 29 * @summary Test class redefinition 30 * 31 * @author Robert Field 32 * 33 * @library .. 34 * @modules jdk.jdi 35 * @run build TestScaffold VMConnection TargetListener TargetAdapter 36 * @run compile -g RedefineTest.java 37 * @run shell RedefineSetUp.sh 38 * @run driver RedefineTest 39 */ 40 import com.sun.jdi.*; 41 import com.sun.jdi.event.*; 42 import com.sun.jdi.request.*; 43 import java.util.*; 44 import java.io.*; 45 46 /********** target program **********/ 47 48 class RedefineTarg { 49 public static void show(String where){ 50 System.out.println("Returned: " + where); 51 } 52 53 public static void lastly(String where){ 54 } 55 56 public static void main(String[] args){ 57 RedefineSubTarg sub = new RedefineSubTarg(); 58 String where = ""; 59 for (int i = 0; i < 5; ++i) { 60 where = sub.foo(where); 61 show(where); 62 } 63 lastly(where); 64 } 65 } 66 67 /********** test program **********/ 68 69 public class RedefineTest extends TestScaffold { 70 ReferenceType targetClass; 71 static final String expected ="Boring Boring Different Boring Different "; 72 int repetitionCount = 0; 73 boolean beforeRedefine = true; 74 75 RedefineTest (String args[]) { 76 super(args); 77 } 78 79 public static void main(String[] args) throws Exception { 80 new RedefineTest(args).startTests(); 81 } 82 83 /********** event handlers **********/ 84 85 public void methodEntered(MethodEntryEvent event) { 86 Method meth = event.location().method(); 87 ThreadReference thread = event.thread(); 88 89 if (meth.name().equals("foo")) { 90 ++repetitionCount; 91 beforeRedefine = true; 92 try { 93 expectNonObsolete(thread); 94 inspectLineNumber(event, thread.frame(0)); 95 96 doRedefine(thread); 97 beforeRedefine = false; 98 99 switch (repetitionCount) { 100 case 1: 101 case 5: 102 expectNonObsolete(thread); 103 inspectLineNumber(event, thread.frame(0)); 104 break; 105 case 2: 106 case 3: 107 case 4: 108 expectObsolete(thread); 109 inspectLineNumber(event, thread.frame(0)); 110 break; 111 } 112 113 114 } catch (Exception exc) { 115 failure("Test Failure: unexpected exception - " + exc); 116 exc.printStackTrace(); 117 } 118 } 119 } 120 121 public void breakpointReached(BreakpointEvent event) { 122 ThreadReference thread = event.thread(); 123 try { 124 StackFrame frame = thread.frame(0); 125 LocalVariable lv = frame.visibleVariableByName("where"); 126 Value vWhere = frame.getValue(lv); 127 String remoteWhere = ((StringReference)vWhere).value(); 128 println("Value of where: " + remoteWhere); 129 if (!remoteWhere.equals(expected)) { 130 failure("FAIL: expected result string: '" + expected + 131 "' got: '" + remoteWhere + "'"); 132 } 133 } catch (Exception thr) { 134 failure("Test Failure: unexpected exception: " + thr); 135 } 136 } 137 138 /********** test assists **********/ 139 140 void expectNonObsolete(ThreadReference thread) throws Exception { 141 if (isObsolete(thread)) { 142 failure("FAIL: Method should NOT be obsolete"); 143 } else { 144 println("as it should be, not obsolete"); 145 } 146 } 147 148 void expectObsolete(ThreadReference thread) throws Exception { 149 if (isObsolete(thread)) { 150 println("obsolete like it should be"); 151 } else { 152 failure("FAIL: Method should be obsolete"); 153 } 154 } 155 156 void inspectLineNumber(LocatableEvent event, StackFrame frame) throws Exception { 157 /* 158 * For each value of repetitionCount, use the beforeRedefine 159 * boolean to distinguish the time before and after the actual 160 * redefinition takes place. Line numbers are inspected both 161 * before and after each redefine. 162 */ 163 int n = -1; 164 int expectedLine = -1; 165 switch (repetitionCount) { 166 case 1: 167 expectedLine = 4; 168 break; 169 case 2: 170 expectedLine = beforeRedefine ? 4:21; 171 break; 172 case 3: 173 expectedLine = beforeRedefine ? 21:4; 174 break; 175 case 4: 176 expectedLine = beforeRedefine ? 4:21; 177 break; 178 case 5: 179 /* The class won't be redefined on this iteration (look 180 * for a java.lang.UnsupportedOperationException instead) 181 * so expected line stays the same as last successful 182 * redefine. 183 */ 184 expectedLine = 21; 185 break; 186 } 187 Method method = event.location().method(); 188 if (frame.location().method().isObsolete()) { 189 /* 190 * Then skip. Obsolete methods are not interesting to 191 * inspect. 192 */ 193 println("inspectLineNumber skipping obsolete method " + method.name()); 194 } else { 195 n = method.location().lineNumber(); 196 int m = frame.location().lineNumber(); 197 if ((n != expectedLine) || (n != m)) { 198 failure("Test Failure: line number disagreement: " + 199 n + " (event) versus " + m + " (frame) versus " + expectedLine + 200 " (expected)"); 201 } else { 202 println("inspectLineNumber in method " + method.name() + " at line " + n); 203 } 204 } 205 } 206 207 boolean isObsolete(ThreadReference thread) throws Exception { 208 StackFrame frame = thread.frame(0); 209 Method meth = frame.location().method(); 210 return meth.isObsolete(); 211 } 212 213 void doRedefine(ThreadReference thread) throws Exception { 214 Exception receivedException = null; 215 String fileName = "notThis"; 216 217 switch (repetitionCount) { 218 case 1: 219 fileName = "RedefineSubTarg.class"; 220 break; 221 case 2: 222 fileName = "Different_RedefineSubTarg.class"; 223 break; 224 case 3: 225 fileName = "RedefineSubTarg.class"; 226 break; 227 case 4: 228 fileName = "Different_RedefineSubTarg.class"; 229 break; 230 case 5: 231 fileName = "SchemaChange_RedefineSubTarg.class"; 232 break; 233 } 234 File phyl = new File(fileName); 235 byte[] bytes = new byte[(int)phyl.length()]; 236 InputStream in = new FileInputStream(phyl); 237 in.read(bytes); 238 in.close(); 239 240 Map map = new HashMap(); 241 map.put(findReferenceType("RedefineSubTarg"), bytes); 242 243 println(System.getProperty("line.separator") + "Iteration # " + repetitionCount + 244 " ------ Redefine as: " + fileName); 245 try { 246 vm().redefineClasses(map); 247 } catch (Exception thr) { 248 receivedException = thr; 249 } 250 switch (repetitionCount) { 251 case 5: 252 if (receivedException == null) { 253 failure("FAIL: no exception; expected: UnsupportedOperationException"); 254 } else if (receivedException instanceof UnsupportedOperationException) { 255 println("Received expected exception: " + receivedException); 256 } else { 257 failure("FAIL: got exception: " + receivedException + 258 ", expected: UnsupportedOperationException"); 259 } 260 break; 261 default: 262 if (receivedException != null) { 263 failure("FAIL: unexpected exception: " + 264 receivedException); 265 } 266 break; 267 } 268 return; 269 } 270 271 /********** test core **********/ 272 273 protected void runTests() throws Exception { 274 275 BreakpointEvent bpe = startToMain("RedefineTarg"); 276 targetClass = bpe.location().declaringType(); 277 EventRequestManager erm = vm().eventRequestManager(); 278 279 /* 280 * Method entry in sub targ 281 */ 282 MethodEntryRequest mee = erm.createMethodEntryRequest(); 283 mee.addClassFilter("RedefineSubTarg"); 284 mee.enable(); 285 286 /* 287 * BP at end to get value 288 */ 289 List lastlys = targetClass.methodsByName("lastly"); 290 if (lastlys.size() != 1) { 291 throw new Exception ("TestFailure: Expected one 'lastly' method, found: " + 292 lastlys); 293 } 294 Location loc = ((Method)(lastlys.get(0))).location(); 295 EventRequest req = erm.createBreakpointRequest(loc); 296 req.enable(); 297 298 // Allow application to complete and shut down 299 listenUntilVMDisconnect(); 300 301 /* 302 * deal with results of test 303 * if anything has called failure("foo") testFailed will be true 304 */ 305 if (!testFailed) { 306 println("RedefineTest: passed"); 307 } else { 308 throw new Exception("RedefineTest: failed"); 309 } 310 } 311 }