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 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 
 64     public static void main(String[] args) {
 65         System.out.println(">>Targ.main");
 66         Value obj = new Value(2); // modify
 67         System.out.println("obj value = " + obj.v); // access
 68         System.out.println("staticField value = " + staticField.v); // access
 69         System.out.println("<<Targ.main");
 70     }
 71 }
 72 
 73 public class FieldWatchpointsTest extends TestScaffold {
 74 
 75     FieldWatchpointsTest (String args[]) {
 76         super(args);
 77     }
 78 
 79     public static void main(String[] args)      throws Exception {
 80         new FieldWatchpointsTest(args).startTests();
 81     }
 82 
 83     boolean equals(ObjectReference obj1, ObjectReference obj2) throws Exception {
 84         return obj1.equals(obj2);
 85     }
 86 
 87     void assertEqual(ObjectReference obj1, ObjectReference obj2) throws Exception {
 88         if (!equals(obj1, obj2)) {
 89             throw new RuntimeException("Values are not equal: " + obj1 + " and " + obj2);
 90         }
 91     }
 92 
 93     void assertNotEqual(ObjectReference obj1, ObjectReference obj2) throws Exception {
 94         if (equals(obj1, obj2)) {
 95             throw new RuntimeException("Values are equal: " + obj1 + " and " + obj2);
 96         }
 97     }
 98 
 99     public void fieldAccessed(AccessWatchpointEvent event) {
100         TestCase.watchpoint(event);
101     }
102 
103     public void fieldModified(ModificationWatchpointEvent event) {
104         TestCase.watchpoint(event);
105     }
106 
107     protected void runTests() throws Exception {
108         List<TestCase> testCases = new ArrayList<>();
109         try {
110             BreakpointEvent bpe = startToMain("FieldWatchpointsTarg");
111             ThreadReference mainThread = bpe.thread();
112             ClassType testClass = (ClassType)bpe.location().declaringType();
113             Field staticValueField = testClass.fieldByName("staticField");
114             ClassType valueClass = (ClassType)staticValueField.type();
115             ObjectReference staticFieldValue = (ObjectReference)testClass.getValue(staticValueField);
116 
117             Field watchField = valueClass.fieldByName("v");
118 
119             WatchpointRequest request = eventRequestManager().createModificationWatchpointRequest(watchField);
120             testCases.add(new TestCase("modify", 1, request)); // obj ctor
121 
122             request = eventRequestManager().createAccessWatchpointRequest(watchField);
123             testCases.add(new TestCase("access", 2, request)); // staticField, obj
124 
125             request = eventRequestManager().createAccessWatchpointRequest(watchField);
126             request.addInstanceFilter(staticFieldValue);
127             testCases.add(new TestCase("access+instanceFilter", 1, request)); // only staticField
128         } finally {
129             listenUntilVMDisconnect();
130         }
131 
132         for (TestCase test: testCases) {
133             String msg = "Testcase: " + test.name
134                         + ", count = " + test.count
135                         + ", expectedCount = " + test.expectedCount;
136             System.out.println(msg);
137             if (test.count != test.expectedCount) {
138                 throw new RuntimeException("FAILED " + msg);
139             }
140         }
141     }
142 
143     class TestCase {
144         String name;
145         int count;
146         int expectedCount;
147         TestCase(String name, int expectedCount, WatchpointRequest request) {
148             this.name = name;
149             this.expectedCount = expectedCount;
150             request.putProperty("testcase", this);
151             request.enable();
152         }
153 
154         static void watchpoint(WatchpointEvent event) {
155             TestCase test = (TestCase)event.request().getProperty("testcase");
156             test.count++;
157         }
158     }
159 }