1 /*
   2  * Copyright (c) 2017, 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 java.lang.constant.Constable;
  29 import java.lang.constant.ConstantDesc;
  30 import java.lang.invoke.AbstractBootstrapCallInfo.*;
  31 import java.lang.invoke.MethodHandles.Lookup;
  32 import java.util.List;
  33 import java.util.Objects;
  34 import sun.invoke.util.Wrapper;
  35 
  36 import static java.lang.invoke.BootstrapMethodInvoker.invokeCommon;
  37 
  38 /**
  39  * An interface providing full static information about a particular
  40  * call to a
  41  * <a href="package-summary.html#bsm">bootstrap method</a> of an
  42  * dynamic call site or dynamic constant.
  43  * This information includes the bootstrap method itself, the associated
  44  * name and type, and any associated static arguments.
  45  * <p>
  46  * If a bootstrap method declares exactly two arguments, and is
  47  * not of variable arity, then it is fed only two arguments by
  48  * the JVM, the {@linkplain Lookup lookup object} and an instance
  49  * of {@code BootstrapCallInfo} which supplies the rest of the
  50  * information about the call.
  51  * <p>
  52  * The API for accessing the static arguments allows the bootstrap
  53  * method to reorder the resolution (in the constant pool) of the
  54  * static arguments, and to catch errors resulting from the resolution.
  55  * This mode of evaluation <em>pulls</em> bootstrap parameters from
  56  * the JVM under control of the bootstrap method, as opposed to
  57  * the JVM <em>pushing</em> parameters to a bootstrap method
  58  * by resolving them all before the bootstrap method is called.
  59  * @apiNote
  60  * <p>
  61  * The {@linkplain Lookup lookup object} is <em>not</em> included in this
  62  * bundle of information, so as not to obscure the access control
  63  * logic of the program.
  64  * In cases where there are many thousands of parameters, it may
  65  * be preferable to pull their resolved values, either singly or in
  66  * batches, rather than wait until all of them have been resolved
  67  * before a constant or call site can be used.
  68  * <p>
  69  * A push mode bootstrap method can be adapted to a pull mode
  70  * bootstrap method, and vice versa.  For example, this generic
  71  * adapter pops a push-mode bootstrap method from the beginning
  72  * of the static argument list, eagerly resolves all the remaining
  73  * static arguments, and invokes the popped method in push mode.
  74  * The callee has no way of telling that it was not called directly
  75  * from the JVM.
  76  * <blockquote><pre>{@code
  77 static Object genericBSM(Lookup lookup, BootstrapCallInfo<Object> bsci)
  78     throws Throwable {
  79   ArrayList<Object> args = new ArrayList<>();
  80   args.add(lookup);
  81   args.add(bsci.invocationName());
  82   args.add(bsci.invocationType());
  83   MethodHandle bsm = (MethodHandle) bsci.argument(0);
  84   List<Object> restOfArgs = bsci.argumentList().subList(1, bsci.argumentCount());
  85   // the next line eagerly resolves all remaining static arguments:
  86   args.addAll(restOfArgs);
  87   return bsm.invokeWithArguments(args);
  88 }
  89  * }</pre></blockquote>
  90  *
  91  * @param <T> the type {@code MethodType} or {@code Class}
  92  *
  93  * @since 12
  94  */
  95 // public
  96 interface BootstrapCallInfo<T extends TypeDescriptor & Constable<T>> {
  97 
  98     /** Returns the bootstrap method for this call.
  99      * @return the bootstrap method
 100      */
 101     MethodHandle bootstrapMethod();
 102 
 103     /** Returns the method name or constant name for this call.
 104      * @return the method name or constant name
 105      */
 106     String invocationName();
 107 
 108     /** Returns the method type or constant type for this call.
 109      * @return the method type or constant type
 110      */
 111     T invocationType();
 112 
 113     /** Returns a ConstantDesc for the method type or constant type for this call.
 114      * Does not (by itself) trigger resolution of this type.
 115      * @return the method type or constant type
 116      */
 117     ConstantDesc<T> invocationTypeDesc();
 118 
 119     /**
 120      * Returns the number of static arguments.
 121      * @return the number of static arguments
 122      */
 123     int argumentCount();
 124 
 125     /**
 126      * Returns the selected static argument, resolving it if necessary.
 127      * Throws a linkage error if resolution proves impossible.
 128      * @param index which static argument to select
 129      * @return the selected static argument
 130      * @throws LinkageError if the selected static argument needs resolution
 131      * and cannot be resolved
 132      */
 133     Object argument(int index) throws LinkageError;
 134 
 135     /**
 136      * Returns the selected static argument,
 137      * or the given sentinel value if there is none available.
 138      * If the static argument cannot be resolved, the sentinel will be returned.
 139      * If the static argument can (perhaps) be resolved, but has not yet been resolved,
 140      * then the sentinel <em>may</em> be returned, at the implementation's discretion.
 141      * To force resolution (and a possible exception), call {@link #argument(int)}.
 142      * @param index which static argument to select
 143      * @param ifNotPresent the sentinel value to return if the static argument is not present
 144      * @return the selected static argument, if available, else the sentinel value
 145      */
 146     default Object argument(int index, Object ifNotPresent) {
 147         if (argumentIsPresent(index))  return argument(index);
 148         return ifNotPresent;
 149     }
 150 
 151     /**
 152      * Returns a symbolic reference underlying the selected static argument,
 153      * if it is available.
 154      * @param index which static argument to select
 155      * @return a symbolic reference underlying the selected static argument
 156      * @throws IllegalArgumentException if the original symbolic reference is not available,
 157      * and a substitute cannot be created on the fly by {@link ConstantDesc}.
 158      */
 159     ConstantDesc<?> argumentDesc(int index);
 160 
 161     /**
 162      * Returns an indication of whether a static argument may be available.
 163      * If it returns {@code true}, it will always return true in the future,
 164      * and a call to {@link #argument(int)} will never throw an exception.
 165      * <p>
 166      * After a normal return from {@link #argument(int)} or a present
 167      * value is reported from {@link #argument(int,Object)}, this method
 168      * must always return true.
 169      * <p>
 170      * If this method returns {@code false}, nothing in particular
 171      * can be inferred, since the query only concerns the internal
 172      * logic of the {@code BootstrapCallInfo} object which ensures that a
 173      * successful query to a constant will always remain successful.
 174      * The only way to force a permanent decision about whether
 175      * a static argument is available is to call {@link #argument(int)} and
 176      * be ready for an exception if the constant is unavailable.
 177      * @param index which constant to select
 178      * @return {@code true} if the selected static argument is known by
 179      *     this object to be present, {@code false} if it is known
 180      *     not to be present or
 181      */
 182     boolean argumentIsPresent(int index);
 183 
 184 
 185     /// Views
 186 
 187     /**
 188      * Create a view on the static arguments as a {@link List} view.
 189      * Any request for a static argument through this view will
 190      * force resolution, and may therefore cause a {@code LinkageError}.
 191      * @return a {@code List} view on the static arguments which will force resolution
 192      */
 193     default List<Object> argumentList() {
 194         return new ArgList(this, 0, argumentCount());
 195     }
 196 
 197     /**
 198      * Create a view on the static arguments as a {@link List} view.
 199      * Any request for a static argument through this view will
 200      * return the given sentinel value, if the corresponding
 201      * call to {@link #argument(int,Object)} would do so.
 202      * @param ifNotPresent the sentinel value to return if a static argument is not present
 203      * @return a {@code List} view on the static arguments which will not force resolution
 204      */
 205     default List<Object> argumentList(Object ifNotPresent) {
 206         return new ArgList(this, 0, argumentCount(), ifNotPresent);
 207     }
 208 
 209     /**
 210      * Create a view on the symbolic references of the static arguments as a {@link List} view.
 211      * @return a {@code List} view on this group's symbolic references
 212      */
 213     default List<ConstantDesc<?>> argumentDescList() {
 214         List<Object> syms = new ArgList(this, true, 0, argumentCount());
 215         @SuppressWarnings({"unchecked", "rawtypes"})
 216         List<ConstantDesc<?>> result = (List) syms;
 217         return result;
 218     }
 219 
 220     /// Factories and helper methods
 221 
 222     /**
 223      * Invoke a bootstrap method handle with arguments obtained by resolving
 224      * the sequence of constants supplied by a given bootstrap call descriptor,
 225      * {@code bci}.
 226      * The first argument to the method will be {@code lookup}.
 227      * The second argument will be the invocation name of {@code bci}.
 228      * The third argument will be the invocation type of {@code bci}.
 229      * The fourth and subsequent arguments (if any) will be the resolved
 230      * constants, in order, supplied by {@code bci}.
 231      * <p>
 232      * @apiNote
 233      * This method behaves like the following but may be more optimal:
 234      * <blockquote><pre>{@code
 235      *   ArrayList<Object> args = new ArrayList<>();
 236      *   args.add(lookup);
 237      *   args.add(name);
 238      *   args.add(type);
 239      *   args.addAll(staticArgs);
 240      *   return handle.invokeWithArguments(args);
 241      * }</pre></blockquote>
 242      *
 243      * @param handle the bootstrap method handle to be invoked on the static arguments
 244      * @param lookup the lookup
 245      * @param name the name associated with the constant or call site being linked
 246      * @param type the type associated with the constant or call site being linked
 247      * @param staticArgs the static argument list
 248      * @return the result of invocation
 249      * @throws Throwable if an error occurs when resolving the constants from
 250      *         the bootstrap call descriptor or invoking the method handle
 251      */
 252     static Object invokeWithMetadata(MethodHandle handle,
 253                                      MethodHandles.Lookup lookup,
 254                                      String name,
 255                                      TypeDescriptor type,
 256                                      List<Object> staticArgs)
 257             throws Throwable {
 258         Objects.requireNonNull(lookup);
 259         return invokeCommon(handle, lookup, name, type, null, staticArgs);
 260     }
 261 
 262     /**
 263      * Invoke a bootstrap method handle with arguments obtained by resolving
 264      * the sequence of constants supplied by a given bootstrap call descriptor,
 265      * {@code bci}.
 266      * The first argument to the method will be {@code lookup}.
 267      * The second argument will be the invocation name of {@code bci}.
 268      * The third argument will be the invocation type of {@code bci}.
 269      * The fourth and subsequent arguments (if any) will be the resolved
 270      * constants, in order, supplied by {@code bci}.
 271      * <p>
 272      * @apiNote
 273      * This method behaves like the following but may be more optimal:
 274      * <blockquote><pre>{@code
 275      *   ArrayList<Object> args = new ArrayList<>();
 276      *   args.add(lookup);
 277      *   args.add(name);
 278      *   args.add(type);
 279      *   args.addAll(Arrays.asList(staticArgs));
 280      *   return handle.invokeWithArguments(args);
 281      * }</pre></blockquote>
 282      *
 283      * @param handle the bootstrap method handle to be invoked on the static arguments
 284      * @param lookup the lookup
 285      * @param name the name associated with the constant or call site being linked
 286      * @param type the type associated with the constant or call site being linked
 287      * @param staticArgs the static argument list
 288      * @return the result of invocation
 289      * @throws Throwable if an error occurs when resolving the constants from
 290      *         the bootstrap call descriptor or invoking the method handle
 291      */
 292     static Object invokeWithMetadata(MethodHandle handle,
 293                                      MethodHandles.Lookup lookup,
 294                                      String name,
 295                                      TypeDescriptor type,
 296                                      Object... staticArgs)
 297             throws Throwable {
 298         Objects.requireNonNull(lookup);
 299         Objects.requireNonNull(staticArgs);
 300         return invokeCommon(handle, lookup, name, type, staticArgs, null);
 301     }
 302 
 303     /**
 304      * Invoke a bootstrap method handle with arguments obtained by resolving
 305      * the sequence of constants supplied by a given bootstrap call descriptor,
 306      * {@code bci}.
 307      * The first argument to the method will be {@code lookup}.
 308      * The second argument will be the invocation name of {@code bci}.
 309      * The third argument will be the invocation type of {@code bci}.
 310      * The fourth and subsequent arguments (if any) will be the resolved
 311      * constants, in order, supplied by {@code bci}.
 312      * <p>
 313      * @apiNote
 314      * This method behaves like the following but may be more optimal:
 315      * <blockquote><pre>{@code
 316      *   ArrayList<Object> args = new ArrayList<>();
 317      *   args.add(lookup);
 318      *   args.add(bci.invocationName());
 319      *   args.add(bci.invocationType());
 320      *   args.addAll(bci.argumentList());
 321      *   return handle.invokeWithArguments(args);
 322      * }</pre></blockquote>
 323      *
 324      * @param handle the bootstrap method handle to be invoked with resolved
 325      *        constants supplied by {@code bci}
 326      * @param lookup the lookup
 327      * @param bsci the bootstrap call descriptor
 328      * @return the result of invocation
 329      * @throws Throwable if an error occurs when resolving the constants from
 330      *         the bootstrap call descriptor or invoking the method handle
 331      */
 332     static Object invokeWithMetadata(MethodHandle handle,
 333                                      MethodHandles.Lookup lookup,
 334                                      BootstrapCallInfo<?> bsci)
 335             throws Throwable {
 336         Objects.requireNonNull(lookup);
 337         return invokeCommon(handle, lookup, bsci.invocationName(), bsci.invocationType(), AbstractBootstrapCallInfo.maybeShareArguments(bsci), bsci.argumentList());
 338     }
 339 
 340     /**
 341      * Convert the result returned by a bootstrap method to the class
 342      * required by the bootstrap method's {@code invocationType}.
 343      *
 344      * @param bsci the bootstrap call descriptor
 345      * @param result the result to be converted
 346      * @param <T> the type {@code MethodType} or {@code Class}
 347      * @return the converted result
 348      * @throws ClassCastException if a value conversion error occurs during conversion
 349      * @throws WrongMethodTypeException if a method type mismatch is detected occurs during conversion
 350      */
 351     static
 352     <T extends TypeDescriptor & Constable<T>>
 353     Object convertResult(BootstrapCallInfo<T> bsci, Object result) {
 354         // FIXME:  If invocationType cannot be resolved, some results are still valid.
 355         return convertResult(bsci.invocationType(), bsci.bootstrapMethod().type().returnType(), result);
 356     }
 357 
 358     /**
 359      * Convert the result returned by a bootstrap method to the class
 360      * required by the bootstrap method's {@code invocationType}.
 361      *
 362      * @param type the method type or constant type to be obtained
 363      * @param resultType the type of the result (return type of the BSM that returned the result)
 364      * @param result the result to be converted
 365      * @param <T> the type {@code MethodType} or {@code Class}
 366      * @return the converted result
 367      * @throws ClassCastException if a value conversion error occurs during conversion
 368      * @throws WrongMethodTypeException if a method type mismatch is detected occurs during conversion
 369      */
 370     static
 371     <T extends TypeDescriptor & Constable<T>>
 372     Object convertResult(T type, Class<?> resultType, Object result) {
 373         Class<?> resultClass;
 374         boolean isFieldType;
 375         if (type instanceof Class) {
 376             isFieldType = true;
 377             resultClass = (Class<?>) type;
 378         } else {
 379             isFieldType = false;
 380             resultClass = null;
 381         }
 382         if (isFieldType && resultClass.isPrimitive()) {
 383             Class<?> wrapperClass = Wrapper.asWrapperType(resultClass);
 384             if (result.getClass() == wrapperClass) {
 385                 return result;  // fast path
 386             }
 387             // Non-reference conversions are more than just plain casts.
 388             // By pushing the value through a funnel of the form (R x)->x,
 389             // the boxed result can be widened as needed.  See MH::asType.
 390             MethodHandle funnel = MethodHandles.identity(resultClass);
 391             if (!MethodType.canConvert(resultType, resultClass)) {
 392                 // Example:  Result type is Integer and resultClass is short.
 393                 funnel = funnel.asType(MethodType.methodType(resultClass, resultType));
 394                 assert(false);  // should have thrown WMTE
 395             }
 396             try {
 397                 result = funnel.invoke(result);
 398             } catch (ClassCastException | WrongMethodTypeException ex) {
 399                 throw ex;
 400             } catch (Throwable ex) {
 401                 throw new InternalError(ex);
 402             }
 403             // Now it is the wrapper type for resultType.
 404             assert(result.getClass() == Wrapper.asWrapperType(resultClass));
 405             return result;
 406         } else if (isFieldType) {
 407             // A reference type.
 408             return resultClass.cast(result);
 409         } else {
 410             // Check or convert the method-like result.
 411             MethodType mt = (MethodType) type;  // must be either Class or MethodType
 412             if (result instanceof CallSite) {
 413                 CallSite cs = (CallSite) result;
 414                 if (!cs.type().equals(mt))
 415                     throw CallSite.wrongTargetType(cs, mt);
 416                 return cs;  // no conversion, just checking
 417             }
 418             if (result instanceof MethodHandle) {
 419                 // Method handles can be converted on the fly:
 420                 MethodHandle mh = (MethodHandle) result;
 421                 return mh.asType(mt);
 422             }
 423             throw new ClassCastException("CallSite bootstrap method failed to produce an instance of CallSite");
 424         }
 425     }
 426 
 427     /**
 428      * Produce a string that briefly reports the BSM, name, type,
 429      * and argument list.  For arguments, use a non-resolving list view,
 430      * with unresolved elements being presented as asterisks.
 431      * @param bsci the object to produce a string for
 432      * @return {@code this.asList("*").toString()}
 433      */
 434     public static String toString(BootstrapCallInfo<?> bsci) {
 435         MethodHandle bsm = bsci.bootstrapMethod();
 436         MemberName mem = bsm.internalMemberName();
 437         Object bsmStr = bsm;
 438         if (mem != null)  bsmStr = mem;
 439         //bsmStr = bsm.describeConstable()
 440         Object typeStr = null;
 441         try {
 442             typeStr = bsci.invocationType();
 443         } catch (LinkageError ex) {
 444             typeStr = bsci.invocationTypeDesc();
 445         }
 446         return (bsmStr
 447                 + "/" + bsci.invocationName()
 448                 + ":" + typeStr
 449                 + bsci.argumentList("*"));
 450     }
 451 }