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 }