1 /*
2 * Copyright (c) 2025, 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 Sanity test for AccessWatchpoint/ModificationWatchpoint and InstanceFilter with value objects
27 *
28 * @library ..
29 * @enablePreview
30 * @run main/othervm FieldWatchpointsTest
31 * -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseAtomicValueFlattening -XX:+UseNullableValueFlattening
32 * -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlineLayout -XX:+PrintFlatArrayLayout
33 */
34 import com.sun.jdi.Field;
35 import com.sun.jdi.ClassType;
36 import com.sun.jdi.Method;
37 import com.sun.jdi.ObjectReference;
38 import com.sun.jdi.ThreadReference;
39 import com.sun.jdi.Value;
40 import com.sun.jdi.event.AccessWatchpointEvent;
41 import com.sun.jdi.event.BreakpointEvent;
42 import com.sun.jdi.event.ModificationWatchpointEvent;
43 import com.sun.jdi.event.WatchpointEvent;
44 import com.sun.jdi.request.WatchpointRequest;
45 import java.util.ArrayList;
46 import java.util.List;
47
48 value class FieldWatchpointsTarg {
49 static value class Value {
50 int v;
51 Value() {
52 this(0);
53 }
54 Value(int v) {
55 this.v = v;
56 }
57 public int getValue() {
58 return v;
59 }
60 }
61
62 static Value staticField = new Value(1);
63 // flattened field
64 Value instanceField = new Value(2);
65
66 public static void main(String[] args) {
67 System.out.println(">>Targ.main");
68 // modify FieldWatchpointsTarg.instanceField and FieldWatchpointsTarg.instanceField.v
69 FieldWatchpointsTarg targ = new FieldWatchpointsTarg();
70 // access FieldWatchpointsTarg.instanceField and FieldWatchpointsTarg.instanceField.v
71 System.out.println("obj value = " + targ.instanceField.v);
72 // access FieldWatchpointsTarg.staticField and FieldWatchpointsTarg.staticField.v
73 System.out.println("staticField value = " + staticField.v);
74 System.out.println("<<Targ.main");
75 }
76 }
77
78 public class FieldWatchpointsTest extends TestScaffold {
79
80 FieldWatchpointsTest (String args[]) {
81 super(args);
82 }
83
84 public static void main(String[] args) throws Exception {
85 new FieldWatchpointsTest(args).startTests();
86 }
87
88 boolean equals(ObjectReference obj1, ObjectReference obj2) throws Exception {
89 return obj1.equals(obj2);
90 }
91
92 void assertEqual(ObjectReference obj1, ObjectReference obj2) throws Exception {
93 if (!equals(obj1, obj2)) {
94 throw new RuntimeException("Values are not equal: " + obj1 + " and " + obj2);
95 }
96 }
97
98 void assertNotEqual(ObjectReference obj1, ObjectReference obj2) throws Exception {
99 if (equals(obj1, obj2)) {
100 throw new RuntimeException("Values are equal: " + obj1 + " and " + obj2);
101 }
102 }
103
104 public void fieldAccessed(AccessWatchpointEvent event) {
105 TestCase.watchpoint(event);
106 }
107
108 public void fieldModified(ModificationWatchpointEvent event) {
109 TestCase.watchpoint(event);
110 }
111
112 protected void runTests() throws Exception {
113 List<TestCase> testCases = new ArrayList<>();
114 try {
115 BreakpointEvent bpe = startToMain("FieldWatchpointsTarg");
116 ThreadReference mainThread = bpe.thread();
117 ClassType testClass = (ClassType)bpe.location().declaringType();
118 Field staticValueField = testClass.fieldByName("staticField");
119 Field instanceValueField = testClass.fieldByName("instanceField");
120 ClassType valueClass = (ClassType)staticValueField.type();
121 ObjectReference staticFieldValue = (ObjectReference)testClass.getValue(staticValueField);
122
123 Field watchField = valueClass.fieldByName("v");
124
125 WatchpointRequest request = eventRequestManager().createModificationWatchpointRequest(watchField);
126 testCases.add(new TestCase("modify", 1, request)); // instanceField ctor
127
128 request = eventRequestManager().createAccessWatchpointRequest(watchField);
129 testCases.add(new TestCase("access", 2, request)); // staticField, instanceField
130
131 request = eventRequestManager().createModificationWatchpointRequest(instanceValueField);
132 testCases.add(new TestCase("modify flat", 1, request)); // instanceField ctor
133
134 request = eventRequestManager().createAccessWatchpointRequest(instanceValueField);
135 testCases.add(new TestCase("access flat", 1, request)); // println(targ.instanceField.v)
136
137 request = eventRequestManager().createAccessWatchpointRequest(watchField);
138 request.addInstanceFilter(staticFieldValue);
139 testCases.add(new TestCase("access+instanceFilter", 1, request)); // only staticField
140 } finally {
141 listenUntilVMDisconnect();
142 }
143
144 for (TestCase test: testCases) {
145 String msg = "Testcase: " + test.name
146 + ", count = " + test.count
147 + ", expectedCount = " + test.expectedCount;
148 System.out.println(msg);
149 if (test.count != test.expectedCount) {
150 throw new RuntimeException("FAILED " + msg);
151 }
152 }
153 }
154
155 class TestCase {
156 String name;
157 int count;
158 int expectedCount;
159 TestCase(String name, int expectedCount, WatchpointRequest request) {
160 this.name = name;
161 this.expectedCount = expectedCount;
162 request.putProperty("testcase", this);
163 request.enable();
164 }
165
166 static void watchpoint(WatchpointEvent event) {
167 TestCase test = (TestCase)event.request().getProperty("testcase");
168 test.count++;
169 }
170 }
171 }