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 }