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