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(super.maxArity); 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(super.maxArity); 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(super.maxArity - 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 > super.maxArity - 1) { 110 fakeParList = TestMethods.reduceArgListToSlotsCount(mtDropArgs.parameterList(), 111 super.maxArity - mtTgtSlotsCount - 1); 112 } else { 113 fakeParList = mtDropArgs.parameterList(); 114 } 115 return MethodHandles.dropArguments(target, dropArgsPos, fakeParList); 116 } 117 }, 118 EXPLICIT_CAST_ARGUMENTS("explicitCastArguments", Helper.MAX_ARITY / 2) { 119 @Override 120 public Map<String, Object> getTestCaseData() { 121 Map<String, Object> data = new HashMap<>(); 122 int desiredArity = Helper.RNG.nextInt(super.maxArity); 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", Helper.MAX_ARITY / 2) { 150 @Override 151 public Map<String, Object> getTestCaseData() { 152 Map<String, Object> data = new HashMap<>(); 153 int desiredArity = Helper.RNG.nextInt(super.maxArity); 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(super.maxArity); 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(super.maxArity); 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", Helper.MAX_ARITY / 2) { 240 @Override 241 public Map<String, Object> getTestCaseData() { 242 Map<String, Object> data = new HashMap<>(); 243 int desiredArity = Helper.RNG.nextInt(super.maxArity); 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 mtPermuteArgsNum = Helper.RNG.nextInt(Helper.MAX_ARITY); 249 mtPermuteArgsNum = mtPermuteArgsNum == 0 ? 1 : mtPermuteArgsNum; 250 MethodType mtPermuteArgs = TestMethods.randomMethodTypeGenerator(mtPermuteArgsNum); 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(super.maxArity); 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(super.maxArity); 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(super.maxArity); 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", Helper.MAX_ARITY - 1) { 363 @Override 364 public Map<String, Object> getTestCaseData() { 365 Map<String, Object> data = new HashMap<>(); 366 int desiredArity = Helper.RNG.nextInt(super.maxArity); 367 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 368 data.put("mtTarget", mtTarget); 369 return data; 370 } 371 372 @Override 373 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 374 MethodType mtTarget = (MethodType) data.get("mtTarget"); 375 return MethodHandles.invoker(mtTarget); 376 } 377 }, 378 EXACT_INVOKER("exactInvoker", Helper.MAX_ARITY - 1) { 379 @Override 380 public Map<String, Object> getTestCaseData() { 381 Map<String, Object> data = new HashMap<>(); 382 int desiredArity = Helper.RNG.nextInt(super.maxArity); 383 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 384 data.put("mtTarget", mtTarget); 385 return data; 386 } 387 388 @Override 389 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 390 MethodType mtTarget = (MethodType) data.get("mtTarget"); 391 return MethodHandles.exactInvoker(mtTarget); 392 } 393 }, 394 SPREAD_INVOKER("spreadInvoker", Helper.MAX_ARITY - 1) { 395 @Override 396 public Map<String, Object> getTestCaseData() { 397 Map<String, Object> data = new HashMap<>(); 398 int desiredArity = Helper.RNG.nextInt(super.maxArity); 399 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 400 data.put("mtTarget", mtTarget); 401 // Arity after reducing because of long and double take 2 slots. 402 int realArity = mtTarget.parameterCount(); 403 int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); 404 data.put("modifierMHArgNum", modifierMHArgNum); 405 return data; 406 } 407 408 @Override 409 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 410 MethodType mtTarget = (MethodType) data.get("mtTarget"); 411 int modifierMHArgNum = (int) data.get("modifierMHArgNum"); 412 return MethodHandles.spreadInvoker(mtTarget, modifierMHArgNum); 413 } 414 }, 415 ARRAY_ELEMENT_GETTER("arrayElementGetter") { 416 @Override 417 public Map<String, Object> getTestCaseData() { 418 Map<String, Object> data = new HashMap<>(); 419 int desiredArity = Helper.RNG.nextInt(super.maxArity); 420 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 421 data.put("mtTarget", mtTarget); 422 return data; 423 } 424 425 @Override 426 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 427 MethodType mtTarget = (MethodType) data.get("mtTarget"); 428 Class<?> rType = mtTarget.returnType(); 429 if (rType == void.class) { 430 rType = Object.class; 431 } 432 return MethodHandles.arrayElementGetter(Array.newInstance(rType, 2).getClass()); 433 } 434 }, 435 ARRAY_ELEMENT_SETTER("arrayElementSetter") { 436 @Override 437 public Map<String, Object> getTestCaseData() { 438 Map<String, Object> data = new HashMap<>(); 439 int desiredArity = Helper.RNG.nextInt(super.maxArity); 440 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 441 data.put("mtTarget", mtTarget); 442 return data; 443 } 444 445 @Override 446 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 447 MethodType mtTarget = (MethodType) data.get("mtTarget"); 448 Class<?> rType = mtTarget.returnType(); 449 if (rType == void.class) { 450 rType = Object.class; 451 } 452 return MethodHandles.arrayElementSetter(Array.newInstance(rType, 2).getClass()); 453 } 454 }, 455 CONSTANT("constant") { 456 @Override 457 public Map<String, Object> getTestCaseData() { 458 Map<String, Object> data = new HashMap<>(); 459 int desiredArity = Helper.RNG.nextInt(super.maxArity); 460 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 461 data.put("mtTarget", mtTarget); 462 return data; 463 } 464 465 @Override 466 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 467 MethodType mtTarget = (MethodType) data.get("mtTarget"); 468 Class<?> rType = mtTarget.returnType(); 469 if (rType == void.class) { 470 rType = Object.class; 471 } 472 if (rType.equals(boolean.class)) { 473 // There should be the same return values because for default values there are special "zero" forms 474 return MethodHandles.constant(rType, true); 475 } else { 476 return MethodHandles.constant(rType, kind.getValue(rType)); 477 } 478 } 479 }, 480 IDENTITY("identity") { 481 @Override 482 public Map<String, Object> getTestCaseData() { 483 Map<String, Object> data = new HashMap<>(); 484 int desiredArity = Helper.RNG.nextInt(super.maxArity); 485 MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); 486 data.put("mtTarget", mtTarget); 487 return data; 488 } 489 490 @Override 491 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { 492 MethodType mtTarget = (MethodType) data.get("mtTarget"); 493 Class<?> rType = mtTarget.returnType(); 494 if (rType == void.class) { 495 rType = Object.class; 496 } 497 return MethodHandles.identity(rType); 498 } 499 }; 500 501 /** 502 * Test method's name. 503 */ 504 public final String name; 505 506 private final int maxArity; 507 508 private TestMethods(String name, int maxArity) { 509 this.name = name; 510 this.maxArity = maxArity; 511 } 512 513 private TestMethods(String name) { 514 this.name = name; 515 this.maxArity = Helper.MAX_ARITY; 516 } 517 518 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 519 throw new UnsupportedOperationException("TESTBUG: getMH method is not implemented for test method " + this); 520 } 521 522 /** 523 * Creates an adapter method handle depending on a test method from 524 * MethodHandles class. Adapter is what is returned by the test method. This 525 * method is able to create two kinds of adapters, their type will be the 526 * same, but return values are different. 527 * 528 * @param data a Map containing data to create a method handle, can be 529 * obtained by {@link #getTestCaseData} method 530 * @param kind defines whether adapter ONE or adapter TWO will be 531 * initialized. Should be equal to TestMethods.Kind.ONE or 532 * TestMethods.Kind.TWO 533 * @return Method handle adapter that behaves according to 534 * TestMethods.Kind.ONE or TestMethods.Kind.TWO 535 * @throws java.lang.NoSuchMethodException 536 * @throws java.lang.IllegalAccessException 537 */ 538 public MethodHandle getTestCaseMH(Map<String, Object> data, TestMethods.Kind kind) 539 throws NoSuchMethodException, IllegalAccessException { 540 if (data == null) { 541 throw new Error(String.format("TESTBUG: Data for test method %s is not prepared", 542 this.name)); 543 } 544 if (!kind.equals(TestMethods.Kind.ONE) && !kind.equals(TestMethods.Kind.TWO)) { 545 throw new IllegalArgumentException("TESTBUG: Wrong \"kind\" (" + kind 546 + ") arg to getTestCaseMH function." 547 + " Should be Kind.ONE or Kind.TWO"); 548 } 549 return getMH(data, kind); 550 } 551 552 /** 553 * Returns a data Map needed for {@link #getTestCaseMH} method. 554 * 555 * @return data Map needed for {@link #getTestCaseMH} method 556 */ 557 public Map<String, Object> getTestCaseData() { 558 throw new UnsupportedOperationException( 559 "TESTBUG: getTestCaseData method is not implemented for test method " + this); 560 } 561 562 /** 563 * Enumeration used in methodHandleGenerator to define whether a MH returned 564 * by this method returns "2" in different type representations, "4", or 565 * throw an Exception. 566 */ 567 public static enum Kind { 568 569 ONE(2), 570 TWO(4), 571 EXCEPT(0); 572 573 private final int value; 574 575 private Object getValue(Class<?> cl) { 576 return Helper.castToWrapper(value, cl); 577 } 578 579 private MethodHandle getBasicMH(Class<?> rType) throws NoSuchMethodException, IllegalAccessException { 580 MethodHandle result = null; 581 switch (this) { 582 case ONE: 583 case TWO: 584 if (rType.equals(void.class)) { 585 result = MethodHandles.lookup().findVirtual(Kind.class, "returnVoid", MethodType.methodType(void.class)); 586 result = MethodHandles.insertArguments(result, 0, this); 587 } else { 588 result = MethodHandles.constant(rType, getValue(rType)); 589 } 590 break; 591 case EXCEPT: 592 result = MethodHandles.throwException(rType, Exception.class); 593 result = MethodHandles.insertArguments(result, 0, new Exception()); 594 break; 595 } 596 return result; 597 } 598 599 private void returnVoid() { 600 } 601 602 private Kind(int value) { 603 this.value = value; 604 } 605 } 606 607 /** 608 * Routine used to obtain a randomly generated method type. 609 * 610 * @param arity Arity of returned method type. 611 * @return MethodType generated randomly. 612 */ 613 private static MethodType randomMethodTypeGenerator(int arity) { 614 final Class<?>[] CLASSES = { 615 Object.class, 616 int.class, 617 boolean.class, 618 byte.class, 619 short.class, 620 char.class, 621 long.class, 622 float.class, 623 double.class 624 }; 625 if (arity > Helper.MAX_ARITY) { 626 throw new IllegalArgumentException( 627 String.format("Arity should not exceed %d!", Helper.MAX_ARITY)); 628 } 629 List<Class<?>> list = Helper.randomClasses(CLASSES, arity); 630 list = Helper.getParams(list, false, arity); 631 int i = Helper.RNG.nextInt(CLASSES.length + 1); 632 Class<?> rtype = i == CLASSES.length ? void.class : CLASSES[i]; 633 return MethodType.methodType(rtype, list); 634 } 635 636 /** 637 * Routine used to obtain a method handles of a given type an kind (return 638 * value). 639 * 640 * @param returnType Type of MH return value. 641 * @param argTypes Types of MH args. 642 * @param kind Defines whether the obtained MH returns "1" or "2". 643 * @return Method handle of the given type. 644 * @throws NoSuchMethodException 645 * @throws IllegalAccessException 646 */ 647 private static MethodHandle methodHandleGenerator(Class<?> returnType, 648 List<Class<?>> argTypes, TestMethods.Kind kind) 649 throws NoSuchMethodException, IllegalAccessException { 650 MethodHandle result; 651 result = kind.getBasicMH(returnType); 652 return Helper.addTrailingArgs(result, argTypes.size(), argTypes); 653 } 654 655 /** 656 * Routine that generates filter method handles to test 657 * MethodHandles.filterArguments method. 658 * 659 * @param inputType Filter's argument type. 660 * @param returnType Filter's return type. 661 * @param kind Filter's return value definer. 662 * @return A filter method handle, that takes one argument. 663 * @throws NoSuchMethodException 664 * @throws IllegalAccessException 665 */ 666 private static MethodHandle filterGenerator(Class<?> inputType, Class<?> returnType, 667 TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 668 MethodHandle tmpMH = kind.getBasicMH(returnType); 669 if (inputType.equals(void.class)) { 670 return tmpMH; 671 } 672 ArrayList<Class<?>> inputTypeList = new ArrayList<>(1); 673 inputTypeList.add(inputType); 674 return Helper.addTrailingArgs(tmpMH, 1, inputTypeList); 675 } 676 677 private static int argSlotsCount(MethodType mt) { 678 int result = 0; 679 for (Class cl : mt.parameterArray()) { 680 if (cl.equals(long.class) || cl.equals(double.class)) { 681 result += 2; 682 } else { 683 result++; 684 } 685 } 686 return result; 687 } 688 689 private static List<Class<?>> reduceArgListToSlotsCount(List<Class<?>> list, 690 int desiredSlotCount) { 691 List<Class<?>> result = new ArrayList<>(desiredSlotCount); 692 int count = 0; 693 for (Class<?> cl : list) { 694 if (count >= desiredSlotCount) { 695 break; 696 } 697 if (cl.equals(long.class) || cl.equals(double.class)) { 698 count += 2; 699 } else { 700 count++; 701 } 702 result.add(cl); 703 } 704 return result; 705 } 706 }