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 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") { 379 @Override 380 public Map<String, Object> getTestCaseData() { 381 Map<String, Object> data = new HashMap<>(); 382 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 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") { 395 @Override 396 public Map<String, Object> getTestCaseData() { 397 Map<String, Object> data = new HashMap<>(); 398 int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); 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(Helper.MAX_ARITY); 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(Helper.MAX_ARITY); 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(Helper.MAX_ARITY); 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(Helper.MAX_ARITY); 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 TestMethods(String name) { 507 this.name = name; 508 } 509 510 protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 511 throw new UnsupportedOperationException("TESTBUG: getMH method is not implemented for test method " + this); 512 } 513 514 /** 515 * Creates an adapter method handle depending on a test method from 516 * MethodHandles class. Adapter is what is returned by the test method. This 517 * method is able to create two kinds of adapters, their type will be the 518 * same, but return values are different. 519 * 520 * @param data a Map containing data to create a method handle, can be 521 * obtained by {@link #getTestCaseData} method 522 * @param kind defines whether adapter ONE or adapter TWO will be 523 * initialized. Should be equal to TestMethods.Kind.ONE or 524 * TestMethods.Kind.TWO 525 * @return Method handle adapter that behaves according to 526 * TestMethods.Kind.ONE or TestMethods.Kind.TWO 527 * @throws java.lang.NoSuchMethodException 528 * @throws java.lang.IllegalAccessException 529 */ 530 public MethodHandle getTestCaseMH(Map<String, Object> data, TestMethods.Kind kind) 531 throws NoSuchMethodException, IllegalAccessException { 532 if (data == null) { 533 throw new Error(String.format("TESTBUG: Data for test method %s is not prepared", 534 this.name)); 535 } 536 if (!kind.equals(TestMethods.Kind.ONE) && !kind.equals(TestMethods.Kind.TWO)) { 537 throw new IllegalArgumentException("TESTBUG: Wrong \"kind\" (" + kind 538 + ") arg to getTestCaseMH function." 539 + " Should be Kind.ONE or Kind.TWO"); 540 } 541 return getMH(data, kind); 542 } 543 544 /** 545 * Returns a data Map needed for {@link #getTestCaseMH} method. 546 * 547 * @return data Map needed for {@link #getTestCaseMH} method 548 */ 549 public Map<String, Object> getTestCaseData() { 550 throw new UnsupportedOperationException( 551 "TESTBUG: getTestCaseData method is not implemented for test method " + this); 552 } 553 554 /** 555 * Enumeration used in methodHandleGenerator to define whether a MH returned 556 * by this method returns "2" in different type representations, "4", or 557 * throw an Exception. 558 */ 559 public static enum Kind { 560 561 ONE(2), 562 TWO(4), 563 EXCEPT(0); 564 565 private final int value; 566 567 private Object getValue(Class<?> cl) { 568 return Helper.castToWrapper(value, cl); 569 } 570 571 private MethodHandle getBasicMH(Class<?> rType) throws NoSuchMethodException, IllegalAccessException { 572 MethodHandle result = null; 573 switch (this) { 574 case ONE: 575 case TWO: 576 if (rType.equals(void.class)) { 577 result = MethodHandles.lookup().findVirtual(Kind.class, "returnVoid", MethodType.methodType(void.class)); 578 result = MethodHandles.insertArguments(result, 0, this); 579 } else { 580 result = MethodHandles.constant(rType, getValue(rType)); 581 } 582 break; 583 case EXCEPT: 584 result = MethodHandles.throwException(rType, Exception.class); 585 result = MethodHandles.insertArguments(result, 0, new Exception()); 586 break; 587 } 588 return result; 589 } 590 591 private void returnVoid() { 592 } 593 594 private Kind(int value) { 595 this.value = value; 596 } 597 } 598 599 /** 600 * Routine used to obtain a randomly generated method type. 601 * 602 * @param arity Arity of returned method type. 603 * @return MethodType generated randomly. 604 */ 605 private static MethodType randomMethodTypeGenerator(int arity) { 606 final Class<?>[] CLASSES = { 607 Object.class, 608 int.class, 609 boolean.class, 610 byte.class, 611 short.class, 612 char.class, 613 long.class, 614 float.class, 615 double.class 616 }; 617 if (arity > Helper.MAX_ARITY) { 618 throw new IllegalArgumentException( 619 String.format("Arity should not exceed %d!", Helper.MAX_ARITY)); 620 } 621 List<Class<?>> list = Helper.randomClasses(CLASSES, arity); 622 list = Helper.getParams(list, false, arity); 623 int i = Helper.RNG.nextInt(CLASSES.length + 1); 624 Class<?> rtype = i == CLASSES.length ? void.class : CLASSES[i]; 625 return MethodType.methodType(rtype, list); 626 } 627 628 /** 629 * Routine used to obtain a method handles of a given type an kind (return 630 * value). 631 * 632 * @param returnType Type of MH return value. 633 * @param argTypes Types of MH args. 634 * @param kind Defines whether the obtained MH returns "1" or "2". 635 * @return Method handle of the given type. 636 * @throws NoSuchMethodException 637 * @throws IllegalAccessException 638 */ 639 private static MethodHandle methodHandleGenerator(Class<?> returnType, 640 List<Class<?>> argTypes, TestMethods.Kind kind) 641 throws NoSuchMethodException, IllegalAccessException { 642 MethodHandle result; 643 result = kind.getBasicMH(returnType); 644 return Helper.addTrailingArgs(result, argTypes.size(), argTypes); 645 } 646 647 /** 648 * Routine that generates filter method handles to test 649 * MethodHandles.filterArguments method. 650 * 651 * @param inputType Filter's argument type. 652 * @param returnType Filter's return type. 653 * @param kind Filter's return value definer. 654 * @return A filter method handle, that takes one argument. 655 * @throws NoSuchMethodException 656 * @throws IllegalAccessException 657 */ 658 private static MethodHandle filterGenerator(Class<?> inputType, Class<?> returnType, 659 TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { 660 MethodHandle tmpMH = kind.getBasicMH(returnType); 661 if (inputType.equals(void.class)) { 662 return tmpMH; 663 } 664 ArrayList<Class<?>> inputTypeList = new ArrayList<>(1); 665 inputTypeList.add(inputType); 666 return Helper.addTrailingArgs(tmpMH, 1, inputTypeList); 667 } 668 669 private static int argSlotsCount(MethodType mt) { 670 int result = 0; 671 for (Class cl : mt.parameterArray()) { 672 if (cl.equals(long.class) || cl.equals(double.class)) { 673 result += 2; 674 } else { 675 result++; 676 } 677 } 678 return result; 679 } 680 681 private static List<Class<?>> reduceArgListToSlotsCount(List<Class<?>> list, 682 int desiredSlotCount) { 683 List<Class<?>> result = new ArrayList<>(desiredSlotCount); 684 int count = 0; 685 for (Class<?> cl : list) { 686 if (count >= desiredSlotCount) { 687 break; 688 } 689 if (cl.equals(long.class) || cl.equals(double.class)) { 690 count += 2; 691 } else { 692 count++; 693 } 694 result.add(cl); 695 } 696 return result; 697 } 698 }