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