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 java.lang.invoke.MethodHandle; 29 30 /** 31 * A tuple of method handles, one for dynamically getting function as a property of an object, and another for invoking 32 * a function with a given signature. A typical use for this class is to create method handles that can be used to 33 * efficiently recreate dynamic invocation of a method on an object from Java code. E.g. if you would have a call site 34 * in JavaScript that says 35 * <pre> 36 * value = obj.toJSON(key) 37 * </pre> 38 * then the efficient way to code an exact equivalent of this in Java would be: 39 * <pre> 40 * private static final InvokeByName TO_JSON = new InvokeByName("toJSON", Object.class, Object.class, Object.class); 41 * ... 42 * final Object toJSONFn = TO_JSON.getGetter().invokeExact(obj); 43 * value = TO_JSON.getInvoker().invokeExact(toJSONFn, obj, key); 44 * </pre> 45 * In practice, you can have stronger type assumptions if it makes sense for your code, just remember that you must use 46 * the same parameter types as the formal types of the arguments for {@code invokeExact} to work: 47 * <pre> 48 * private static final InvokeByName TO_JSON = new InvokeByName("toJSON", ScriptObject.class, Object.class, Object.class); 49 * ... 50 * final ScriptObject sobj = (ScriptObject)obj; 51 * final Object toJSONFn = TO_JSON.getGetter().invokeExact(sobj); 52 * if(toJSONFn instanceof ScriptFunction) { 53 * value = TO_JSON.getInvoker().invokeExact(toJSONFn, sobj, key); 54 * } 55 * </pre> 56 * Note that in general you will not want to reuse a single instance of this class for implementing more than one call 57 * site - that would increase the risk of them becoming megamorphic or otherwise hard to optimize by the JVM. Even if 58 * you dynamically invoke a function with the same name from multiple places in your code, it is advisable to create a 59 * separate instance of this class for every place. 60 */ 61 public final class InvokeByName { 62 private final String name; 63 private final MethodHandle getter; 64 private final MethodHandle invoker; 65 66 /** 67 * Creates a getter and invoker for a function of the given name that takes no arguments and has a return type of 68 * {@code Object}. 69 * @param name the name of the function 70 * @param targetClass the target class it is invoked on; e.g. {@code Object} or {@code ScriptObject}. 71 */ 72 public InvokeByName(final String name, final Class<?> targetClass) { 73 this(name, targetClass, Object.class); 74 } 75 76 /** 77 * Creates a getter and invoker for a function of the given name with given parameter types and a given return type 78 * of {@code Object}. 79 * @param name the name of the function 80 * @param targetClass the target class it is invoked on; e.g. {@code Object} or {@code ScriptObject}. 81 * @param rtype the return type of the function 82 * @param ptypes the parameter types of the function. 83 */ 84 public InvokeByName(final String name, final Class<?> targetClass, final Class<?> rtype, final Class<?>... ptypes) { 85 this.name = name; 86 getter = Bootstrap.createDynamicInvoker(name, NashornCallSiteDescriptor.GET_METHOD_PROPERTY, Object.class, targetClass); 87 88 final Class<?>[] finalPtypes; 89 final int plength = ptypes.length; 90 if(plength == 0) { 91 finalPtypes = new Class<?>[] { Object.class, targetClass }; 92 } else { 93 finalPtypes = new Class<?>[plength + 2]; 94 finalPtypes[0] = Object.class; 95 finalPtypes[1] = targetClass; 96 System.arraycopy(ptypes, 0, finalPtypes, 2, plength); 97 } 98 invoker = Bootstrap.createDynamicCallInvoker(rtype, finalPtypes); 99 } 100 101 /** 102 * Returns the name of the function retrieved through this invoker. 103 * @return the name of the function retrieved through this invoker. 104 */ 105 public String getName() { 106 return name; 107 } 108 109 /** 110 * Returns the property getter that can be invoked on an object to retrieve the function object that will be 111 * subsequently invoked by the invoker returned by {@link #getInvoker()}. 112 * @return the property getter method handle for the function. 113 */ 114 public MethodHandle getGetter() { 115 return getter; 116 } 117 118 /** 119 * Returns the function invoker that can be used to invoke a function object previously retrieved by invoking 120 * the getter retrieved with {@link #getGetter()} on the target object. 121 * @return the invoker method handle for the function. 122 */ 123 public MethodHandle getInvoker() { 124 return invoker; 125 } 126 }