1 /* 2 * Copyright (c) 2014, 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 import com.oracle.testlibrary.jsr292.Helper; 25 import java.lang.invoke.MethodHandle; 26 import java.lang.invoke.MethodHandles; 27 import java.lang.invoke.MethodType; 28 import java.lang.reflect.Array; 29 import java.util.ArrayList; 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Map; 33 34 /** 35 * Enumeration containing information about methods from 36 * {@code j.l.i.MethodHandles} class that are used for testing lambda forms 37 * caching. 38 * 39 * @author kshefov 40 */ 41 public enum TestMethods { 42 43 FOLD_ARGUMENTS("foldArguments") { 44 @Override 45 public Map<String, Object> getTestCaseData() { 46 Map<String, Object> data = new HashMap<>(); 47 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 48 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 49 data.put("mtTarget", mtTarget); 50 // Arity after reducing because of long and double take 2 slots. 51 int realArity = mtTarget.parameterCount(); 52 int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); 53 data.put("modifierMHArgNum", modifierMHArgNum); 54 Class<?> combinerReturnType; 55 if (realArity == 0) { 56 combinerReturnType = void.class; 57 } else { 58 combinerReturnType = Helper.RNG.nextBoolean() ? void.class : mtTarget.parameterType(0); 59 } 60 data.put("combinerReturnType", combinerReturnType); 61 return data; 62 } 63 64 @Override 65 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 66 MethodType mtTarget = (MethodType) data.get("mtTarget"); 67 Class<?> combinerReturnType = (Class) data.get("combinerReturnType"); 68 int modifierMHArgNum = (int) data.get("modifierMHArgNum"); 69 MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 70 mtTarget.parameterList(), kind); 71 Class<?> rType = mtTarget.returnType(); 72 int combListStart = (combinerReturnType == void.class) ? 0 : 1; 73 if (modifierMHArgNum < combListStart) { 74 modifierMHArgNum = combListStart; 75 } 76 MethodHandle combiner = TestMethods.methodHandleGenerator(combinerReturnType, 77 mtTarget.parameterList().subList(combListStart, 78 modifierMHArgNum), kind); 79 return MethodHandles.foldArguments(target, combiner); 80 } 81 }, 82 DROP_ARGUMENTS("dropArguments") { 83 @Override 84 public Map<String, Object> getTestCaseData() { 85 Map<String, Object> data = new HashMap<>(); 86 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 87 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 88 data.put("mtTarget", mtTarget); 89 // Arity after reducing because of long and double take 2 slots. 90 int realArity = mtTarget.parameterCount(); 91 int dropArgsPos = Helper.RNG.nextInt(realArity + 1); 92 data.put("dropArgsPos", dropArgsPos); 93 MethodType mtDropArgs = TestMethods.randomMethodTypeGenerator( 94 Helper.RNG.nextInt(Helper.MAX_ARITY - realArity)); 95 data.put("mtDropArgs", mtDropArgs); 96 return data; 97 } 98 99 @Override 100 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 101 MethodType mtTarget = (MethodType) data.get("mtTarget"); 102 MethodType mtDropArgs = (MethodType) data.get("mtDropArgs"); 103 int dropArgsPos = (int) data.get("dropArgsPos"); 104 MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 105 mtTarget.parameterList(), kind); 106 int mtTgtSlotsCount = TestMethods.argSlotsCount(mtTarget); 107 int mtDASlotsCount = TestMethods.argSlotsCount(mtDropArgs); 108 List<Class<?>> fakeParList; 109 if (mtTgtSlotsCount + mtDASlotsCount > Helper.MAX_ARITY - 1) { 110 fakeParList = TestMethods.reduceArgListToSlotsCount(mtDropArgs.parameterList(), 111 Helper.MAX_ARITY - mtTgtSlotsCount - 1); 112 } else { 113 fakeParList = mtDropArgs.parameterList(); 114 } 115 return MethodHandles.dropArguments(target, dropArgsPos, fakeParList); 116 } 117 }, 118 EXPLICIT_CAST_ARGUMENTS("explicitCastArguments") { 119 @Override 120 public Map<String, Object> getTestCaseData() { 121 Map<String, Object> data = new HashMap<>(); 122 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); 123 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 124 data.put("mtTarget", mtTarget); 125 // Arity after reducing because of long and double take 2 slots. 126 int realArity = mtTarget.parameterCount(); 127 MethodType mtExcplCastArgs = TestMethods.randomMethodTypeGenerator(realArity); 128 if (mtTarget.returnType() == void.class) { 129 mtExcplCastArgs = MethodType.methodType(void.class, 130 mtExcplCastArgs.parameterArray()); 131 } 132 if (mtExcplCastArgs.returnType() == void.class) { 133 mtExcplCastArgs = MethodType.methodType(mtTarget.returnType(), 134 mtExcplCastArgs.parameterArray()); 135 } 136 data.put("mtExcplCastArgs", mtExcplCastArgs); 137 return data; 138 } 139 140 @Override 141 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 142 MethodType mtTarget = (MethodType) data.get("mtTarget"); 143 MethodType mtExcplCastArgs = (MethodType) data.get("mtExcplCastArgs"); 144 MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 145 mtTarget.parameterList(), kind); 146 return MethodHandles.explicitCastArguments(target, mtExcplCastArgs); 147 } 148 }, 149 FILTER_ARGUMENTS("filterArguments") { 150 @Override 151 public Map<String, Object> getTestCaseData() { 152 Map<String, Object> data = new HashMap<>(); 153 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); 154 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 155 data.put("mtTarget", mtTarget); 156 // Arity after reducing because of long and double take 2 slots. 157 int realArity = mtTarget.parameterCount(); 158 int filterArgsPos = Helper.RNG.nextInt(realArity + 1); 159 data.put("filterArgsPos", filterArgsPos); 160 int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos); 161 data.put("filtersArgsArrayLength", filtersArgsArrayLength); 162 MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength); 163 data.put("mtFilter", mtFilter); 164 return data; 165 } 166 167 @Override 168 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 169 MethodType mtTarget = (MethodType) data.get("mtTarget"); 170 MethodType mtFilter = (MethodType) data.get("mtFilter"); 171 int filterArgsPos = (int) data.get("filterArgsPos"); 172 int filtersArgsArrayLength = (int) data.get("filtersArgsArrayLength"); 173 MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 174 mtTarget.parameterList(), kind); 175 MethodHandle[] filters = new MethodHandle[filtersArgsArrayLength]; 176 for (int i = 0; i < filtersArgsArrayLength; i++) { 177 filters[i] = TestMethods.filterGenerator(mtFilter.parameterType(i), 178 mtTarget.parameterType(filterArgsPos + i), kind); 179 } 180 return MethodHandles.filterArguments(target, filterArgsPos, filters); 181 } 182 }, 183 FILTER_RETURN_VALUE("filterReturnValue") { 184 @Override 185 public Map<String, Object> getTestCaseData() { 186 Map<String, Object> data = new HashMap<>(); 187 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 188 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 189 data.put("mtTarget", mtTarget); 190 // Arity after reducing because of long and double take 2 slots. 191 int realArity = mtTarget.parameterCount(); 192 int filterArgsPos = Helper.RNG.nextInt(realArity + 1); 193 int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos); 194 MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength); 195 data.put("mtFilter", mtFilter); 196 return data; 197 } 198 199 @Override 200 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 201 MethodType mtTarget = (MethodType) data.get("mtTarget"); 202 MethodType mtFilter = (MethodType) data.get("mtFilter"); 203 MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 204 mtTarget.parameterList(), kind); 205 MethodHandle filter = TestMethods.filterGenerator(mtTarget.returnType(), 206 mtFilter.returnType(), kind); 207 return MethodHandles.filterReturnValue(target, filter); 208 } 209 }, 210 INSERT_ARGUMENTS("insertArguments") { 211 @Override 212 public Map<String, Object> getTestCaseData() { 213 Map<String, Object> data = new HashMap<>(); 214 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 215 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 216 data.put("mtTarget", mtTarget); 217 // Arity after reducing because of long and double take 2 slots. 218 int realArity = mtTarget.parameterCount(); 219 int insertArgsPos = Helper.RNG.nextInt(realArity + 1); 220 data.put("insertArgsPos", insertArgsPos); 221 int insertArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - insertArgsPos); 222 MethodType mtInsertArgs = MethodType.methodType(void.class, mtTarget.parameterList() 223 .subList(insertArgsPos, insertArgsPos + insertArgsArrayLength)); 224 data.put("mtInsertArgs", mtInsertArgs); 225 return data; 226 } 227 228 @Override 229 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 230 MethodType mtTarget = (MethodType) data.get("mtTarget"); 231 MethodType mtInsertArgs = (MethodType) data.get("mtInsertArgs"); 232 int insertArgsPos = (int) data.get("insertArgsPos"); 233 MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 234 mtTarget.parameterList(), kind); 235 Object[] insertList = Helper.randomArgs(mtInsertArgs.parameterList()); 236 return MethodHandles.insertArguments(target, insertArgsPos, insertList); 237 } 238 }, 239 PERMUTE_ARGUMENTS("permuteArguments") { 240 @Override 241 public Map<String, Object> getTestCaseData() { 242 Map<String, Object> data = new HashMap<>(); 243 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); 244 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 245 // Arity after reducing because of long and double take 2 slots. 246 int realArity = mtTarget.parameterCount(); 247 int[] permuteArgsReorderArray = new int[realArity]; 248 int mtParmuteArgsNum = Helper.RNG.nextInt(Helper.MAX_ARITY); 249 mtParmuteArgsNum = mtParmuteArgsNum == 0 ? 1 : mtParmuteArgsNum; 250 MethodType mtPermuteArgs = TestMethods.randomMethodTypeGenerator(mtParmuteArgsNum); 251 mtTarget = mtTarget.changeReturnType(mtPermuteArgs.returnType()); 252 for (int i = 0; i < realArity; i++) { 253 int mtPermuteArgsParNum = Helper.RNG.nextInt(mtPermuteArgs.parameterCount()); 254 permuteArgsReorderArray[i] = mtPermuteArgsParNum; 255 mtTarget = mtTarget.changeParameterType( 256 i, mtPermuteArgs.parameterType(mtPermuteArgsParNum)); 257 } 258 data.put("mtTarget", mtTarget); 259 data.put("permuteArgsReorderArray", permuteArgsReorderArray); 260 data.put("mtPermuteArgs", mtPermuteArgs); 261 return data; 262 } 263 264 @Override 265 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 266 MethodType mtTarget = (MethodType) data.get("mtTarget"); 267 MethodType mtPermuteArgs = (MethodType) data.get("mtPermuteArgs"); 268 int[] permuteArgsReorderArray = (int[]) data.get("permuteArgsReorderArray"); 269 MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 270 mtTarget.parameterList(), kind); 271 return MethodHandles.permuteArguments(target, mtPermuteArgs, permuteArgsReorderArray); 272 } 273 }, 274 THROW_EXCEPTION("throwException") { 275 @Override 276 public Map<String, Object> getTestCaseData() { 277 Map<String, Object> data = new HashMap<>(); 278 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 279 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 280 data.put("mtTarget", mtTarget); 281 return data; 282 } 283 284 @Override 285 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 286 MethodType mtTarget = (MethodType) data.get("mtTarget"); 287 Class<?> rType = mtTarget.returnType(); 288 return MethodHandles.throwException(rType, Exception.class 289 ); 290 } 291 }, 292 GUARD_WITH_TEST("guardWithTest") { 293 @Override 294 public Map<String, Object> getTestCaseData() { 295 Map<String, Object> data = new HashMap<>(); 296 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 297 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 298 data.put("mtTarget", mtTarget); 299 // Arity after reducing because of long and double take 2 slots. 300 int realArity = mtTarget.parameterCount(); 301 int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); 302 data.put("modifierMHArgNum", modifierMHArgNum); 303 return data; 304 } 305 306 @Override 307 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 308 MethodType mtTarget = (MethodType) data.get("mtTarget"); 309 int modifierMHArgNum = (int) data.get("modifierMHArgNum"); 310 TestMethods.Kind targetKind; 311 TestMethods.Kind fallbackKind; 312 if (kind.equals(TestMethods.Kind.ONE)) { 313 targetKind = TestMethods.Kind.ONE; 314 fallbackKind = TestMethods.Kind.TWO; 315 } else { 316 targetKind = TestMethods.Kind.TWO; 317 fallbackKind = TestMethods.Kind.ONE; 318 } 319 MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 320 mtTarget.parameterList(), targetKind); 321 MethodHandle fallback = TestMethods.methodHandleGenerator(mtTarget.returnType(), 322 mtTarget.parameterList(), fallbackKind); 323 MethodHandle test = TestMethods.methodHandleGenerator(boolean.class, 324 mtTarget.parameterList().subList(0, modifierMHArgNum), kind); 325 return MethodHandles.guardWithTest(test, target, fallback); 326 } 327 }, 328 CATCH_EXCEPTION("catchException") { 329 @Override 330 public Map<String, Object> getTestCaseData() { 331 Map<String, Object> data = new HashMap<>(); 332 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 333 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 334 data.put("mtTarget", mtTarget); 335 // Arity after reducing because of long and double take 2 slots. 336 int realArity = mtTarget.parameterCount(); 337 int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); 338 data.put("modifierMHArgNum", modifierMHArgNum); 339 return data; 340 } 341 342 @Override 343 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 344 MethodType mtTarget = (MethodType) data.get("mtTarget"); 345 int modifierMHArgNum = (int) data.get("modifierMHArgNum"); 346 MethodHandle target; 347 if (kind.equals(TestMethods.Kind.ONE)) { 348 target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 349 mtTarget.parameterList(), TestMethods.Kind.ONE); 350 } else { 351 target = TestMethods.methodHandleGenerator(mtTarget.returnType(), 352 mtTarget.parameterList(), TestMethods.Kind.EXCEPT); 353 } 354 List<Class<?>> handlerParamList = new ArrayList<>(mtTarget.parameterCount() + 1); 355 handlerParamList.add(Exception.class); 356 handlerParamList.addAll(mtTarget.parameterList().subList(0, modifierMHArgNum)); 357 MethodHandle handler = TestMethods.methodHandleGenerator( 358 mtTarget.returnType(), handlerParamList, TestMethods.Kind.TWO); 359 return MethodHandles.catchException(target, Exception.class, handler); 360 } 361 }, 362 INVOKER("invoker") { 363 @Override 364 public Map<String, Object> getTestCaseData() { 365 Map<String, Object> data = new HashMap<>(); 366 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 367 desiredArity = desiredArity <= 252 ? desiredArity : 252; 368 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 369 data.put("mtTarget", mtTarget); 370 return data; 371 } 372 373 @Override 374 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 375 MethodType mtTarget = (MethodType) data.get("mtTarget"); 376 return MethodHandles.invoker(mtTarget); 377 } 378 }, 379 EXACT_INVOKER("exactInvoker") { 380 @Override 381 public Map<String, Object> getTestCaseData() { 382 Map<String, Object> data = new HashMap<>(); 383 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 384 desiredArity = desiredArity <= 252 ? desiredArity : 252; 385 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 386 data.put("mtTarget", mtTarget); 387 return data; 388 } 389 390 @Override 391 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 392 MethodType mtTarget = (MethodType) data.get("mtTarget"); 393 return MethodHandles.exactInvoker(mtTarget); 394 } 395 }, 396 SPREAD_INVOKER("spreadInvoker") { 397 @Override 398 public Map<String, Object> getTestCaseData() { 399 Map<String, Object> data = new HashMap<>(); 400 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 401 desiredArity = desiredArity <= 252 ? desiredArity : 252; 402 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 403 data.put("mtTarget", mtTarget); 404 // Arity after reducing because of long and double take 2 slots. 405 int realArity = mtTarget.parameterCount(); 406 int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); 407 data.put("modifierMHArgNum", modifierMHArgNum); 408 return data; 409 } 410 411 @Override 412 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 413 MethodType mtTarget = (MethodType) data.get("mtTarget"); 414 int modifierMHArgNum = (int) data.get("modifierMHArgNum"); 415 return MethodHandles.spreadInvoker(mtTarget, modifierMHArgNum); 416 } 417 }, 418 ARRAY_ELEMENT_GETTER("arrayElementGetter") { 419 @Override 420 public Map<String, Object> getTestCaseData() { 421 Map<String, Object> data = new HashMap<>(); 422 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 423 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 424 data.put("mtTarget", mtTarget); 425 return data; 426 } 427 428 @Override 429 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 430 MethodType mtTarget = (MethodType) data.get("mtTarget"); 431 Class<?> rType = mtTarget.returnType(); 432 if (rType == void.class) { 433 rType = Object.class; 434 } 435 return MethodHandles.arrayElementGetter(Array.newInstance(rType, 2).getClass()); 436 } 437 }, 438 ARRAY_ELEMENT_SETTER("arrayElementSetter") { 439 @Override 440 public Map<String, Object> getTestCaseData() { 441 Map<String, Object> data = new HashMap<>(); 442 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 443 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 444 data.put("mtTarget", mtTarget); 445 return data; 446 } 447 448 @Override 449 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 450 MethodType mtTarget = (MethodType) data.get("mtTarget"); 451 Class<?> rType = mtTarget.returnType(); 452 if (rType == void.class) { 453 rType = Object.class; 454 } 455 return MethodHandles.arrayElementSetter(Array.newInstance(rType, 2).getClass()); 456 } 457 }, 458 CONSTANT("constant") { 459 @Override 460 public Map<String, Object> getTestCaseData() { 461 Map<String, Object> data = new HashMap<>(); 462 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 463 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 464 data.put("mtTarget", mtTarget); 465 return data; 466 } 467 468 @Override 469 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 470 MethodType mtTarget = (MethodType) data.get("mtTarget"); 471 Class<?> rType = mtTarget.returnType(); 472 if (rType == void.class) { 473 rType = Object.class; 474 } 475 if (rType.equals(boolean.class)) { 476 // There should be the same return values because for default values there are special "zero" forms 477 return MethodHandles.constant(rType, true); 478 } else { 479 return MethodHandles.constant(rType, kind.getValue(rType)); 480 } 481 } 482 }, 483 IDENTITY("identity") { 484 @Override 485 public Map<String, Object> getTestCaseData() { 486 Map<String, Object> data = new HashMap<>(); 487 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 488 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 489 data.put("mtTarget", mtTarget); 490 return data; 491 } 492 493 @Override 494 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 495 MethodType mtTarget = (MethodType) data.get("mtTarget"); 496 Class<?> rType = mtTarget.returnType(); 497 if (rType == void.class) { 498 rType = Object.class; 499 } 500 return MethodHandles.identity(rType); 501 } 502 }; 503 504 /** 505 * Test method's name. 506 */ 507 public final String name; 508 509 private TestMethods(String name) { 510 this.name = name; 511 } 512 513 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 514 throw new UnsupportedOperationException("TESTBUG: getMH method is not implemented for test method " + this); 515 } 516 517 /** 518 * Creates an adapter method handle depending on a test method from 519 * MethodHandles class. Adapter is what is returned by the test method. This 520 * method is able to create two kinds of adapters, their type will be the 521 * same, but return values are different. 522 * 523 * @param data a Map containing data to create a method handle, can be 524 * obtained by {@link #getTestCaseData} method 525 * @param kind defines whether adapter ONE or adapter TWO will be 526 * initialized. Should be equal to TestMethods.Kind.ONE or 527 * TestMethods.Kind.TWO 528 * @return Method handle adapter that behaves according to 529 * TestMethods.Kind.ONE or TestMethods.Kind.TWO 530 * @throws java.lang.NoSuchMethodException 531 * @throws java.lang.IllegalAccessException 532 */ 533 public MethodHandle getTestCaseMH(Map<String, Object> data, TestMethods.Kind kind) 534 throws NoSuchMethodException, IllegalAccessException { 535 if (data == null) { 536 throw new Error(String.format("TESTBUG: Data for test method %s is not prepared", 537 this.name)); 538 } 539 if (!kind.equals(TestMethods.Kind.ONE) && !kind.equals(TestMethods.Kind.TWO)) { 540 throw new IllegalArgumentException("TESTBUG: Wrong \"kind\" (" + kind 541 + ") arg to getTestCaseMH function." 542 + " Should be Kind.ONE or Kind.TWO"); 543 } 544 return getMH(data, kind); 545 } 546 547 /** 548 * Returns a data Map needed for {@link #getTestCaseMH} method. 549 * 550 * @return data Map needed for {@link #getTestCaseMH} method 551 */ 552 public Map<String, Object> getTestCaseData() { 553 throw new UnsupportedOperationException( 554 "TESTBUG: getTestCaseData method is not implemented for test method " + this); 555 } 556 557 /** 558 * Enumeration used in methodHandleGenerator to define whether a MH returned 559 * by this method returns "2" in different type representations, "4", or 560 * throw an Exception. 561 */ 562 public static enum Kind { 563 564 ONE(2), 565 TWO(4), 566 EXCEPT(0); 567 568 private final int value; 569 570 private Object getValue(Class<?> cl) { 571 return Helper.castToWrapper(value, cl); 572 } 573 574 private MethodHandle getBasicMH(Class<?> rType) throws NoSuchMethodException, IllegalAccessException { 575 MethodHandle result = null; 576 switch (this) { 577 case ONE: 578 case TWO: 579 if (rType.equals(void.class)) { 580 result = MethodHandles.lookup().findVirtual(Kind.class, "returnVoid", MethodType.methodType(void.class)); 581 result = MethodHandles.insertArguments(result, 0, this); 582 } else { 583 result = MethodHandles.constant(rType, getValue(rType)); 584 } 585 break; 586 case EXCEPT: 587 result = MethodHandles.throwException(rType, Exception.class); 588 result = MethodHandles.insertArguments(result, 0, new Exception()); 589 break; 590 } 591 return result; 592 } 593 594 private void returnVoid() { 595 } 596 597 private Kind(int value) { 598 this.value = value; 599 } 600 } 601 602 /** 603 * Routine used to obtain a randomly generated method type. 604 * 605 * @param arity Arity of returned method type. 606 * @return MethodType generated randomly. 607 */ 608 private static MethodType randomMethodTypeGenerator(int arity) { 609 final Class<?>[] CLASSES = { 610 Object.class, 611 int.class, 612 boolean.class, 613 byte.class, 614 short.class, 615 char.class, 616 long.class, 617 float.class, 618 double.class 619 }; 620 if (arity > Helper.MAX_ARITY) { 621 throw new IllegalArgumentException( 622 String.format("Arity should not exceed %d!", Helper.MAX_ARITY)); 623 } 624 List<Class<?>> list = Helper.randomClasses(CLASSES, arity); 625 list = Helper.getParams(list, false, arity); 626 int i = Helper.RNG.nextInt(CLASSES.length + 1); 627 Class<?> rtype = i == CLASSES.length ? void.class : CLASSES[i]; 628 return MethodType.methodType(rtype, list); 629 } 630 631 /** 632 * Routine used to obtain a method handles of a given type an kind (return 633 * value). 634 * 635 * @param returnType Type of MH return value. 636 * @param argTypes Types of MH args. 637 * @param kind Defines whether the obtained MH returns "1" or "2". 638 * @return Method handle of the given type. 639 * @throws NoSuchMethodException 640 * @throws IllegalAccessException 641 */ 642 private static MethodHandle methodHandleGenerator(Class<?> returnType, 643 List<Class<?>> argTypes, TestMethods.Kind kind) 644 throws NoSuchMethodException, IllegalAccessException { 645 MethodHandle result; 646 result = kind.getBasicMH(returnType); 647 return Helper.addTrailingArgs(result, argTypes.size(), argTypes); 648 } 649 650 /** 651 * Routine that generates filter method handles to test 652 * MethodHandles.filterArguments method. 653 * 654 * @param inputType Filter's argument type. 655 * @param returnType Filter's return type. 656 * @param kind Filter's return value definer. 657 * @return A filter method handle, that takes one argument. 658 * @throws NoSuchMethodException 659 * @throws IllegalAccessException 660 */ 661 private static MethodHandle filterGenerator(Class<?> inputType, Class<?> returnType, 662 TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 663 MethodHandle tmpMH = kind.getBasicMH(returnType); 664 if (inputType.equals(void.class)) { 665 return tmpMH; 666 } 667 ArrayList<Class<?>> inputTypeList = new ArrayList<>(1); 668 inputTypeList.add(inputType); 669 return Helper.addTrailingArgs(tmpMH, 1, inputTypeList); 670 } 671 672 private static int argSlotsCount(MethodType mt) { 673 int result = 0; 674 for (Class cl : mt.parameterArray()) { 675 if (cl.equals(long.class) || cl.equals(double.class)) { 676 result += 2; 677 } else { 678 result++; 679 } 680 } 681 return result; 682 } 683 684 private static List<Class<?>> reduceArgListToSlotsCount(List<Class<?>> list, 685 int desiredSlotCount) { 686 List<Class<?>> result = new ArrayList<>(desiredSlotCount); 687 int count = 0; 688 for (Class<?> cl : list) { 689 if (count >= desiredSlotCount) { 690 break; 691 } 692 if (cl.equals(long.class) || cl.equals(double.class)) { 693 count += 2; 694 } else { 695 count++; 696 } 697 result.add(cl); 698 } 699 return result; 700 } 701 }