1 /* 2 * Copyright (c) 2008, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.invoke; 27 28 import jdk.internal.vm.annotation.Stable; 29 import sun.invoke.util.ValueConversions; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 import static java.lang.invoke.LambdaForm.BasicType; 35 import static java.lang.invoke.LambdaForm.BasicType.*; 36 import static java.lang.invoke.LambdaForm.BasicType.V_TYPE_NUM; 37 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 38 import static java.lang.invoke.MethodHandleNatives.Constants.*; 39 import static java.lang.invoke.MethodHandleStatics.newInternalError; 40 import static java.lang.invoke.MethodHandleStatics.uncaughtException; 41 42 /** 43 * The flavor of method handle which emulates an invoke instruction 44 * on a predetermined argument. The JVM dispatches to the correct method 45 * when the handle is created, not when it is invoked. 46 * 47 * All bound arguments are encapsulated in dedicated species. 48 */ 49 /*non-public*/ 50 abstract class BoundMethodHandle extends MethodHandle { 51 52 /*non-public*/ 53 BoundMethodHandle(MethodType type, LambdaForm form) { 54 super(type, form); 55 assert(speciesData() == speciesDataFor(form)); 56 } 57 58 // 59 // BMH API and internals 60 // 61 62 static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) { 63 // for some type signatures, there exist pre-defined concrete BMH classes 64 try { 65 return switch (xtype) { 66 case L_TYPE -> bindSingle(type, form, x); // Use known fast path. 67 case I_TYPE -> (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(I_TYPE_NUM).factory().invokeBasic(type, form, ValueConversions.widenSubword(x)); 68 case J_TYPE -> (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(J_TYPE_NUM).factory().invokeBasic(type, form, (long) x); 69 case F_TYPE -> (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(F_TYPE_NUM).factory().invokeBasic(type, form, (float) x); 70 case D_TYPE -> (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(D_TYPE_NUM).factory().invokeBasic(type, form, (double) x); 71 default -> throw newInternalError("unexpected xtype: " + xtype); 72 }; 73 } catch (Throwable t) { 74 throw uncaughtException(t); 75 } 76 } 77 78 /*non-public*/ 79 LambdaFormEditor editor() { 80 return form.editor(); 81 } 82 83 static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) { 84 return Species_L.make(type, form, x); 85 } 86 87 @Override // there is a default binder in the super class, for 'L' types only 88 /*non-public*/ 89 BoundMethodHandle bindArgumentL(int pos, Object value) { 90 return editor().bindArgumentL(this, pos, value); 91 } 92 93 /*non-public*/ 94 BoundMethodHandle bindArgumentI(int pos, int value) { 95 return editor().bindArgumentI(this, pos, value); 96 } 97 /*non-public*/ 98 BoundMethodHandle bindArgumentJ(int pos, long value) { 99 return editor().bindArgumentJ(this, pos, value); 100 } 101 /*non-public*/ 102 BoundMethodHandle bindArgumentF(int pos, float value) { 103 return editor().bindArgumentF(this, pos, value); 104 } 105 /*non-public*/ 106 BoundMethodHandle bindArgumentD(int pos, double value) { 107 return editor().bindArgumentD(this, pos, value); 108 } 109 @Override 110 BoundMethodHandle rebind() { 111 if (!tooComplex()) { 112 return this; 113 } 114 return makeReinvoker(this); 115 } 116 117 private boolean tooComplex() { 118 return (fieldCount() > FIELD_COUNT_THRESHOLD || 119 form.expressionCount() > FORM_EXPRESSION_THRESHOLD); 120 } 121 private static final int FIELD_COUNT_THRESHOLD = 12; // largest convenient BMH field count 122 private static final int FORM_EXPRESSION_THRESHOLD = 24; // largest convenient BMH expression count 123 124 /** 125 * A reinvoker MH has this form: 126 * {@code lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }} 127 */ 128 static BoundMethodHandle makeReinvoker(MethodHandle target) { 129 LambdaForm form = DelegatingMethodHandle.makeReinvokerForm( 130 target, MethodTypeForm.LF_REBIND, 131 Species_L.BMH_SPECIES, Species_L.BMH_SPECIES.getterFunction(0)); 132 return Species_L.make(target.type(), form, target); 133 } 134 135 /** 136 * Return the {@link BoundMethodHandle.SpeciesData} instance representing this BMH species. All subclasses must provide a 137 * static field containing this value, and they must accordingly implement this method. 138 */ 139 /*non-public*/ 140 abstract BoundMethodHandle.SpeciesData speciesData(); 141 142 /*non-public*/ 143 static BoundMethodHandle.SpeciesData speciesDataFor(LambdaForm form) { 144 Object c = form.names[0].constraint; 145 if (c instanceof SpeciesData) { 146 return (SpeciesData) c; 147 } 148 // if there is no BMH constraint, then use the null constraint 149 return SPECIALIZER.topSpecies(); 150 } 151 152 /** 153 * Return the number of fields in this BMH. Equivalent to speciesData().fieldCount(). 154 */ 155 /*non-public*/ 156 final int fieldCount() { return speciesData().fieldCount(); } 157 158 @Override 159 Object internalProperties() { 160 return "\n& BMH="+internalValues(); 161 } 162 163 @Override 164 final String internalValues() { 165 int count = fieldCount(); 166 if (count == 1) { 167 return "[" + arg(0) + "]"; 168 } 169 StringBuilder sb = new StringBuilder("["); 170 for (int i = 0; i < count; ++i) { 171 sb.append("\n ").append(i).append(": ( ").append(arg(i)).append(" )"); 172 } 173 return sb.append("\n]").toString(); 174 } 175 176 /*non-public*/ 177 final Object arg(int i) { 178 try { 179 Class<?> fieldType = speciesData().fieldTypes().get(i); 180 switch (BasicType.basicType(fieldType)) { 181 case L_TYPE: return speciesData().getter(i).invokeBasic(this); 182 case I_TYPE: return (int) speciesData().getter(i).invokeBasic(this); 183 case J_TYPE: return (long) speciesData().getter(i).invokeBasic(this); 184 case F_TYPE: return (float) speciesData().getter(i).invokeBasic(this); 185 case D_TYPE: return (double) speciesData().getter(i).invokeBasic(this); 186 } 187 } catch (Throwable ex) { 188 throw uncaughtException(ex); 189 } 190 throw new InternalError("unexpected type: " + speciesData().key()+"."+i); 191 } 192 193 // 194 // cloning API 195 // 196 197 /*non-public*/ 198 abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf); 199 /*non-public*/ 200 abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg); 201 /*non-public*/ 202 abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg); 203 /*non-public*/ 204 abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg); 205 /*non-public*/ 206 abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg); 207 /*non-public*/ 208 abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg); 209 210 // 211 // concrete BMH classes required to close bootstrap loops 212 // 213 214 private // make it private to force users to access the enclosing class first 215 static final class Species_L extends BoundMethodHandle { 216 217 final Object argL0; 218 219 private Species_L(MethodType mt, LambdaForm lf, Object argL0) { 220 super(mt, lf); 221 this.argL0 = argL0; 222 } 223 224 @Override 225 /*non-public*/ 226 SpeciesData speciesData() { 227 return BMH_SPECIES; 228 } 229 230 /*non-public*/ 231 static @Stable SpeciesData BMH_SPECIES; 232 233 /*non-public*/ 234 static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) { 235 return new Species_L(mt, lf, argL0); 236 } 237 @Override 238 /*non-public*/ 239 final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) { 240 return new Species_L(mt, lf, argL0); 241 } 242 @Override 243 /*non-public*/ 244 final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) { 245 try { 246 return (BoundMethodHandle) BMH_SPECIES.extendWith(L_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg); 247 } catch (Throwable ex) { 248 throw uncaughtException(ex); 249 } 250 } 251 @Override 252 /*non-public*/ 253 final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) { 254 try { 255 return (BoundMethodHandle) BMH_SPECIES.extendWith(I_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg); 256 } catch (Throwable ex) { 257 throw uncaughtException(ex); 258 } 259 } 260 @Override 261 /*non-public*/ 262 final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) { 263 try { 264 return (BoundMethodHandle) BMH_SPECIES.extendWith(J_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg); 265 } catch (Throwable ex) { 266 throw uncaughtException(ex); 267 } 268 } 269 @Override 270 /*non-public*/ 271 final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) { 272 try { 273 return (BoundMethodHandle) BMH_SPECIES.extendWith(F_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg); 274 } catch (Throwable ex) { 275 throw uncaughtException(ex); 276 } 277 } 278 @Override 279 /*non-public*/ 280 final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) { 281 try { 282 return (BoundMethodHandle) BMH_SPECIES.extendWith(D_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg); 283 } catch (Throwable ex) { 284 throw uncaughtException(ex); 285 } 286 } 287 } 288 289 // 290 // BMH species meta-data 291 // 292 293 /*non-public*/ 294 static final class SpeciesData 295 extends ClassSpecializer<BoundMethodHandle, String, SpeciesData>.SpeciesData { 296 // This array is filled in lazily, as new species come into being over time. 297 @Stable private final SpeciesData[] extensions = new SpeciesData[ARG_TYPE_LIMIT]; 298 299 public SpeciesData(Specializer outer, String key) { 300 outer.super(key); 301 } 302 303 @Override 304 protected String deriveClassName() { 305 String typeString = deriveTypeString(); 306 if (typeString.isEmpty()) { 307 return SimpleMethodHandle.class.getName(); 308 } 309 return BoundMethodHandle.class.getName() + "$Species_" + typeString; 310 } 311 312 @Override 313 protected List<Class<?>> deriveFieldTypes(String key) { 314 ArrayList<Class<?>> types = new ArrayList<>(key.length()); 315 for (int i = 0; i < key.length(); i++) { 316 types.add(basicType(key.charAt(i)).basicTypeClass()); 317 } 318 return types; 319 } 320 321 @Override 322 protected String deriveTypeString() { 323 // (If/when we have to add nominal types, just inherit the more complex default.) 324 return key(); 325 } 326 327 @Override 328 protected MethodHandle deriveTransformHelper(MemberName transform, int whichtm) { 329 if (whichtm == Specializer.TN_COPY_NO_EXTEND) { 330 return factory(); 331 } else if (whichtm < ARG_TYPE_LIMIT) { 332 return extendWith((byte) whichtm).factory(); 333 } else { 334 throw newInternalError("bad transform"); 335 } 336 } 337 338 @Override 339 protected <X> List<X> deriveTransformHelperArguments(MemberName transform, int whichtm, List<X> args, List<X> fields) { 340 assert(verifyTHAargs(transform, whichtm, args, fields)); 341 // The rule is really simple: Keep the first two arguments 342 // the same, then put in the fields, then put any other argument. 343 args.addAll(2, fields); 344 return args; 345 } 346 347 private boolean verifyTHAargs(MemberName transform, int whichtm, List<?> args, List<?> fields) { 348 assert(transform == Specializer.BMH_TRANSFORMS.get(whichtm)); 349 assert(args.size() == transform.getMethodType().parameterCount()); 350 assert(fields.size() == this.fieldCount()); 351 final int MH_AND_LF = 2; 352 if (whichtm == Specializer.TN_COPY_NO_EXTEND) { 353 assert(transform.getMethodType().parameterCount() == MH_AND_LF); 354 } else if (whichtm < ARG_TYPE_LIMIT) { 355 assert(transform.getMethodType().parameterCount() == MH_AND_LF+1); 356 final BasicType type = basicType((byte) whichtm); 357 assert(transform.getParameterTypes()[MH_AND_LF] == type.basicTypeClass()); 358 } else { 359 return false; 360 } 361 return true; 362 } 363 364 /*non-public*/ 365 SpeciesData extendWith(byte typeNum) { 366 SpeciesData sd = extensions[typeNum]; 367 if (sd != null) return sd; 368 sd = SPECIALIZER.findSpecies(key() + BasicType.basicType(typeNum).basicTypeChar()); 369 extensions[typeNum] = sd; 370 return sd; 371 } 372 } 373 374 /*non-public*/ 375 static final Specializer SPECIALIZER = new Specializer(); 376 static { 377 SimpleMethodHandle.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies(""); 378 Species_L.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies("L"); 379 } 380 381 /*non-public*/ 382 static final class Specializer 383 extends ClassSpecializer<BoundMethodHandle, String, SpeciesData> { 384 385 private static final MemberName SPECIES_DATA_ACCESSOR; 386 387 static { 388 try { 389 SPECIES_DATA_ACCESSOR = IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BoundMethodHandle.class, 390 "speciesData", MethodType.methodType(BoundMethodHandle.SpeciesData.class)); 391 } catch (ReflectiveOperationException ex) { 392 throw newInternalError("Bootstrap link error", ex); 393 } 394 } 395 396 private Specializer() { 397 super( // Reified type parameters: 398 BoundMethodHandle.class, String.class, BoundMethodHandle.SpeciesData.class, 399 // Principal constructor type: 400 MethodType.methodType(void.class, MethodType.class, LambdaForm.class), 401 // Required linkage between class and species: 402 SPECIES_DATA_ACCESSOR, 403 "BMH_SPECIES", 404 BMH_TRANSFORMS); 405 } 406 407 @Override 408 protected String topSpeciesKey() { 409 return ""; 410 } 411 412 @Override 413 protected BoundMethodHandle.SpeciesData newSpeciesData(String key) { 414 return new BoundMethodHandle.SpeciesData(this, key); 415 } 416 417 static final List<MemberName> BMH_TRANSFORMS; 418 static final int TN_COPY_NO_EXTEND = V_TYPE_NUM; 419 static { 420 final Class<BoundMethodHandle> BMH = BoundMethodHandle.class; 421 // copyWithExtendLIJFD + copyWith 422 try { 423 BMH_TRANSFORMS = List.of( 424 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendL", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, Object.class)), 425 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendI", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, int.class)), 426 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendJ", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, long.class)), 427 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendF", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, float.class)), 428 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendD", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, double.class)), 429 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWith", MethodType.methodType(BMH, MethodType.class, LambdaForm.class)) 430 ); 431 } catch (ReflectiveOperationException ex) { 432 throw newInternalError("Failed resolving copyWith methods", ex); 433 } 434 435 // as it happens, there is one transform per BasicType including V_TYPE 436 assert(BMH_TRANSFORMS.size() == TYPE_LIMIT); 437 } 438 439 /** 440 * Generation of concrete BMH classes. 441 * 442 * A concrete BMH species is fit for binding a number of values adhering to a 443 * given type pattern. Reference types are erased. 444 * 445 * BMH species are cached by type pattern. 446 * 447 * A BMH species has a number of fields with the concrete (possibly erased) types of 448 * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs, 449 * which can be included as names in lambda forms. 450 */ 451 class Factory extends ClassSpecializer<BoundMethodHandle, String, BoundMethodHandle.SpeciesData>.Factory { 452 @Override 453 protected String chooseFieldName(Class<?> type, int index) { 454 return "arg" + super.chooseFieldName(type, index); 455 } 456 } 457 458 @Override 459 protected Factory makeFactory() { 460 return new Factory(); 461 } 462 } 463 464 static SpeciesData speciesData_L() { return Species_L.BMH_SPECIES; } 465 static SpeciesData speciesData_LL() { return SPECIALIZER.findSpecies("LL"); } 466 static SpeciesData speciesData_LLL() { return SPECIALIZER.findSpecies("LLL"); } 467 static SpeciesData speciesData_LLLL() { return SPECIALIZER.findSpecies("LLLL"); } 468 static SpeciesData speciesData_LLLLL() { return SPECIALIZER.findSpecies("LLLLL"); } 469 }