1 /*
2 * Copyright (c) 2020, 2026, 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 package jdk.jfr.event.runtime;
25
26 import java.time.Duration;
27 import java.util.*;
28
29 import jdk.jfr.Recording;
30 import jdk.jfr.consumer.RecordedEvent;
31 import jdk.jfr.consumer.RecordedThread;
32 import jdk.test.lib.jfr.EventNames;
33 import jdk.test.lib.jfr.Events;
34
35 /**
36 * @test
37 * @comment The name of this test (TestSyncOnValueBasedClassEvent) makes
38 * the reader think that we should be able to synchronize on a
39 * ValueBasedClass, but that IS NOT the case because that would
40 * result in an IdentityException.
41 * @comment The purpose of this test is to verify that SyncOnValueBasedClass
42 * JFR events are generated when we synchronize on classes that
43 * WOULD BE ValueBasedClasses IF --enable-preview is enabled. The
44 * purpose of those JFR events is to evaluate Java codebases and
45 * determine if synchronization is used on objects that ARE NOT
46 * compatible with ValueBasedClasses.
47 * @bug 8242263
48 * @requires vm.hasJFR
49 * @requires vm.flagless
50 * @requires !java.enablePreview
51 * @library /test/lib
52 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=2 jdk.jfr.event.runtime.TestSyncOnValueBasedClassEvent
53 */
54 public class TestSyncOnValueBasedClassEvent {
55 static final String EVENT_NAME = EventNames.SyncOnValueBasedClass;
56 static String[] classesWanted = {"java/lang/Character", "java/lang/Boolean", "java/lang/Byte", "java/lang/Short",
57 "java/lang/Integer", "java/lang/Long", "java/lang/Float", "java/lang/Double",
58 "java/lang/Runtime$Version"};
59 static List<Object> testObjects = new ArrayList<Object>();
60 static Integer counter = 0;
61
62 private static void initTestObjects() {
63 testObjects.add(Character.valueOf('H'));
64 testObjects.add(Boolean.valueOf(true));
65 testObjects.add(Byte.valueOf((byte)0x40));
66 testObjects.add(Short.valueOf((short)0x4000));
67 testObjects.add(Integer.valueOf(0x40000000));
68 testObjects.add(Long.valueOf(0x4000000000000000L));
69 testObjects.add(Float.valueOf(1.20f));
70 testObjects.add(Double.valueOf(1.2345));
71 testObjects.add(Runtime.version());
72 }
73
74 public static void main(String[] args) throws Throwable {
75 initTestObjects();
76 Recording recording = new Recording();
77 recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
78 recording.start();
79 for (Object obj : testObjects) {
80 synchronized (obj) {
81 counter++;
82 }
83 }
84 recording.stop();
85
86 List<String> classesFound = new ArrayList<String>();
87 List<RecordedEvent> events = Events.fromRecording(recording);
88 Events.hasEvents(events);
89 for (RecordedEvent event : events) {
90 String className = Events.assertField(event, "valueBasedClass.name").notEmpty().getValue();
91 RecordedThread jt = event.getThread();
92 if (Thread.currentThread().getName().equals(jt.getJavaName())) {
93 classesFound.add(className);
94 }
95 }
96 for (String classWanted : classesWanted) {
97 if (!classesFound.contains(classWanted)) {
98 throw new AssertionError("No matching event SyncOnValueBasedClass with \"valueBasedClass=" + classWanted + "\" and current thread as caller");
99 }
100 }
101 if (classesFound.size() != classesWanted.length) {
102 throw new AssertionError("Invalid number of SyncOnValueBasedClass events for current thread");
103 }
104 }
105 }