nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java
changeset 25865 d38d876f1654
parent 24770 17f8e3b82ad3
child 26236 78b5ece438c0
equal deleted inserted replaced
25864:62406a5c8345 25865:d38d876f1654
       
     1 /*
       
     2  * Copyright (c) 2010, 2013, 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 jdk.nashorn.internal.runtime.linker;
       
    27 
       
    28 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
       
    29 
       
    30 import java.lang.invoke.CallSite;
       
    31 import java.lang.invoke.ConstantCallSite;
       
    32 import java.lang.invoke.MethodHandle;
       
    33 import java.lang.invoke.MethodHandles;
       
    34 import java.lang.invoke.MethodHandles.Lookup;
       
    35 import java.lang.invoke.MethodType;
       
    36 import jdk.internal.dynalink.CallSiteDescriptor;
       
    37 import jdk.internal.dynalink.DynamicLinker;
       
    38 import jdk.internal.dynalink.DynamicLinkerFactory;
       
    39 import jdk.internal.dynalink.GuardedInvocationFilter;
       
    40 import jdk.internal.dynalink.beans.BeansLinker;
       
    41 import jdk.internal.dynalink.beans.StaticClass;
       
    42 import jdk.internal.dynalink.linker.GuardedInvocation;
       
    43 import jdk.internal.dynalink.linker.LinkRequest;
       
    44 import jdk.internal.dynalink.linker.LinkerServices;
       
    45 import jdk.nashorn.api.scripting.JSObject;
       
    46 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
       
    47 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
       
    48 import jdk.nashorn.internal.codegen.RuntimeCallSite;
       
    49 import jdk.nashorn.internal.lookup.MethodHandleFactory;
       
    50 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
       
    51 import jdk.nashorn.internal.runtime.JSType;
       
    52 import jdk.nashorn.internal.runtime.OptimisticReturnFilters;
       
    53 import jdk.nashorn.internal.runtime.ScriptFunction;
       
    54 import jdk.nashorn.internal.runtime.ScriptRuntime;
       
    55 import jdk.nashorn.internal.runtime.options.Options;
       
    56 
       
    57 /**
       
    58  * This class houses bootstrap method for invokedynamic instructions generated by compiler.
       
    59  */
       
    60 public final class Bootstrap {
       
    61     /** Reference to the seed boostrap function */
       
    62     public static final Call BOOTSTRAP = staticCallNoLookup(Bootstrap.class, "bootstrap", CallSite.class, Lookup.class, String.class, MethodType.class, int.class);
       
    63 
       
    64     private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
       
    65 
       
    66     /**
       
    67      * The default dynalink relink threshold for megamorphisism is 8. In the case
       
    68      * of object fields only, it is fine. However, with dual fields, in order to get
       
    69      * performance on benchmarks with a lot of object instantiation and then field
       
    70      * reassignment, it can take slightly more relinks to become stable with type
       
    71      * changes swapping out an entire proprety map and making a map guard fail.
       
    72      * Therefore the relink threshold is set to 16 for dual fields (now the default).
       
    73      * This doesn't seem to have any other negative performance implication.
       
    74      *
       
    75      * See for example octane.gbemu, run with --log=fields:warning to study
       
    76      * megamorphic behavior
       
    77      */
       
    78     private static final int NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD =
       
    79             ObjectClassGenerator.OBJECT_FIELDS_ONLY ?
       
    80                      8 :
       
    81                     16;
       
    82 
       
    83     // do not create me!!
       
    84     private Bootstrap() {
       
    85     }
       
    86 
       
    87     private static final DynamicLinker dynamicLinker;
       
    88     static {
       
    89         final DynamicLinkerFactory factory = new DynamicLinkerFactory();
       
    90         final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker();
       
    91         final JSObjectLinker jsObjectLinker = new JSObjectLinker(nashornBeansLinker);
       
    92         factory.setPrioritizedLinkers(
       
    93             new NashornLinker(),
       
    94             new NashornPrimitiveLinker(),
       
    95             new NashornStaticClassLinker(),
       
    96             new BoundDynamicMethodLinker(),
       
    97             new JavaSuperAdapterLinker(),
       
    98             jsObjectLinker,
       
    99             new ReflectionCheckLinker());
       
   100         factory.setFallbackLinkers(nashornBeansLinker, new NashornBottomLinker());
       
   101         factory.setSyncOnRelink(true);
       
   102         factory.setPrelinkFilter(new GuardedInvocationFilter() {
       
   103             @Override
       
   104             public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) {
       
   105                 final CallSiteDescriptor desc = request.getCallSiteDescriptor();
       
   106                 return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType());
       
   107             }
       
   108         });
       
   109         final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD);
       
   110         if (relinkThreshold > -1) {
       
   111             factory.setUnstableRelinkThreshold(relinkThreshold);
       
   112         }
       
   113 
       
   114         // Linkers for any additional language runtimes deployed alongside Nashorn will be picked up by the factory.
       
   115         factory.setClassLoader(Bootstrap.class.getClassLoader());
       
   116 
       
   117         dynamicLinker = factory.createLinker();
       
   118     }
       
   119 
       
   120     /**
       
   121      * Returns if the given object is a "callable"
       
   122      * @param obj object to be checked for callability
       
   123      * @return true if the obj is callable
       
   124      */
       
   125     public static boolean isCallable(final Object obj) {
       
   126         if (obj == ScriptRuntime.UNDEFINED || obj == null) {
       
   127             return false;
       
   128         }
       
   129 
       
   130         return obj instanceof ScriptFunction ||
       
   131             ((obj instanceof JSObject) && ((JSObject)obj).isFunction()) ||
       
   132             isDynamicMethod(obj) ||
       
   133             isFunctionalInterfaceObject(obj) ||
       
   134             obj instanceof StaticClass;
       
   135     }
       
   136 
       
   137     /**
       
   138      * Returns if the given object is a dynalink Dynamic method
       
   139      * @param obj object to be checked
       
   140      * @return true if the obj is a dynamic method
       
   141      */
       
   142     public static boolean isDynamicMethod(final Object obj) {
       
   143         return obj instanceof BoundDynamicMethod || BeansLinker.isDynamicMethod(obj);
       
   144     }
       
   145 
       
   146     /**
       
   147      * Returns if the given object is an instance of an interface annotated with
       
   148      * java.lang.FunctionalInterface
       
   149      * @param obj object to be checked
       
   150      * @return true if the obj is an instance of @FunctionalInterface interface
       
   151      */
       
   152     public static boolean isFunctionalInterfaceObject(final Object obj) {
       
   153         return !JSType.isPrimitive(obj) && (NashornBottomLinker.getFunctionalInterfaceMethod(obj.getClass()) != null);
       
   154     }
       
   155 
       
   156     /**
       
   157      * Create a call site and link it for Nashorn. This version of the method conforms to the invokedynamic bootstrap
       
   158      * method expected signature and is referenced from Nashorn generated bytecode as the bootstrap method for all
       
   159      * invokedynamic instructions.
       
   160      * @param lookup MethodHandle lookup. Ignored as Nashorn only uses public lookup.
       
   161      * @param opDesc Dynalink dynamic operation descriptor.
       
   162      * @param type   Method type.
       
   163      * @param flags  flags for call type, trace/profile etc.
       
   164      * @return CallSite with MethodHandle to appropriate method or null if not found.
       
   165      */
       
   166     public static CallSite bootstrap(final Lookup lookup, final String opDesc, final MethodType type, final int flags) {
       
   167         return dynamicLinker.link(LinkerCallSite.newLinkerCallSite(lookup, opDesc, type, flags));
       
   168     }
       
   169 
       
   170     /**
       
   171      * Bootstrapper for a specialized Runtime call
       
   172      *
       
   173      * @param lookup       lookup
       
   174      * @param initialName  initial name for callsite
       
   175      * @param type         method type for call site
       
   176      *
       
   177      * @return callsite for a runtime node
       
   178      */
       
   179     public static CallSite runtimeBootstrap(final MethodHandles.Lookup lookup, final String initialName, final MethodType type) {
       
   180         return new RuntimeCallSite(type, initialName);
       
   181     }
       
   182 
       
   183     /**
       
   184      * Boostrapper for math calls that may overflow
       
   185      * @param lookup         lookup
       
   186      * @param name           name of operation
       
   187      * @param type           method type
       
   188      * @param programPoint   program point to bind to callsite
       
   189      *
       
   190      * @return callsite for a math instrinic node
       
   191      */
       
   192     public static CallSite mathBootstrap(final MethodHandles.Lookup lookup, final String name, final MethodType type, final int programPoint) {
       
   193         final MethodHandle mh;
       
   194         switch (name) {
       
   195         case "iadd":
       
   196             mh = JSType.ADD_EXACT.methodHandle();
       
   197             break;
       
   198         case "isub":
       
   199             mh = JSType.SUB_EXACT.methodHandle();
       
   200             break;
       
   201         case "imul":
       
   202             mh = JSType.MUL_EXACT.methodHandle();
       
   203             break;
       
   204         case "idiv":
       
   205             mh = JSType.DIV_EXACT.methodHandle();
       
   206             break;
       
   207         case "irem":
       
   208             mh = JSType.REM_EXACT.methodHandle();
       
   209             break;
       
   210         case "ineg":
       
   211             mh = JSType.NEGATE_EXACT.methodHandle();
       
   212             break;
       
   213         case "ladd":
       
   214             mh = JSType.ADD_EXACT_LONG.methodHandle();
       
   215             break;
       
   216         case "lsub":
       
   217             mh = JSType.SUB_EXACT_LONG.methodHandle();
       
   218             break;
       
   219         case "lmul":
       
   220             mh = JSType.MUL_EXACT_LONG.methodHandle();
       
   221             break;
       
   222         case "ldiv":
       
   223             mh = JSType.DIV_EXACT_LONG.methodHandle();
       
   224             break;
       
   225         case "lrem":
       
   226             mh = JSType.REM_EXACT_LONG.methodHandle();
       
   227             break;
       
   228         case "lneg":
       
   229             mh = JSType.NEGATE_EXACT_LONG.methodHandle();
       
   230             break;
       
   231         default:
       
   232             throw new AssertionError("unsupported math intrinsic");
       
   233         }
       
   234         return new ConstantCallSite(MH.insertArguments(mh, mh.type().parameterCount() - 1, programPoint));
       
   235     }
       
   236 
       
   237     /**
       
   238      * Returns a dynamic invoker for a specified dynamic operation using the public lookup. You can use this method to
       
   239      * create a method handle that when invoked acts completely as if it were a Nashorn-linked call site. An overview of
       
   240      * available dynamic operations can be found in the
       
   241      * <a href="https://github.com/szegedi/dynalink/wiki/User-Guide-0.6">Dynalink User Guide</a>, but we'll show few
       
   242      * examples here:
       
   243      * <ul>
       
   244      *   <li>Get a named property with fixed name:
       
   245      *     <pre>
       
   246      * MethodHandle getColor = Boostrap.createDynamicInvoker("dyn:getProp:color", Object.class, Object.class);
       
   247      * Object obj = ...; // somehow obtain the object
       
   248      * Object color = getColor.invokeExact(obj);
       
   249      *     </pre>
       
   250      *   </li>
       
   251      *   <li>Get a named property with variable name:
       
   252      *     <pre>
       
   253      * MethodHandle getProperty = Boostrap.createDynamicInvoker("dyn:getElem", Object.class, Object.class, String.class);
       
   254      * Object obj = ...; // somehow obtain the object
       
   255      * Object color = getProperty.invokeExact(obj, "color");
       
   256      * Object shape = getProperty.invokeExact(obj, "shape");
       
   257      * MethodHandle getNumProperty = Boostrap.createDynamicInvoker("dyn:getElem", Object.class, Object.class, int.class);
       
   258      * Object elem42 = getNumProperty.invokeExact(obj, 42);
       
   259      *     </pre>
       
   260      *   </li>
       
   261      *   <li>Set a named property with fixed name:
       
   262      *     <pre>
       
   263      * MethodHandle setColor = Boostrap.createDynamicInvoker("dyn:setProp:color", void.class, Object.class, Object.class);
       
   264      * Object obj = ...; // somehow obtain the object
       
   265      * setColor.invokeExact(obj, Color.BLUE);
       
   266      *     </pre>
       
   267      *   </li>
       
   268      *   <li>Set a property with variable name:
       
   269      *     <pre>
       
   270      * MethodHandle setProperty = Boostrap.createDynamicInvoker("dyn:setElem", void.class, Object.class, String.class, Object.class);
       
   271      * Object obj = ...; // somehow obtain the object
       
   272      * setProperty.invokeExact(obj, "color", Color.BLUE);
       
   273      * setProperty.invokeExact(obj, "shape", Shape.CIRCLE);
       
   274      *     </pre>
       
   275      *   </li>
       
   276      *   <li>Call a function on an object; two-step variant. This is the actual variant used by Nashorn-generated code:
       
   277      *     <pre>
       
   278      * MethodHandle findFooFunction = Boostrap.createDynamicInvoker("dyn:getMethod:foo", Object.class, Object.class);
       
   279      * Object obj = ...; // somehow obtain the object
       
   280      * Object foo_fn = findFooFunction.invokeExact(obj);
       
   281      * MethodHandle callFunctionWithTwoArgs = Boostrap.createDynamicInvoker("dyn:call", Object.class, Object.class, Object.class, Object.class, Object.class);
       
   282      * // Note: "call" operation takes a function, then a "this" value, then the arguments:
       
   283      * Object foo_retval = callFunctionWithTwoArgs.invokeExact(foo_fn, obj, arg1, arg2);
       
   284      *     </pre>
       
   285      *   </li>
       
   286      *   <li>Call a function on an object; single-step variant. Although Nashorn doesn't use this variant and never
       
   287      *   emits any INVOKEDYNAMIC instructions with {@code dyn:getMethod}, it still supports this standard Dynalink
       
   288      *   operation:
       
   289      *     <pre>
       
   290      * MethodHandle callFunctionFooWithTwoArgs = Boostrap.createDynamicInvoker("dyn:callMethod:foo", Object.class, Object.class, Object.class, Object.class);
       
   291      * Object obj = ...; // somehow obtain the object
       
   292      * Object foo_retval = callFunctionFooWithTwoArgs.invokeExact(obj, arg1, arg2);
       
   293      *     </pre>
       
   294      *   </li>
       
   295      * </ul>
       
   296      * Few additional remarks:
       
   297      * <ul>
       
   298      * <li>Just as Nashorn works with any Java object, the invokers returned from this method can also be applied to
       
   299      * arbitrary Java objects in addition to Nashorn JavaScript objects.</li>
       
   300      * <li>For invoking a named function on an object, you can also use the {@link InvokeByName} convenience class.</li>
       
   301      * <li>For Nashorn objects {@code getElem}, {@code getProp}, and {@code getMethod} are handled almost identically,
       
   302      * since JavaScript doesn't distinguish between different kinds of properties on an object. Either can be used with
       
   303      * fixed property name or a variable property name. The only significant difference is handling of missing
       
   304      * properties: {@code getMethod} for a missing member will link to a potential invocation of
       
   305      * {@code __noSuchMethod__} on the object, {@code getProp} for a missing member will link to a potential invocation
       
   306      * of {@code __noSuchProperty__}, while {@code getElem} for a missing member will link to an empty getter.</li>
       
   307      * <li>In similar vein, {@code setElem} and {@code setProp} are handled identically on Nashorn objects.</li>
       
   308      * <li>There's no rule that the variable property identifier has to be a {@code String} for {@code getProp/setProp}
       
   309      * and {@code int} for {@code getElem/setElem}. You can declare their type to be {@code int}, {@code double},
       
   310      * {@code Object}, and so on regardless of the kind of the operation.</li>
       
   311      * <li>You can be as specific in parameter types as you want. E.g. if you know that the receiver of the operation
       
   312      * will always be {@code ScriptObject}, you can pass {@code ScriptObject.class} as its parameter type. If you happen
       
   313      * to link to a method that expects different types, (you can use these invokers on POJOs too, after all, and end up
       
   314      * linking with their methods that have strongly-typed signatures), all necessary conversions allowed by either Java
       
   315      * or JavaScript will be applied: if invoked methods specify either primitive or wrapped Java numeric types, or
       
   316      * {@code String} or {@code boolean/Boolean}, then the parameters might be subjected to standard ECMAScript
       
   317      * {@code ToNumber}, {@code ToString}, and {@code ToBoolean} conversion, respectively. Less obviously, if the
       
   318      * expected parameter type is a SAM type, and you pass a JavaScript function, a proxy object implementing the SAM
       
   319      * type and delegating to the function will be passed. Linkage can often be optimized when linkers have more
       
   320      * specific type information than "everything can be an object".</li>
       
   321      * <li>You can also be as specific in return types as you want. For return types any necessary type conversion
       
   322      * available in either Java or JavaScript will be automatically applied, similar to the process described for
       
   323      * parameters, only in reverse direction:  if you specify any either primitive or wrapped Java numeric type, or
       
   324      * {@code String} or {@code boolean/Boolean}, then the return values will be subjected to standard ECMAScript
       
   325      * {@code ToNumber}, {@code ToString}, and {@code ToBoolean} conversion, respectively. Less obviously, if the return
       
   326      * type is a SAM type, and the return value is a JavaScript function, a proxy object implementing the SAM type and
       
   327      * delegating to the function will be returned.</li>
       
   328      * </ul>
       
   329      * @param opDesc Dynalink dynamic operation descriptor.
       
   330      * @param rtype the return type for the operation
       
   331      * @param ptypes the parameter types for the operation
       
   332      * @return MethodHandle for invoking the operation.
       
   333      */
       
   334     public static MethodHandle createDynamicInvoker(final String opDesc, final Class<?> rtype, final Class<?>... ptypes) {
       
   335         return createDynamicInvoker(opDesc, MethodType.methodType(rtype, ptypes));
       
   336     }
       
   337 
       
   338     /**
       
   339      * Returns a dynamic invoker for a specified dynamic operation using the public lookup. Similar to
       
   340      * {@link #createDynamicInvoker(String, Class, Class...)} but with return and parameter types composed into a
       
   341      * method type in the signature. See the discussion of that method for details.
       
   342      * @param opDesc Dynalink dynamic operation descriptor.
       
   343      * @param type the method type for the operation
       
   344      * @return MethodHandle for invoking the operation.
       
   345      */
       
   346     public static MethodHandle createDynamicInvoker(final String opDesc, final MethodType type) {
       
   347         return bootstrap(MethodHandles.publicLookup(), opDesc, type, 0).dynamicInvoker();
       
   348     }
       
   349 
       
   350     /**
       
   351      * Binds a bean dynamic method (returned by invoking {@code dyn:getMethod} on an object linked with
       
   352      * {@code BeansLinker} to a receiver.
       
   353      * @param dynamicMethod the dynamic method to bind
       
   354      * @param boundThis the bound "this" value.
       
   355      * @return a bound dynamic method.
       
   356      */
       
   357     public static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
       
   358         return new BoundDynamicMethod(dynamicMethod, boundThis);
       
   359     }
       
   360 
       
   361     /**
       
   362      * Creates a super-adapter for an adapter, that is, an adapter to the adapter that allows invocation of superclass
       
   363      * methods on it.
       
   364      * @param adapter the original adapter
       
   365      * @return a new adapter that can be used to invoke super methods on the original adapter.
       
   366      */
       
   367     public static Object createSuperAdapter(final Object adapter) {
       
   368         return new JavaSuperAdapter(adapter);
       
   369     }
       
   370 
       
   371     /**
       
   372      * If the given class is a reflection-specific class (anything in {@code java.lang.reflect} and
       
   373      * {@code java.lang.invoke} package, as well a {@link Class} and any subclass of {@link ClassLoader}) and there is
       
   374      * a security manager in the system, then it checks the {@code nashorn.JavaReflection} {@code RuntimePermission}.
       
   375      * @param clazz the class being tested
       
   376      * @param isStatic is access checked for static members (or instance members)
       
   377      */
       
   378     public static void checkReflectionAccess(final Class<?> clazz, final boolean isStatic) {
       
   379         ReflectionCheckLinker.checkReflectionAccess(clazz, isStatic);
       
   380     }
       
   381 
       
   382     /**
       
   383      * Returns the Nashorn's internally used dynamic linker's services object. Note that in code that is processing a
       
   384      * linking request, you will normally use the {@code LinkerServices} object passed by whatever top-level linker
       
   385      * invoked the linking (if the call site is in Nashorn-generated code, you'll get this object anyway). You should
       
   386      * only resort to retrieving a linker services object using this method when you need some linker services (e.g.
       
   387      * type converter method handles) outside of a code path that is linking a call site.
       
   388      * @return Nashorn's internal dynamic linker's services object.
       
   389      */
       
   390     public static LinkerServices getLinkerServices() {
       
   391         return dynamicLinker.getLinkerServices();
       
   392     }
       
   393 
       
   394     /**
       
   395      * Takes a guarded invocation, and ensures its method and guard conform to the type of the call descriptor, using
       
   396      * all type conversions allowed by the linker's services. This method is used by Nashorn's linkers as a last step
       
   397      * before returning guarded invocations. Most of the code used to produce the guarded invocations does not make an
       
   398      * effort to coordinate types of the methods, and so a final type adjustment before a guarded invocation is returned
       
   399      * to the aggregating linker is the responsibility of the linkers themselves.
       
   400      * @param inv the guarded invocation that needs to be type-converted. Can be null.
       
   401      * @param linkerServices the linker services object providing the type conversions.
       
   402      * @param desc the call site descriptor to whose method type the invocation needs to conform.
       
   403      * @return the type-converted guarded invocation. If input is null, null is returned. If the input invocation
       
   404      * already conforms to the requested type, it is returned unchanged.
       
   405      */
       
   406     static GuardedInvocation asTypeSafeReturn(final GuardedInvocation inv, final LinkerServices linkerServices, final CallSiteDescriptor desc) {
       
   407         return inv == null ? null : inv.asTypeSafeReturn(linkerServices, desc.getMethodType());
       
   408     }
       
   409 }