1 /* 2 * Copyright (c) 2024, 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 * @modules jdk.incubator.code 27 * @enablePreview 28 * @run testng TestSynchronizedOp 29 */ 30 31 import jdk.incubator.code.Op; 32 import org.testng.Assert; 33 import org.testng.annotations.Test; 34 35 import java.lang.classfile.ClassFile; 36 import java.lang.classfile.CodeModel; 37 import java.lang.classfile.MethodModel; 38 import java.lang.classfile.Opcode; 39 import java.lang.classfile.instruction.MonitorInstruction; 40 import java.lang.invoke.MethodHandle; 41 import java.lang.invoke.MethodHandles; 42 import java.lang.reflect.Method; 43 import jdk.incubator.code.OpTransformer; 44 import jdk.incubator.code.bytecode.BytecodeGenerator; 45 import jdk.incubator.code.op.CoreOp; 46 import jdk.incubator.code.CodeReflection; 47 import java.util.Map; 48 import java.util.Optional; 49 import java.util.stream.Collectors; 50 import java.util.stream.Stream; 51 52 public class TestSynchronizedOp { 53 54 @CodeReflection 55 static int f(Object o, int i, int[] a) { 56 synchronized (o) { 57 if (i < 0) { 58 throw new RuntimeException(); 59 } 60 a[0] = ++i; 61 } 62 return i; 63 } 64 65 @Test 66 public void testInstructions() { 67 CoreOp.FuncOp f = getFuncOp("f"); 68 f = f.transform(OpTransformer.LOWERING_TRANSFORMER); 69 70 byte[] classdata = BytecodeGenerator.generateClassData(MethodHandles.lookup(), f); 71 CodeModel cmf = ClassFile.of().parse(classdata).methods().stream() 72 .filter(mm -> mm.methodName().equalsString("f")) 73 .findFirst().flatMap(MethodModel::code).orElseThrow(); 74 Map<Opcode, Long> monitorCount = cmf.elementStream().<Opcode>mapMulti((i, c) -> { 75 if (i instanceof MonitorInstruction mi) { 76 c.accept(mi.opcode()); 77 } 78 }).collect(Collectors.groupingBy(oc -> oc, Collectors.counting())); 79 Assert.assertEquals(monitorCount, Map.of( 80 Opcode.MONITORENTER, 1L, 81 Opcode.MONITOREXIT, 2L)); 82 } 83 84 @Test 85 public void testExecution() throws Throwable { 86 CoreOp.FuncOp f = getFuncOp("f"); 87 f = f.transform(OpTransformer.LOWERING_TRANSFORMER); 88 89 MethodHandle mf = BytecodeGenerator.generate(MethodHandles.lookup(), f); 90 91 Object monitor = new Object(); 92 int[] a = new int[1]; 93 Assert.assertEquals((int) mf.invoke(monitor, 0, a), 1); 94 a[0] = 0; 95 Assert.assertThrows(RuntimeException.class, () -> { 96 int i = (int) mf.invoke(monitor, -1, a); 97 }); 98 Assert.assertEquals(a[0], 0); 99 } 100 101 static CoreOp.FuncOp getFuncOp(String name) { 102 Optional<Method> om = Stream.of(TestSynchronizedOp.class.getDeclaredMethods()) 103 .filter(m -> m.getName().equals(name)) 104 .findFirst(); 105 106 Method m = om.get(); 107 return Op.ofMethod(m).get(); 108 } 109 }