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