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