1 /*
2 * Copyright (c) 2025, 2026, 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 * @summary Redefinition tests that larval_frame stackmaps are adjusted
27 * @enablePreview
28 * @library /test/lib
29 * @run main RedefineClassHelper
30 * @compile StrictFieldsOld.java StrictFieldsNew.java
31 * @run driver jdk.test.lib.helpers.StrictProcessor
32 * StrictFieldsOld StrictFieldsNew
33 * @run main/othervm -Xverify:remote -javaagent:redefineagent.jar RedefineStrictFieldsTest
34 */
35
36 import java.io.InputStream;
37 import static jdk.test.lib.Asserts.assertTrue;
38
39 // Must be placed in top-level package to avoid issues with RedefineClassHelper.
40 public class RedefineStrictFieldsTest {
41
42 // All of this should be moved to RedefineClassHelper
43 private static byte[] getBytecodes(Class<?> thisClass, String name) throws Exception {
44 InputStream is = thisClass.getClassLoader().getResourceAsStream(name + ".class");
45 byte[] buf = is.readAllBytes();
46 System.out.println("sizeof(" + name + ".class) == " + buf.length);
47 return buf;
48 }
49
50 private static int getStringIndex(String needle, byte[] buf) {
51 return getStringIndex(needle, buf, 0);
52 }
53
54 private static int getStringIndex(String needle, byte[] buf, int offset) {
55 outer:
56 for (int i = offset; i < buf.length - offset - needle.length(); i++) {
57 for (int j = 0; j < needle.length(); j++) {
58 if (buf[i + j] != (byte)needle.charAt(j)) continue outer;
59 }
60 return i;
61 }
62 return 0;
63 }
64
65 private static void replaceString(byte[] buf, String name, int index) {
66 for (int i = index; i < index + name.length(); i++) {
67 buf[i] = (byte)name.charAt(i - index);
68 }
69 }
70
71 private static byte[] replaceAllStrings(String oldString, String newString) throws Exception {
72 byte [] buf = getBytecodes(RedefineStrictFieldsTest.class, oldString);
73 assertTrue(oldString.length() == newString.length(), "must have same length");
74 int index = -1;
75 while ((index = getStringIndex(oldString, buf, index + 1)) != 0) {
76 replaceString(buf, newString, index);
77 }
78 return buf;
79 }
80
81 // This should fail because x and y are no longer strict.
82 static String newClassBytes = "class StrictFieldsOld { " +
83 "int x; int y; " +
84 "StrictFieldsOld(boolean a, boolean b) { }" +
85 "public void foo() { System.out.println(x + y );}}";
86
87 public static void main(java.lang.String[] unused) throws Exception {
88
89 StrictFieldsOld old = new StrictFieldsOld(true, false);
90 old.foo();
91
92 // Rename class "StrictFieldsNew" to "StrictFieldsOld" so we can redefine it.
93 byte [] buf = replaceAllStrings("StrictFieldsNew", "StrictFieldsOld");
94 // Now redefine the original version.
95 // If the stackmaps aren't rewritten to point to new constant pool indices, this should get a VerifyError
96 // which RedefineClasses eats and makes into an InternalError. Either way, this test will fail.
97 RedefineClassHelper.redefineClass(StrictFieldsOld.class, buf);
98 StrictFieldsOld newOld = new StrictFieldsOld(true, false);
99 newOld.foo(); // should call the new foo
100
101 // Redefine class without strict fields. Should get a redefinition error.
102 try {
103 RedefineClassHelper.redefineClass(StrictFieldsOld.class, newClassBytes);
104 StrictFieldsOld shouldThrow = new StrictFieldsOld(false, false);
105 shouldThrow.foo(); // Should not be called.
106 throw new RuntimeException("Redefinition should have failed");
107 } catch (java.lang.UnsupportedOperationException uoe) {
108 String msg = uoe.getMessage();
109 assertTrue(msg.contains("class redefinition failed: attempted to change the schema (add/remove fields)"), "FAILED");
110 }
111
112 }
113 }