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.lang.reflect.Method; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Objects; 35 36 import static java.lang.invoke.LambdaForm.BasicType; 37 import static java.lang.invoke.LambdaForm.BasicType.*; 38 import static java.lang.invoke.MethodHandleStatics.newInternalError; 39 import static java.lang.invoke.MethodHandleStatics.uncaughtException; 40 41 /** 42 * The flavor of method handle which emulates an invoke instruction 43 * on a predetermined argument. The JVM dispatches to the correct method 44 * when the handle is created, not when it is invoked. 45 * 46 * All bound arguments are encapsulated in dedicated species. 47 */ 48 /*non-public*/ abstract class BoundMethodHandle extends MethodHandle { 49 50 /*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) { 51 super(type, form); 52 assert(speciesData() == formSpeciesData(form)); 53 } 54 55 // 56 // BMH API and internals 57 // 58 59 static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) { 60 // for some type signatures, there exist pre-defined concrete BMH classes 61 try { 62 switch (xtype) { 63 case L_TYPE: 64 return bindSingle(type, form, x); // Use known fast path. 65 case I_TYPE: 66 return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(I_TYPE_NUM).factory().invokeBasic(type, form, ValueConversions.widenSubword(x)); 67 case J_TYPE: 68 return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(J_TYPE_NUM).factory().invokeBasic(type, form, (long) x); 69 case F_TYPE: 70 return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(F_TYPE_NUM).factory().invokeBasic(type, form, (float) x); 71 case D_TYPE: 72 return (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 BMHSpecies} 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*/ abstract BMHSpecies speciesData(); 142 143 /*non-public*/ static BMHSpecies formSpeciesData(LambdaForm form) { 144 Object c = form.names[0].constraint; 145 if (c instanceof BMHSpecies) { 146 return (BMHSpecies) 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*/ final int fieldCount() { return speciesData().fieldCount(); } 156 157 @Override 158 Object internalProperties() { 159 return "\n& BMH="+internalValues(); 160 } 161 162 @Override 163 final String internalValues() { 164 int count = fieldCount(); 165 if (count == 1) { 166 return "[" + arg(0) + "]"; 167 } 168 StringBuilder sb = new StringBuilder("["); 169 for (int i = 0; i < count; ++i) { 170 sb.append("\n ").append(i).append(": ( ").append(arg(i)).append(" )"); 171 } 172 return sb.append("\n]").toString(); 173 } 174 175 /*non-public*/ final Object arg(int i) { 176 try { 177 switch (BasicType.basicType(speciesData().fieldTypes().get(i))) { 178 case L_TYPE: return speciesData().getter(i).invokeBasic(this); 179 case I_TYPE: return (int) speciesData().getter(i).invokeBasic(this); 180 case J_TYPE: return (long) speciesData().getter(i).invokeBasic(this); 181 case F_TYPE: return (float) speciesData().getter(i).invokeBasic(this); 182 case D_TYPE: return (double) speciesData().getter(i).invokeBasic(this); 183 } 184 } catch (Throwable ex) { 185 throw uncaughtException(ex); 186 } 187 throw new InternalError("unexpected type: " + speciesData().key()+"."+i); 188 } 189 190 // 191 // cloning API 192 // 193 194 /*non-public*/ abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf); 195 /*non-public*/ abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg); 196 /*non-public*/ abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg); 197 /*non-public*/ abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg); 198 /*non-public*/ abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg); 199 /*non-public*/ abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg); 200 201 // 202 // concrete BMH classes required to close bootstrap loops 203 // 204 205 private // make it private to force users to access the enclosing class first 206 static final class Species_L extends BoundMethodHandle { 207 final Object argL0; 208 private Species_L(MethodType mt, LambdaForm lf, Object argL0) { 209 super(mt, lf); 210 this.argL0 = argL0; 211 } 212 @Override 213 /*non-public*/ BMHSpecies speciesData() { 214 return BMH_SPECIES; 215 } 216 /*non-public*/ static @Stable 217 BMHSpecies BMH_SPECIES; 218 /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) { 219 return new Species_L(mt, lf, argL0); 220 } 221 @Override 222 /*non-public*/ final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) { 223 return new Species_L(mt, lf, argL0); 224 } 225 @Override 226 /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) { 227 try { 228 return (BoundMethodHandle) BMH_SPECIES.extendWith(L_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg); 229 } catch (Throwable ex) { 230 throw uncaughtException(ex); 231 } 232 } 233 @Override 234 /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) { 235 try { 236 return (BoundMethodHandle) BMH_SPECIES.extendWith(I_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 copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) { 243 try { 244 return (BoundMethodHandle) BMH_SPECIES.extendWith(J_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 copyWithExtendF(MethodType mt, LambdaForm lf, float narg) { 251 try { 252 return (BoundMethodHandle) BMH_SPECIES.extendWith(F_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 copyWithExtendD(MethodType mt, LambdaForm lf, double narg) { 259 try { 260 return (BoundMethodHandle) BMH_SPECIES.extendWith(D_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg); 261 } catch (Throwable ex) { 262 throw uncaughtException(ex); 263 } 264 } 265 } 266 267 // 268 // BMH species meta-data 269 // 270 271 /*non-public*/ 272 static final class BMHSpecies extends ClassSpecializer<BoundMethodHandle, String, BMHSpecies>.SpeciesData<BoundMethodHandle, String> { 273 // This array is filled in lazily, as new species come into being over time. 274 @Stable final private BMHSpecies[] extensions = new BMHSpecies[ARG_TYPE_LIMIT]; 275 276 public BMHSpecies(Specializer outer, String key) { 277 outer.super(key); 278 } 279 280 @Override 281 protected List<Class<?>> deriveFieldTypes(String key) { 282 ArrayList<Class<?>> types = new ArrayList<>(key.length()); 283 for (int i = 0; i < key.length(); i++) { 284 types.add(basicType(key.charAt(i)).basicTypeClass()); 285 } 286 return types; 287 } 288 289 @Override 290 protected String deriveTypeString() { 291 // (If/when we have to add nominal types, just inherit the more complex default.) 292 return key(); 293 } 294 295 @Override 296 protected MethodHandle deriveTransformHelper(Method transform, int whichtm) { 297 if (whichtm == Specializer.TN_COPY_NO_EXTEND) 298 return factory(); 299 else if (whichtm < ARG_TYPE_LIMIT) 300 return extendWith((byte)whichtm).factory(); 301 else 302 throw newInternalError("bad transform"); 303 } 304 305 @Override 306 protected <X> List<X> deriveTransformHelperArguments(Method transform, int whichtm, List<X> args, List<X> fields) { 307 assert(verifyTHAargs(transform, whichtm, args, fields)); 308 // The rule is really simple: Keep the first two arguments 309 // the same, then put in the fields, then put any other argument. 310 args.addAll(2, fields); 311 return args; 312 } 313 private boolean verifyTHAargs(Method transform, int whichtm, List<?> args, List<?> fields) { 314 assert(transform == Specializer.BMH_TRANSFORMS.get(whichtm)); 315 assert(args.size() == transform.getParameterCount()); 316 assert(fields.size() == this.fieldCount()); 317 final int MH_AND_LF = 2; 318 if (whichtm == Specializer.TN_COPY_NO_EXTEND) { 319 assert(transform.getParameterCount() == MH_AND_LF); 320 } else if (whichtm < ARG_TYPE_LIMIT) { 321 assert(transform.getParameterCount() == MH_AND_LF+1); 322 final BasicType type = basicType((byte) whichtm); 323 assert(transform.getParameterTypes()[MH_AND_LF] == type.basicTypeClass()); 324 } else { 325 return false; 326 } 327 return true; 328 } 329 //private boolean verfiyTHA(); 330 331 /*non-public*/ BMHSpecies extendWith(byte typeNum) { 332 BMHSpecies sd = extensions[typeNum]; 333 if (sd != null) return sd; 334 sd = SPECIALIZER.findSpecies(key() + BasicType.basicType(typeNum).basicTypeChar()); 335 extensions[typeNum] = sd; 336 return sd; 337 } 338 } 339 340 /*non-public*/ 341 static final Specializer SPECIALIZER = new Specializer(); 342 343 /*non-public*/ 344 static final class Specializer extends ClassSpecializer<BoundMethodHandle, String, BMHSpecies> { 345 private Specializer() { 346 super( // Reified type parameters: 347 BoundMethodHandle.class, String.class, BMHSpecies.class, 348 // Principal constructor type: 349 MethodType.methodType(void.class, MethodType.class, LambdaForm.class), 350 // Required linkage between class and species: 351 reflectMethod(BoundMethodHandle.class, "speciesData"), 352 "BMH_SPECIES", 353 BMH_TRANSFORMS); 354 } 355 356 @Override 357 protected String topSpeciesKey() { 358 return ""; 359 } 360 361 @Override 362 protected String addFieldTypeToKey(String key, Class<?> type) { 363 BasicType bt = basicType(type); 364 if (type != bt.basicTypeClass()) throw newInternalError("must be basic-type"); 365 Objects.requireNonNull(key); 366 return key + bt.basicTypeChar(); 367 } 368 369 @Override 370 protected List<Class<? extends BoundMethodHandle>> predeclaredSpeciesCode() { 371 List<Class<? extends BoundMethodHandle>> result = new ArrayList<>(); 372 // pick up all nested classes (Species_L): 373 result.addAll(super.predeclaredSpeciesCode()); 374 // pick up the special nullary version: 375 result.add(SimpleMethodHandle.class); 376 return result; 377 } 378 379 @Override 380 protected BMHSpecies newSpeciesData(String key) { 381 return new BMHSpecies(this, key); 382 } 383 384 static final List<Method> BMH_TRANSFORMS; 385 static final int TN_COPY_NO_EXTEND = V_TYPE_NUM; 386 static { 387 ArrayList<Method> result = new ArrayList<>(); 388 final Class<BoundMethodHandle> BMH = BoundMethodHandle.class; 389 Class<?>[] params = { MethodType.class, LambdaForm.class, null }; 390 // for each basic type T, note the transform BMH::copyWithExtendT(MT, LF, T) 391 for (BasicType type : BasicType.ARG_TYPES) { 392 final String tname = "copyWithExtend" + type.basicTypeChar(); 393 params[params.length-1] = type.basicTypeClass(); 394 result.add(ClassSpecializer.reflectMethod(BMH, tname, params)); 395 } 396 // at the end add BMH::copyWith(MT, LF) 397 assert(result.size() == TN_COPY_NO_EXTEND); 398 result.add(ClassSpecializer.reflectMethod(BMH, "copyWith", params[0], params[1])); 399 // as it happens, there is one transform per BasicType including V_TYPE 400 assert(result.size() == TYPE_LIMIT); 401 BMH_TRANSFORMS = List.of(result.toArray(new Method[result.size()])); 402 } 403 404 /** 405 * Generation of concrete BMH classes. 406 * 407 * A concrete BMH species is fit for binding a number of values adhering to a 408 * given type pattern. Reference types are erased. 409 * 410 * BMH species are cached by type pattern. 411 * 412 * A BMH species has a number of fields with the concrete (possibly erased) types of 413 * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs, 414 * which can be included as names in lambda forms. 415 */ 416 class Factory extends ClassSpecializer<BoundMethodHandle, String, BMHSpecies>.Factory { 417 @Override 418 protected String chooseFieldName(Class<?> type, int index) { 419 return "arg" + super.chooseFieldName(type, index); 420 } 421 422 @Override protected String loadSpeciesKeyFromPredefinedClass(Class<? extends BoundMethodHandle> speciesClass) { 423 if (speciesClass == SimpleMethodHandle.class) return ""; 424 assert(speciesClass.getEnclosingClass() == BoundMethodHandle.class); 425 String name = speciesClass.getSimpleName(); 426 assert(name.startsWith("Species_")); 427 final String key = name.substring(name.indexOf('_') + 1); 428 return key; 429 } 430 } 431 432 @Override 433 protected Factory makeFactory() { 434 return new Factory(); 435 } 436 } 437 438 private static final BMHSpecies[] SPECIES_DATA_CACHE = new BMHSpecies[6]; 439 private static BMHSpecies checkCache(int size, String types) { 440 int idx = size - 1; 441 BMHSpecies data = SPECIES_DATA_CACHE[idx]; 442 if (data != null) return data; 443 SPECIES_DATA_CACHE[idx] = data = SPECIALIZER.findSpecies(types); 444 return data; 445 } 446 static BMHSpecies speciesData_L() { return checkCache(1, "L"); } 447 static BMHSpecies speciesData_LL() { return checkCache(2, "LL"); } 448 static BMHSpecies speciesData_LLL() { return checkCache(3, "LLL"); } 449 static BMHSpecies speciesData_LLLL() { return checkCache(4, "LLLL"); } 450 static BMHSpecies speciesData_LLLLL() { return checkCache(5, "LLLLL"); } 451 }