< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java

Print this page




   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.nodes.graphbuilderconf;
  26 
  27 import static java.lang.String.format;


  28 import static org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.LateClassPlugins.CLOSED_LATE_CLASS_PLUGIN;
  29 
  30 import java.lang.reflect.Constructor;
  31 import java.lang.reflect.Method;
  32 import java.lang.reflect.Modifier;
  33 import java.lang.reflect.Type;
  34 import java.util.ArrayList;
  35 import java.util.Arrays;
  36 import java.util.Collections;
  37 import java.util.List;
  38 import java.util.Map;
  39 
  40 import jdk.internal.vm.compiler.collections.EconomicMap;
  41 import jdk.internal.vm.compiler.collections.Equivalence;
  42 import jdk.internal.vm.compiler.collections.MapCursor;
  43 import jdk.internal.vm.compiler.collections.Pair;
  44 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
  45 import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor;
  46 import org.graalvm.compiler.api.replacements.MethodSubstitution;
  47 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;


 127         public ResolvedJavaType getResolved() {
 128             return resolved;
 129         }
 130 
 131         @Override
 132         public String toString() {
 133             return resolved.toJavaName();
 134         }
 135     }
 136 
 137     /**
 138      * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}.
 139      */
 140     static class OptionalLazySymbol implements Type {
 141         private static final Class<?> MASK_NULL = OptionalLazySymbol.class;
 142         private final String name;
 143         private Class<?> resolved;
 144 
 145         OptionalLazySymbol(String name) {
 146             this.name = name;



 147         }
 148 
 149         @Override
 150         public String getTypeName() {
 151             return name;
 152         }
 153 
 154         /**
 155          * Gets the resolved {@link Class} corresponding to this symbol or {@code null} if
 156          * resolution fails.
 157          */
 158         public Class<?> resolve() {
 159             if (resolved == null) {
 160                 Class<?> resolvedOrNull = resolveClass(name, true);
 161                 resolved = resolvedOrNull == null ? MASK_NULL : resolvedOrNull;
 162             }
 163             return resolved == MASK_NULL ? null : resolved;
 164         }
 165 
 166         @Override
 167         public String toString() {
 168             return name;
 169         }
 170     }
 171 
 172     /**
 173      * Utility for {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
 174      * registration} of invocation plugins.
 175      */
 176     public static class Registration implements MethodSubstitutionRegistry {
 177 
 178         private final InvocationPlugins plugins;
 179         private final Type declaringType;


 205          *
 206          * @param plugins where to register the plugins
 207          * @param declaringType the class declaring the methods for which plugins will be registered
 208          *            via this object
 209          * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
 210          *            method substitutions
 211          */
 212         public Registration(InvocationPlugins plugins, Type declaringType, BytecodeProvider methodSubstitutionBytecodeProvider) {
 213             this.plugins = plugins;
 214             this.declaringType = declaringType;
 215             this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
 216         }
 217 
 218         /**
 219          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
 220          * given class.
 221          *
 222          * @param plugins where to register the plugins
 223          * @param declaringClassName the name of the class class declaring the methods for which
 224          *            plugins will be registered via this object














 225          * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
 226          *            method substitutions
 227          */
 228         public Registration(InvocationPlugins plugins, String declaringClassName, BytecodeProvider methodSubstitutionBytecodeProvider) {
 229             this.plugins = plugins;
 230             this.declaringType = new OptionalLazySymbol(declaringClassName);
 231             this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
 232         }
 233 
 234         /**
 235          * Configures this registration to allow or disallow overwriting of invocation plugins.
 236          */
 237         public Registration setAllowOverwrite(boolean allowOverwrite) {
 238             this.allowOverwrite = allowOverwrite;
 239             return this;
 240         }
 241 
 242         /**
 243          * Registers a plugin for a method with no arguments.
 244          *


 435         /**
 436          * Registers an invocation plugin for a given method. There must be no plugin currently
 437          * registered for {@code method}.
 438          *
 439          * @param argumentTypes the argument types of the method. Element 0 of this array must be
 440          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
 441          *            is non-static. Upon returning, element 0 will have been rewritten to
 442          *            {@code declaringClass}
 443          */
 444         public void register(InvocationPlugin plugin, String name, Type... argumentTypes) {
 445             assert plugins != null : String.format("Late registrations of invocation plugins for %s is already closed", declaringType);
 446             boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
 447             if (!isStatic) {
 448                 argumentTypes[0] = declaringType;
 449             }
 450 
 451             assert isStatic || argumentTypes[0] == declaringType;
 452             Binding binding = new Binding(plugin, isStatic, name, argumentTypes);
 453             bindings.add(binding);
 454 
 455             assert Checks.check(this.plugins, declaringType, binding);
 456             assert Checks.checkResolvable(false, declaringType, binding);
 457         }
 458 
 459         @Override
 460         public void close() {
 461             assert plugins != null : String.format("Late registrations of invocation plugins for %s is already closed", declaringType);
 462             plugins.registerLate(declaringType, bindings);
 463             plugins = null;
 464         }
 465     }
 466 
 467     /**
 468      * Associates an {@link InvocationPlugin} with the details of a method it substitutes.
 469      */
 470     public static class Binding {
 471         /**
 472          * The plugin this binding is for.
 473          */
 474         public final InvocationPlugin plugin;
 475 
 476         /**


 719 
 720     /**
 721      * Determines if methods in a given class can have invocation plugins.
 722      *
 723      * @param declaringClass the class to test
 724      */
 725     public boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
 726         return true;
 727     }
 728 
 729     LateClassPlugins findLateClassPlugins(String internalClassName) {
 730         for (LateClassPlugins lcp = lateRegistrations; lcp != null; lcp = lcp.next) {
 731             if (lcp.className.equals(internalClassName)) {
 732                 return lcp;
 733             }
 734         }
 735         return null;
 736     }
 737 
 738     @SuppressWarnings("serial")
 739     static class InvocationPlugRegistrationError extends GraalError {
 740         InvocationPlugRegistrationError(Throwable cause) {
 741             super(cause);
 742         }
 743     }
 744 
 745     private void flushDeferrables() {
 746         if (deferredRegistrations != null) {
 747             synchronized (this) {
 748                 if (deferredRegistrations != null) {
 749                     try {
 750                         for (Runnable deferrable : deferredRegistrations) {
 751                             deferrable.run();
 752                         }
 753                         deferredRegistrations = null;
 754                     } catch (InvocationPlugRegistrationError t) {
 755                         throw t;
 756                     } catch (Throwable t) {
 757                         /*
 758                          * Something went wrong during registration but it's possible we'll end up
 759                          * coming back into this code. nulling out deferredRegistrations would just
 760                          * cause other things to break and rerunning them would cause errors about
 761                          * already registered plugins, so rethrow the original exception during
 762                          * later invocations.
 763                          */
 764                         deferredRegistrations.clear();
 765                         Runnable rethrow = new Runnable() {
 766                             @Override
 767                             public void run() {
 768                                 throw new InvocationPlugRegistrationError(t);
 769                             }
 770                         };
 771                         deferredRegistrations.add(rethrow);
 772                         rethrow.run();
 773                     }
 774                 }
 775             }
 776         }
 777     }
 778 
 779     private volatile EconomicMap<String, List<Binding>> testExtensions;
 780 
 781     private static int findBinding(List<Binding> list, Binding key) {
 782         for (int i = 0; i < list.size(); i++) {
 783             Binding b = list.get(i);
 784             if (b.isStatic == key.isStatic && b.name.equals(key.name) && b.argumentsDescriptor.equals(key.argumentsDescriptor)) {
 785                 return i;
 786             }
 787         }
 788         return -1;


 943      * cannot have further plugins registered.
 944      */
 945     public InvocationPlugins(Map<ResolvedJavaMethod, InvocationPlugin> plugins, InvocationPlugins parent) {
 946         this.parent = parent;
 947         this.registrations = null;
 948         this.deferredRegistrations = null;
 949         EconomicMap<ResolvedJavaMethod, InvocationPlugin> map = EconomicMap.create(plugins.size());
 950 
 951         for (Map.Entry<ResolvedJavaMethod, InvocationPlugin> entry : plugins.entrySet()) {
 952             map.put(entry.getKey(), entry.getValue());
 953         }
 954         this.resolvedRegistrations = map;
 955     }
 956 
 957     protected void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
 958         boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
 959         if (!isStatic) {
 960             argumentTypes[0] = declaringClass;
 961         }
 962         Binding binding = put(plugin, isStatic, allowOverwrite, declaringClass, name, argumentTypes);
 963         assert Checks.check(this, declaringClass, binding);
 964         assert Checks.checkResolvable(isOptional, declaringClass, binding);
 965     }
 966 
 967     /**
 968      * Registers an invocation plugin for a given method. There must be no plugin currently
 969      * registered for {@code method}.
 970      *
 971      * @param argumentTypes the argument types of the method. Element 0 of this array must be the
 972      *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
 973      *            non-static. Upon returning, element 0 will have been rewritten to
 974      *            {@code declaringClass}
 975      */
 976     public final void register(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
 977         register(plugin, false, false, declaringClass, name, argumentTypes);
 978     }
 979 
 980     public final void register(InvocationPlugin plugin, String declaringClass, String name, Type... argumentTypes) {
 981         register(plugin, false, false, new OptionalLazySymbol(declaringClass), name, argumentTypes);
 982     }
 983 
 984     /**


 987      *
 988      * @param argumentTypes the argument types of the method. Element 0 of this array must be the
 989      *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
 990      *            non-static. Upon returning, element 0 will have been rewritten to
 991      *            {@code declaringClass}
 992      */
 993     public final void registerOptional(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
 994         register(plugin, true, false, declaringClass, name, argumentTypes);
 995     }
 996 
 997     /**
 998      * Gets the plugin for a given method.
 999      *
1000      * @param method the method to lookup
1001      * @return the plugin associated with {@code method} or {@code null} if none exists
1002      */
1003     public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
1004         if (parent != null) {
1005             InvocationPlugin plugin = parent.lookupInvocation(method);
1006             if (plugin != null) {




1007                 return plugin;
1008             }
1009         }
1010         return get(method);





