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 }