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 * @run testng TestNormalizeBlocksTransformer 27 */ 28 29 import org.testng.Assert; 30 import org.testng.annotations.DataProvider; 31 import org.testng.annotations.Test; 32 33 import java.lang.reflect.code.Op; 34 import java.lang.reflect.code.analysis.NormalizeBlocksTransformer; 35 import java.lang.reflect.code.op.ExtendedOp; 36 import java.lang.reflect.code.parser.OpParser; 37 import java.util.stream.Stream; 38 39 public class TestNormalizeBlocksTransformer { 40 static final String TEST1_INPUT = """ 41 func @"f" (%0 : int)int -> { 42 %1 : int = invoke @"C::m()int"; 43 branch ^block_1; 44 45 ^block_1: 46 %2 : int = invoke %1 @"C::m(int)int"; 47 branch ^block_2(%2); 48 49 ^block_2(%3: int): 50 %4 : int = invoke %2 %3 @"C::m(int, int)int"; 51 branch ^block_3(%3); 52 53 ^block_3(%5: int): 54 %6 : int = invoke %4 %3 %5 @"C::m(int, int, int)int"; 55 branch ^block_4; 56 57 ^block_4: 58 return %6; 59 }; 60 """; 61 static final String TEST1_EXPECTED = """ 62 func @"f" (%0 : int)int -> { 63 %1 : int = invoke @"C::m()int"; 64 %2 : int = invoke %1 @"C::m(int)int"; 65 %3 : int = invoke %2 %2 @"C::m(int, int)int"; 66 %4 : int = invoke %3 %2 %2 @"C::m(int, int, int)int"; 67 return %4; 68 }; 69 """; 70 71 static final String TEST2_INPUT = """ 72 func @"f" (%0 : java.lang.Object)void -> { 73 %1 : Var<java.lang.Object> = var %0 @"o"; 74 %2 : java.lang.reflect.code.op.CoreOp$ExceptionRegion = exception.region.enter ^block_1 ^block_3 ^block_8; 75 76 ^block_1: 77 %3 : int = invoke @"A::try_()int"; 78 branch ^block_2; 79 80 ^block_2: 81 exception.region.exit %2 ^block_6; 82 83 ^block_3(%4 : java.lang.RuntimeException): 84 %5 : java.lang.reflect.code.op.CoreOp$ExceptionRegion = exception.region.enter ^block_4 ^block_8; 85 86 ^block_4: 87 %6 : Var<java.lang.RuntimeException> = var %4 @"e"; 88 branch ^block_5; 89 90 ^block_5: 91 exception.region.exit %5 ^block_6; 92 93 ^block_6: 94 %7 : int = invoke @"A::finally_()int"; 95 branch ^block_7; 96 97 ^block_7: 98 return; 99 100 ^block_8(%8 : java.lang.Throwable): 101 %9 : int = invoke @"A::finally_()int"; 102 throw %8; 103 }; 104 """; 105 static final String TEST2_EXPECTED = """ 106 func @"f" (%0 : java.lang.Object)void -> { 107 %1 : Var<java.lang.Object> = var %0 @"o"; 108 %2 : java.lang.reflect.code.op.CoreOp$ExceptionRegion = exception.region.enter ^block_1 ^block_2 ^block_5; 109 110 ^block_1: 111 %3 : int = invoke @"A::try_()int"; 112 exception.region.exit %2 ^block_4; 113 114 ^block_2(%4 : java.lang.RuntimeException): 115 %5 : java.lang.reflect.code.op.CoreOp$ExceptionRegion = exception.region.enter ^block_3 ^block_5; 116 117 ^block_3: 118 %6 : Var<java.lang.RuntimeException> = var %4 @"e"; 119 exception.region.exit %5 ^block_4; 120 121 ^block_4: 122 %7 : int = invoke @"A::finally_()int"; 123 return; 124 125 ^block_5(%8 : java.lang.Throwable): 126 %9 : int = invoke @"A::finally_()int"; 127 throw %8; 128 };"""; 129 130 static final String TEST3_INPUT = """ 131 func @"f" (%0 : int)int -> { 132 %1 : int = constant @"0"; 133 %2 : boolean = gt %0 %1; 134 cbranch %2 ^block_1 ^block_2; 135 136 ^block_1: 137 %3 : int = constant @"1"; 138 branch ^block_1_1; 139 140 ^block_1_1: 141 branch ^block_3(%3); 142 143 ^block_2: 144 %4 : int = constant @"-1"; 145 branch ^block_2_1; 146 147 ^block_2_1: 148 branch ^block_3(%4); 149 150 ^block_3(%5 : int): 151 return %5; 152 };"""; 153 static final String TEST3_EXPECTED = """ 154 func @"f" (%0 : int)int -> { 155 %1 : int = constant @"0"; 156 %2 : boolean = gt %0 %1; 157 cbranch %2 ^block_1 ^block_2; 158 159 ^block_1: 160 %3 : int = constant @"1"; 161 branch ^block_3(%3); 162 163 ^block_2: 164 %4 : int = constant @"-1"; 165 branch ^block_3(%4); 166 167 ^block_3(%5 : int): 168 return %5; 169 }; 170 """; 171 172 static final String TEST4_INPUT = """ 173 func @"f" (%0 : int)int -> { 174 %1 : int = constant @"0"; 175 %2 : boolean = gt %0 %1; 176 cbranch %2 ^block_1 ^block_2; 177 178 ^block_1: 179 %3 : int = constant @"1"; 180 branch ^block_1_1; 181 182 ^block_1_1: 183 branch ^block_3(%0, %3, %1); 184 185 ^block_2: 186 %4 : int = constant @"-1"; 187 branch ^block_2_1; 188 189 ^block_2_1: 190 branch ^block_3(%0, %4, %1); 191 192 ^block_3(%unused_1 : int, %5 : int, %unused_2 : int): 193 return %5; 194 };"""; 195 static final String TEST4_EXPECTED = """ 196 func @"f" (%0 : int)int -> { 197 %1 : int = constant @"0"; 198 %2 : boolean = gt %0 %1; 199 cbranch %2 ^block_1 ^block_2; 200 201 ^block_1: 202 %3 : int = constant @"1"; 203 branch ^block_3(%3); 204 205 ^block_2: 206 %4 : int = constant @"-1"; 207 branch ^block_3(%4); 208 209 ^block_3(%5 : int): 210 return %5; 211 }; 212 """; 213 214 static final String TEST5_INPUT = """ 215 func @"f" ()void -> { 216 %0 : java.lang.reflect.code.op.CoreOp$ExceptionRegion = exception.region.enter ^block_1 ^block_4; 217 218 ^block_1: 219 invoke @"A::m()void"; 220 branch ^block_2; 221 222 ^block_2: 223 exception.region.exit %0 ^block_3; 224 225 ^block_3: 226 branch ^block_5; 227 228 ^block_4(%1 : java.lang.Throwable): 229 branch ^block_5; 230 231 ^block_5: 232 return; 233 }; 234 """; 235 static final String TEST5_EXPECTED = """ 236 func @"f" ()void -> { 237 %0 : java.lang.reflect.code.op.CoreOp$ExceptionRegion = exception.region.enter ^block_1 ^block_3; 238 239 ^block_1: 240 invoke @"A::m()void"; 241 exception.region.exit %0 ^block_2; 242 243 ^block_2: 244 branch ^block_4; 245 246 ^block_3(%1 : java.lang.Throwable): 247 branch ^block_4; 248 249 ^block_4: 250 return; 251 }; 252 """; 253 254 @DataProvider 255 static Object[][] testModels() { 256 return new Object[][]{ 257 parse(TEST1_INPUT, TEST1_EXPECTED), 258 parse(TEST2_INPUT, TEST2_EXPECTED), 259 parse(TEST3_INPUT, TEST3_EXPECTED), 260 parse(TEST4_INPUT, TEST4_EXPECTED), 261 parse(TEST5_INPUT, TEST5_EXPECTED), 262 }; 263 } 264 265 static Object[] parse(String... models) { 266 return Stream.of(models).map(s -> OpParser.fromString(ExtendedOp.FACTORY, s).getFirst()) 267 .toArray(Object[]::new); 268 } 269 270 @Test(dataProvider = "testModels") 271 public void test(Op input, Op expected) { 272 Op actual = NormalizeBlocksTransformer.transform(input); 273 Assert.assertEquals(actual.toText(), expected.toText()); 274 } 275 }