1011     }
1012 
1013     /**
1014      * Gets the set of registered invocation plugins.
1015      *
1016      * @return a map from class names in {@linkplain MetaUtil#toInternalName(String) internal} form
1017      *         to the invocation plugin bindings for methods in the class
1018      */
1019     public EconomicMap<String, List<Binding>> getBindings(boolean includeParents) {
1020         return getBindings(includeParents, true);
1021     }
1022 
1023     /**
1024      * Gets the set of registered invocation plugins.
1025      *
1026      * @return a map from class names in {@linkplain MetaUtil#toInternalName(String) internal} form
1027      *         to the invocation plugin bindings for methods in the class
1028      */
1029     private EconomicMap<String, List<Binding>> getBindings(boolean includeParents, boolean flushDeferrables) {
1030         EconomicMap<String, List<Binding>> res = EconomicMap.create(Equivalence.DEFAULT);


1124         if (parent != null) {
1125             if (buf.length() != 0) {
1126                 buf.append(nl);
1127             }
1128             buf.append("// parent").append(nl).append(parent);
1129         }
1130         return buf.toString();
1131     }
1132 
1133     /**
1134      * Code only used in assertions. Putting this in a separate class reduces class load time.
1135      */
1136     private static class Checks {
1137         private static final int MAX_ARITY = 7;
1138         /**
1139          * The set of all {@link InvocationPlugin#apply} method signatures.
1140          */
1141         static final Class<?>[][] SIGS;
1142 
1143         static {
1144             if (!Assertions.assertionsEnabled()) {
1145                 throw new GraalError("%s must only be used in assertions", Checks.class.getName());
1146             }
1147             ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
1148             for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
1149                 if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
1150                     Class<?>[] sig = method.getParameterTypes();
1151                     assert sig[0] == GraphBuilderContext.class;
1152                     assert sig[1] == ResolvedJavaMethod.class;
1153                     assert sig[2] == InvocationPlugin.Receiver.class;
1154                     assert Arrays.asList(sig).subList(3, sig.length).stream().allMatch(c -> c == ValueNode.class);
1155                     while (sigs.size() < sig.length - 2) {
1156                         sigs.add(null);



1157                     }
1158                     sigs.set(sig.length - 3, sig);
1159                 }


1160             }
1161             assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
1162                             ValueNode.class.getSimpleName());
1163             SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
1164         }
1165 
1166         static boolean containsBinding(InvocationPlugins p, Type declaringType, Binding key) {
1167             String internalName = MetaUtil.toInternalName(declaringType.getTypeName());
1168             ClassPlugins classPlugins = p.registrations.get(internalName);
1169             return classPlugins != null && classPlugins.lookup(key) != null;
1170         }
1171 
1172         public static boolean check(InvocationPlugins plugins, Type declaringType, Binding binding) {
1173             InvocationPlugin plugin = binding.plugin;
1174             InvocationPlugins p = plugins.parent;
1175             while (p != null) {
1176                 assert !containsBinding(p, declaringType, binding) : "a plugin is already registered for " + binding;
1177                 p = p.parent;
1178             }
1179             if (plugin instanceof ForeignCallPlugin || plugin instanceof GeneratedInvocationPlugin) {
1180                 return true;
1181             }
1182             if (plugin instanceof MethodSubstitutionPlugin) {


1258             if (optional) {
1259                 return null;
1260             }
1261             throw new GraalError("Could not resolve type " + className);
1262         }
1263     }
1264 
1265     /**
1266      * Resolves a {@link Type} to a {@link Class}.
1267      *
1268      * @param type the type to resolve
1269      * @param optional if true, resolution failure returns null
1270      * @return the resolved class or null if resolution fails and {@code optional} is true
1271      */
1272     public static Class<?> resolveType(Type type, boolean optional) {
1273         if (type instanceof Class) {
1274             return (Class<?>) type;
1275         }
1276         if (type instanceof OptionalLazySymbol) {
1277             return ((OptionalLazySymbol) type).resolve();



1278         }
1279         return resolveClass(type.getTypeName(), optional);
1280     }
1281 
1282     private static List<String> toInternalTypeNames(Class<?>[] types) {
1283         String[] res = new String[types.length];
1284         for (int i = 0; i < types.length; i++) {
1285             res[i] = MetaUtil.toInternalName(types[i].getTypeName());
1286         }
1287         return Arrays.asList(res);
1288     }
1289 
1290     /**
1291      * Resolves a given binding to a method in a given class. If more than one method with the
1292      * parameter types matching {@code binding} is found and the return types of all the matching
1293      * methods form an inheritance chain, the one with the most specific type is returned; otherwise
1294      * {@link NoSuchMethodError} is thrown.
1295      *
1296      * @param declaringClass the class to search for a method matching {@code binding}
1297      * @return the method (if any) in {@code declaringClass} matching {@code binding}




   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.nodes.graphbuilderconf;
  26 
  27 import static java.lang.String.format;
  28 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
  29 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
  30 import static org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.LateClassPlugins.CLOSED_LATE_CLASS_PLUGIN;
  31 
  32 import java.lang.reflect.Constructor;
  33 import java.lang.reflect.Method;
  34 import java.lang.reflect.Modifier;
  35 import java.lang.reflect.Type;
  36 import java.util.ArrayList;
  37 import java.util.Arrays;
  38 import java.util.Collections;
  39 import java.util.List;
  40 import java.util.Map;
  41 
  42 import jdk.internal.vm.compiler.collections.EconomicMap;
  43 import jdk.internal.vm.compiler.collections.Equivalence;
  44 import jdk.internal.vm.compiler.collections.MapCursor;
  45 import jdk.internal.vm.compiler.collections.Pair;
  46 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
  47 import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor;
  48 import org.graalvm.compiler.api.replacements.MethodSubstitution;
  49 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;


 129         public ResolvedJavaType getResolved() {
 130             return resolved;
 131         }
 132 
 133         @Override
 134         public String toString() {
 135             return resolved.toJavaName();
 136         }
 137     }
 138 
 139     /**
 140      * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}.
 141      */
 142     static class OptionalLazySymbol implements Type {
 143         private static final Class<?> MASK_NULL = OptionalLazySymbol.class;
 144         private final String name;
 145         private Class<?> resolved;
 146 
 147         OptionalLazySymbol(String name) {
 148             this.name = name;
 149             if (IS_BUILDING_NATIVE_IMAGE) {
 150                 resolve();
 151             }
 152         }
 153 
 154         @Override
 155         public String getTypeName() {
 156             return name;
 157         }
 158 
 159         /**
 160          * Gets the resolved {@link Class} corresponding to this symbol or {@code null} if
 161          * resolution fails.
 162          */
 163         public Class<?> resolve() {
 164             if (!IS_IN_NATIVE_IMAGE && resolved == null) {
 165                 Class<?> resolvedOrNull = resolveClass(name, true);
 166                 resolved = resolvedOrNull == null ? MASK_NULL : resolvedOrNull;
 167             }
 168             return resolved == MASK_NULL ? null : resolved;
 169         }
 170 
 171         @Override
 172         public String toString() {
 173             return name;
 174         }
 175     }
 176 
 177     /**
 178      * Utility for {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
 179      * registration} of invocation plugins.
 180      */
 181     public static class Registration implements MethodSubstitutionRegistry {
 182 
 183         private final InvocationPlugins plugins;
 184         private final Type declaringType;


 210          *
 211          * @param plugins where to register the plugins
 212          * @param declaringType the class declaring the methods for which plugins will be registered
 213          *            via this object
 214          * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
 215          *            method substitutions
 216          */
 217         public Registration(InvocationPlugins plugins, Type declaringType, BytecodeProvider methodSubstitutionBytecodeProvider) {
 218             this.plugins = plugins;
 219             this.declaringType = declaringType;
 220             this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
 221         }
 222 
 223         /**
 224          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
 225          * given class.
 226          *
 227          * @param plugins where to register the plugins
 228          * @param declaringClassName the name of the class class declaring the methods for which
 229          *            plugins will be registered via this object
 230          */
 231         public Registration(InvocationPlugins plugins, String declaringClassName) {
 232             this.plugins = plugins;
 233             this.declaringType = new OptionalLazySymbol(declaringClassName);
 234             this.methodSubstitutionBytecodeProvider = null;
 235         }
 236 
 237         /**
 238          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
 239          * given class.
 240          *
 241          * @param plugins where to register the plugins
 242          * @param declaringClassName the name of the class class declaring the methods for which
 243          *            plugins will be registered via this object
 244          * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
 245          *            method substitutions
 246          */
 247         public Registration(InvocationPlugins plugins, String declaringClassName, BytecodeProvider methodSubstitutionBytecodeProvider) {
 248             this.plugins = plugins;
 249             this.declaringType = new OptionalLazySymbol(declaringClassName);
 250             this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
 251         }
 252 
 253         /**
 254          * Configures this registration to allow or disallow overwriting of invocation plugins.
 255          */
 256         public Registration setAllowOverwrite(boolean allowOverwrite) {
 257             this.allowOverwrite = allowOverwrite;
 258             return this;
 259         }
 260 
 261         /**
 262          * Registers a plugin for a method with no arguments.
 263          *


 454         /**
 455          * Registers an invocation plugin for a given method. There must be no plugin currently
 456          * registered for {@code method}.
 457          *
 458          * @param argumentTypes the argument types of the method. Element 0 of this array must be
 459          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
 460          *            is non-static. Upon returning, element 0 will have been rewritten to
 461          *            {@code declaringClass}
 462          */
 463         public void register(InvocationPlugin plugin, String name, Type... argumentTypes) {
 464             assert plugins != null : String.format("Late registrations of invocation plugins for %s is already closed", declaringType);
 465             boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
 466             if (!isStatic) {
 467                 argumentTypes[0] = declaringType;
 468             }
 469 
 470             assert isStatic || argumentTypes[0] == declaringType;
 471             Binding binding = new Binding(plugin, isStatic, name, argumentTypes);
 472             bindings.add(binding);
 473 
 474             assert IS_IN_NATIVE_IMAGE || Checks.check(this.plugins, declaringType, binding);
 475             assert IS_IN_NATIVE_IMAGE || Checks.checkResolvable(false, declaringType, binding);
 476         }
 477 
 478         @Override
 479         public void close() {
 480             assert plugins != null : String.format("Late registrations of invocation plugins for %s is already closed", declaringType);
 481             plugins.registerLate(declaringType, bindings);
 482             plugins = null;
 483         }
 484     }
 485 
 486     /**
 487      * Associates an {@link InvocationPlugin} with the details of a method it substitutes.
 488      */
 489     public static class Binding {
 490         /**
 491          * The plugin this binding is for.
 492          */
 493         public final InvocationPlugin plugin;
 494 
 495         /**


 738 
 739     /**
 740      * Determines if methods in a given class can have invocation plugins.
 741      *
 742      * @param declaringClass the class to test
 743      */
 744     public boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
 745         return true;
 746     }
 747 
 748     LateClassPlugins findLateClassPlugins(String internalClassName) {
 749         for (LateClassPlugins lcp = lateRegistrations; lcp != null; lcp = lcp.next) {
 750             if (lcp.className.equals(internalClassName)) {
 751                 return lcp;
 752             }
 753         }
 754         return null;
 755     }
 756 
 757     @SuppressWarnings("serial")
 758     static class InvocationPluginRegistrationError extends GraalError {
 759         InvocationPluginRegistrationError(Throwable cause) {
 760             super(cause);
 761         }
 762     }
 763 
 764     private void flushDeferrables() {
 765         if (deferredRegistrations != null) {
 766             synchronized (this) {
 767                 if (deferredRegistrations != null) {
 768                     try {
 769                         for (Runnable deferrable : deferredRegistrations) {
 770                             deferrable.run();
 771                         }
 772                         deferredRegistrations = null;
 773                     } catch (InvocationPluginRegistrationError t) {
 774                         throw t;
 775                     } catch (Throwable t) {
 776                         /*
 777                          * Something went wrong during registration but it's possible we'll end up
 778                          * coming back into this code. nulling out deferredRegistrations would just
 779                          * cause other things to break and rerunning them would cause errors about
 780                          * already registered plugins, so rethrow the original exception during
 781                          * later invocations.
 782                          */
 783                         deferredRegistrations.clear();
 784                         Runnable rethrow = new Runnable() {
 785                             @Override
 786                             public void run() {
 787                                 throw new InvocationPluginRegistrationError(t);
 788                             }
 789                         };
 790                         deferredRegistrations.add(rethrow);
 791                         rethrow.run();
 792                     }
 793                 }
 794             }
 795         }
 796     }
 797 
 798     private volatile EconomicMap<String, List<Binding>> testExtensions;
 799 
 800     private static int findBinding(List<Binding> list, Binding key) {
 801         for (int i = 0; i < list.size(); i++) {
 802             Binding b = list.get(i);
 803             if (b.isStatic == key.isStatic && b.name.equals(key.name) && b.argumentsDescriptor.equals(key.argumentsDescriptor)) {
 804                 return i;
 805             }
 806         }
 807         return -1;


 962      * cannot have further plugins registered.
 963      */
 964     public InvocationPlugins(Map<ResolvedJavaMethod, InvocationPlugin> plugins, InvocationPlugins parent) {
 965         this.parent = parent;
 966         this.registrations = null;
 967         this.deferredRegistrations = null;
 968         EconomicMap<ResolvedJavaMethod, InvocationPlugin> map = EconomicMap.create(plugins.size());
 969 
 970         for (Map.Entry<ResolvedJavaMethod, InvocationPlugin> entry : plugins.entrySet()) {
 971             map.put(entry.getKey(), entry.getValue());
 972         }
 973         this.resolvedRegistrations = map;
 974     }
 975 
 976     protected void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
 977         boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
 978         if (!isStatic) {
 979             argumentTypes[0] = declaringClass;
 980         }
 981         Binding binding = put(plugin, isStatic, allowOverwrite, declaringClass, name, argumentTypes);
 982         assert IS_IN_NATIVE_IMAGE || Checks.check(this, declaringClass, binding);
 983         assert IS_IN_NATIVE_IMAGE || Checks.checkResolvable(isOptional, declaringClass, binding);
 984     }
 985 
 986     /**
 987      * Registers an invocation plugin for a given method. There must be no plugin currently
 988      * registered for {@code method}.
 989      *
 990      * @param argumentTypes the argument types of the method. Element 0 of this array must be the
 991      *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
 992      *            non-static. Upon returning, element 0 will have been rewritten to
 993      *            {@code declaringClass}
 994      */
 995     public final void register(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
 996         register(plugin, false, false, declaringClass, name, argumentTypes);
 997     }
 998 
 999     public final void register(InvocationPlugin plugin, String declaringClass, String name, Type... argumentTypes) {
1000         register(plugin, false, false, new OptionalLazySymbol(declaringClass), name, argumentTypes);
1001     }
1002 
1003     /**


1006      *
1007      * @param argumentTypes the argument types of the method. Element 0 of this array must be the
1008      *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
1009      *            non-static. Upon returning, element 0 will have been rewritten to
1010      *            {@code declaringClass}
1011      */
1012     public final void registerOptional(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
1013         register(plugin, true, false, declaringClass, name, argumentTypes);
1014     }
1015 
1016     /**
1017      * Gets the plugin for a given method.
1018      *
1019      * @param method the method to lookup
1020      * @return the plugin associated with {@code method} or {@code null} if none exists
1021      */
1022     public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
1023         if (parent != null) {
1024             InvocationPlugin plugin = parent.lookupInvocation(method);
1025             if (plugin != null) {
1026                 if (IS_IN_NATIVE_IMAGE && plugin instanceof MethodSubstitutionPlugin) {
1027                     // Disable method substitutions until GR-13607
1028                     return null;
1029                 }
1030                 return plugin;
1031             }
1032         }
1033         InvocationPlugin invocationPlugin = get(method);
1034         if (IS_IN_NATIVE_IMAGE && invocationPlugin instanceof MethodSubstitutionPlugin) {
1035             // Disable method substitutions until GR-13607
1036             return null;
1037         }
1038         return invocationPlugin;
1039     }
1040 
1041     /**
1042      * Gets the set of registered invocation plugins.
1043      *
1044      * @return a map from class names in {@linkplain MetaUtil#toInternalName(String) internal} form
1045      *         to the invocation plugin bindings for methods in the class
1046      */
1047     public EconomicMap<String, List<Binding>> getBindings(boolean includeParents) {
1048         return getBindings(includeParents, true);
1049     }
1050 
1051     /**
1052      * Gets the set of registered invocation plugins.
1053      *
1054      * @return a map from class names in {@linkplain MetaUtil#toInternalName(String) internal} form
1055      *         to the invocation plugin bindings for methods in the class
1056      */
1057     private EconomicMap<String, List<Binding>> getBindings(boolean includeParents, boolean flushDeferrables) {
1058         EconomicMap<String, List<Binding>> res = EconomicMap.create(Equivalence.DEFAULT);


1152         if (parent != null) {
1153             if (buf.length() != 0) {
1154                 buf.append(nl);
1155             }
1156             buf.append("// parent").append(nl).append(parent);
1157         }
1158         return buf.toString();
1159     }
1160 
1161     /**
1162      * Code only used in assertions. Putting this in a separate class reduces class load time.
1163      */
1164     private static class Checks {
1165         private static final int MAX_ARITY = 7;
1166         /**
1167          * The set of all {@link InvocationPlugin#apply} method signatures.
1168          */
1169         static final Class<?>[][] SIGS;
1170 
1171         static {
1172             if (!Assertions.assertionsEnabled() && !IS_BUILDING_NATIVE_IMAGE) {
1173                 throw new GraalError("%s must only be used in assertions", Checks.class.getName());
1174             }
1175             ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
1176             if (!IS_IN_NATIVE_IMAGE) {
1177                 for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
1178                     if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
1179                         Class<?>[] sig = method.getParameterTypes();
1180                         assert sig[0] == GraphBuilderContext.class;
1181                         assert sig[1] == ResolvedJavaMethod.class;
1182                         assert sig[2] == InvocationPlugin.Receiver.class;
1183                         assert Arrays.asList(sig).subList(3, sig.length).stream().allMatch(c -> c == ValueNode.class);
1184                         while (sigs.size() < sig.length - 2) {
1185                             sigs.add(null);
1186                         }
1187                         sigs.set(sig.length - 3, sig);
1188                     }

1189                 }
1190                 assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
1191                                 ValueNode.class.getSimpleName());
1192             }


