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