1193             SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
1194         }
1195 
1196         static boolean containsBinding(InvocationPlugins p, Type declaringType, Binding key) {
1197             String internalName = MetaUtil.toInternalName(declaringType.getTypeName());
1198             ClassPlugins classPlugins = p.registrations.get(internalName);
1199             return classPlugins != null && classPlugins.lookup(key) != null;
1200         }
1201 
1202         public static boolean check(InvocationPlugins plugins, Type declaringType, Binding binding) {
1203             InvocationPlugin plugin = binding.plugin;
1204             InvocationPlugins p = plugins.parent;
1205             while (p != null) {
1206                 assert !containsBinding(p, declaringType, binding) : "a plugin is already registered for " + binding;
1207                 p = p.parent;
1208             }
1209             if (plugin instanceof ForeignCallPlugin || plugin instanceof GeneratedInvocationPlugin) {
1210                 return true;
1211             }
1212             if (plugin instanceof MethodSubstitutionPlugin) {


1288             if (optional) {
1289                 return null;
1290             }
1291             throw new GraalError("Could not resolve type " + className);
1292         }
1293     }
1294 
1295     /**
1296      * Resolves a {@link Type} to a {@link Class}.
1297      *
1298      * @param type the type to resolve
1299      * @param optional if true, resolution failure returns null
1300      * @return the resolved class or null if resolution fails and {@code optional} is true
1301      */
1302     public static Class<?> resolveType(Type type, boolean optional) {
1303         if (type instanceof Class) {
1304             return (Class<?>) type;
1305         }
1306         if (type instanceof OptionalLazySymbol) {
1307             return ((OptionalLazySymbol) type).resolve();
1308         }
1309         if (IS_IN_NATIVE_IMAGE) {
1310             throw new GraalError("Unresolved type in native image image:" + type.getTypeName());
1311         }
1312         return resolveClass(type.getTypeName(), optional);
1313     }
1314 
1315     private static List<String> toInternalTypeNames(Class<?>[] types) {
1316         String[] res = new String[types.length];
1317         for (int i = 0; i < types.length; i++) {
1318             res[i] = MetaUtil.toInternalName(types[i].getTypeName());
1319         }
1320         return Arrays.asList(res);
1321     }
1322 
1323     /**
1324      * Resolves a given binding to a method in a given class. If more than one method with the
1325      * parameter types matching {@code binding} is found and the return types of all the matching
1326      * methods form an inheritance chain, the one with the most specific type is returned; otherwise
1327      * {@link NoSuchMethodError} is thrown.
1328      *
1329      * @param declaringClass the class to search for a method matching {@code binding}
1330      * @return the method (if any) in {@code declaringClass} matching {@code binding}


< prev index next >