src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File hotspot Sdiff src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf

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

Print this page




  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 package org.graalvm.compiler.nodes.graphbuilderconf;
  24 
  25 import static java.lang.String.format;
  26 
  27 import java.lang.reflect.Executable;
  28 import java.lang.reflect.Method;
  29 import java.lang.reflect.Modifier;
  30 import java.lang.reflect.Type;
  31 import java.util.ArrayList;
  32 import java.util.Arrays;
  33 import java.util.Collections;
  34 import java.util.HashMap;
  35 import java.util.HashSet;
  36 import java.util.List;
  37 import java.util.Map;
  38 import java.util.Set;
  39 
  40 import org.graalvm.compiler.api.replacements.MethodSubstitution;
  41 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
  42 import org.graalvm.compiler.bytecode.BytecodeProvider;
  43 import org.graalvm.compiler.debug.GraalError;
  44 import org.graalvm.compiler.graph.Node;
  45 import org.graalvm.compiler.graph.iterators.NodeIterable;
  46 import org.graalvm.compiler.nodes.ValueNode;
  47 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;




  48 
  49 import jdk.vm.ci.meta.MetaAccessProvider;
  50 import jdk.vm.ci.meta.MetaUtil;
  51 import jdk.vm.ci.meta.ResolvedJavaMethod;
  52 
  53 /**
  54  * Manages a set of {@link InvocationPlugin}s.
  55  */
  56 public class InvocationPlugins {
  57 
  58     public static class InvocationPluginReceiver implements InvocationPlugin.Receiver {
  59         private final GraphBuilderContext parser;
  60         private ValueNode[] args;
  61         private ValueNode value;
  62 
  63         public InvocationPluginReceiver(GraphBuilderContext parser) {
  64             this.parser = parser;
  65         }
  66 
  67         @Override


 243          * Registers a plugin for a method with 4 arguments.
 244          *
 245          * @param name the name of the method
 246          * @param plugin the plugin to be registered
 247          */
 248         public void register4(String name, Type arg1, Type arg2, Type arg3, Type arg4, InvocationPlugin plugin) {
 249             plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4);
 250         }
 251 
 252         /**
 253          * Registers a plugin for a method with 5 arguments.
 254          *
 255          * @param name the name of the method
 256          * @param plugin the plugin to be registered
 257          */
 258         public void register5(String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, InvocationPlugin plugin) {
 259             plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5);
 260         }
 261 
 262         /**




















 263          * Registers a plugin for an optional method with no arguments.
 264          *
 265          * @param name the name of the method
 266          * @param plugin the plugin to be registered
 267          */
 268         public void registerOptional0(String name, InvocationPlugin plugin) {
 269             plugins.register(plugin, true, allowOverwrite, declaringType, name);
 270         }
 271 
 272         /**
 273          * Registers a plugin for an optional method with 1 argument.
 274          *
 275          * @param name the name of the method
 276          * @param plugin the plugin to be registered
 277          */
 278         public void registerOptional1(String name, Type arg, InvocationPlugin plugin) {
 279             plugins.register(plugin, true, allowOverwrite, declaringType, name, arg);
 280         }
 281 
 282         /**


 320          *            {@code declaringClass}
 321          */
 322         @Override
 323         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
 324             registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
 325         }
 326 
 327         /**
 328          * Registers a plugin that implements a method based on the bytecode of a substitute method.
 329          *
 330          * @param substituteDeclaringClass the class declaring the substitute method
 331          * @param name the name of both the original method
 332          * @param substituteName the name of the substitute method
 333          * @param argumentTypes the argument types of the method. Element 0 of this array must be
 334          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
 335          *            is non-static. Upon returning, element 0 will have been rewritten to
 336          *            {@code declaringClass}
 337          */
 338         @Override
 339         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {





 340             assert methodSubstitutionBytecodeProvider != null : "Registration used for method substitutions requires a non-null methodSubstitutionBytecodeProvider";
 341             MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(methodSubstitutionBytecodeProvider, substituteDeclaringClass, substituteName, argumentTypes);
 342             plugins.register(plugin, false, allowOverwrite, declaringType, name, argumentTypes);
 343         }

 344     }
 345 
 346     /**
 347      * Key for a {@linkplain ClassPlugins#entries resolved} plugin registration. Due to the
 348      * possibility of class redefinition, we cannot directly use {@link ResolvedJavaMethod}s as
 349      * keys. A {@link ResolvedJavaMethod} implementation might implement {@code equals()} and
 350      * {@code hashCode()} based on internal representation subject to change by class redefinition.
 351      */
 352     static final class ResolvedJavaMethodKey {
 353         private final ResolvedJavaMethod method;
 354 
 355         ResolvedJavaMethodKey(ResolvedJavaMethod method) {
 356             this.method = method;
 357         }
 358 
 359         @Override
 360         public boolean equals(Object obj) {
 361             if (obj instanceof ResolvedJavaMethodKey) {
 362                 ResolvedJavaMethodKey that = (ResolvedJavaMethodKey) obj;
 363                 if (this.method.isStatic() == that.method.isStatic()) {


 477                 }
 478                 throw new InternalError(e);
 479             }
 480         }
 481 
 482         @Override
 483         public String toString() {
 484             StringBuilder sb = new StringBuilder(name).append('(');
 485             for (Type p : argumentTypes) {
 486                 if (sb.charAt(sb.length() - 1) != '(') {
 487                     sb.append(", ");
 488                 }
 489                 sb.append(p.getTypeName());
 490             }
 491             return sb.append(')').toString();
 492         }
 493     }
 494 
 495     private final MetaAccessProvider metaAccess;
 496 
 497     private final Map<String, ClassPlugins> registrations = new HashMap<>();
 498 
 499     /**
 500      * Deferred registrations as well as guard for initialization. The guard uses double-checked
 501      * locking which is why this field is {@code volatile}.
 502      */
 503     private volatile List<Runnable> deferredRegistrations = new ArrayList<>();
 504 
 505     /**
 506      * Adds a {@link Runnable} for doing registration deferred until the first time
 507      * {@link #get(ResolvedJavaMethod)} or {@link #closeRegistration()} is called on this object.
 508      */
 509     public void defer(Runnable deferrable) {
 510         assert deferredRegistrations != null : "registration is closed";
 511         deferredRegistrations.add(deferrable);
 512     }
 513 
 514     /**
 515      * Per-class invocation plugins.
 516      */
 517     protected static class ClassPlugins {
 518         private final Type declaringType;
 519 
 520         private final List<MethodKey> registrations = new ArrayList<>();
 521 
 522         public ClassPlugins(Type declaringClass) {
 523             this.declaringType = declaringClass;
 524         }
 525 
 526         /**
 527          * Entry map that is initialized upon first call to {@link #get(ResolvedJavaMethod)}.
 528          *
 529          * Note: this must be volatile as threads may race to initialize it.
 530          */
 531         private volatile Map<ResolvedJavaMethodKey, InvocationPlugin> entries;
 532 
 533         void initializeMap() {
 534             if (!isClosed()) {
 535                 if (registrations.isEmpty()) {
 536                     entries = Collections.emptyMap();
 537                 } else {
 538                     Class<?> declaringClass = resolveType(declaringType, true);
 539                     if (declaringClass == null) {
 540                         // An optional type that could not be resolved
 541                         entries = Collections.emptyMap();
 542                     } else {
 543                         Map<ResolvedJavaMethodKey, InvocationPlugin> newEntries = new HashMap<>();
 544                         for (MethodKey methodKey : registrations) {
 545                             ResolvedJavaMethod m = methodKey.resolve(declaringClass);
 546                             if (m != null) {
 547                                 newEntries.put(new ResolvedJavaMethodKey(m), methodKey.value);
 548                                 if (entries != null) {
 549                                     // Another thread finished initializing entries first
 550                                     return;
 551                                 }
 552                             }
 553                         }
 554                         entries = newEntries;
 555                     }
 556                 }
 557             }
 558         }
 559 
 560         public InvocationPlugin get(ResolvedJavaMethod method) {
 561             if (!isClosed()) {
 562                 initializeMap();
 563             }
 564             return entries.get(new ResolvedJavaMethodKey(method));
 565         }
 566 
 567         public void register(MethodKey methodKey, boolean allowOverwrite) {
 568             assert !isClosed() : "registration is closed: " + methodKey + " " + Arrays.toString(entries.keySet().toArray());
 569             if (allowOverwrite) {
 570                 int index = registrations.indexOf(methodKey);
 571                 if (index >= 0) {
 572                     registrations.set(index, methodKey);
 573                     return;
 574                 }
 575             } else {
 576                 assert !registrations.contains(methodKey) : "a value is already registered for " + declaringType + "." + methodKey;
 577             }
 578             registrations.add(methodKey);
 579         }
 580 
 581         public boolean isClosed() {
 582             return entries != null;
 583         }
 584     }
 585 
 586     /**
 587      * Adds an entry to this map for a specified method.
 588      *


 622     InvocationPlugin get(ResolvedJavaMethod method) {
 623         flushDeferrables();
 624         String internalName = method.getDeclaringClass().getName();
 625         ClassPlugins classPlugins = registrations.get(internalName);
 626         if (classPlugins != null) {
 627             return classPlugins.get(method);
 628         }
 629         return null;
 630     }
 631 
 632     private void flushDeferrables() {
 633         if (deferredRegistrations != null) {
 634             synchronized (this) {
 635                 if (deferredRegistrations != null) {
 636                     for (Runnable deferrable : deferredRegistrations) {
 637                         deferrable.run();
 638                     }
 639                     deferredRegistrations = null;
 640                 }
 641             }
 642             for (Map.Entry<String, ClassPlugins> e : registrations.entrySet()) {
 643                 e.getValue().initializeMap();
 644             }
 645         }
 646     }
 647 
 648     /**
 649      * Disallows new registrations of new plugins, and creates the internal tables for method
 650      * lookup.
 651      */
 652     public void closeRegistration() {
 653         flushDeferrables();
 654         for (Map.Entry<String, ClassPlugins> e : registrations.entrySet()) {
 655             e.getValue().initializeMap();
 656         }
 657     }
 658 
 659     public int size() {
 660         return registrations.size();
 661     }
 662 
 663     /**
 664      * The plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} before searching in
 665      * this object.
 666      */
 667     protected final InvocationPlugins parent;
 668 
 669     private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess) {
 670         this.metaAccess = metaAccess;
 671         InvocationPlugins p = parent;
 672         this.parent = p;
 673     }
 674 
 675     /**


 677      */
 678     public InvocationPlugins(InvocationPlugins parent) {
 679         this(parent, parent.getMetaAccess());
 680     }
 681 
 682     public InvocationPlugins(Map<ResolvedJavaMethod, InvocationPlugin> plugins, InvocationPlugins parent, MetaAccessProvider metaAccess) {
 683         this.metaAccess = metaAccess;
 684         this.parent = parent;
 685 
 686         this.deferredRegistrations = null;
 687 
 688         for (Map.Entry<ResolvedJavaMethod, InvocationPlugin> entry : plugins.entrySet()) {
 689             ResolvedJavaMethod method = entry.getKey();
 690             InvocationPlugin plugin = entry.getValue();
 691 
 692             String internalName = method.getDeclaringClass().getName();
 693             ClassPlugins classPlugins = registrations.get(internalName);
 694             if (classPlugins == null) {
 695                 classPlugins = new ClassPlugins(null);
 696                 registrations.put(internalName, classPlugins);
 697                 classPlugins.entries = new HashMap<>();
 698             }
 699 
 700             classPlugins.entries.put(new ResolvedJavaMethodKey(method), plugin);
 701         }
 702     }
 703 
 704     public MetaAccessProvider getMetaAccess() {
 705         return metaAccess;
 706     }
 707 
 708     public InvocationPlugins(MetaAccessProvider metaAccess) {
 709         this(null, metaAccess);
 710     }
 711 
 712     protected void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
 713         boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
 714         if (!isStatic) {
 715             argumentTypes[0] = declaringClass;
 716         }
 717         MethodKey methodKey = put(plugin, isStatic, isOptional, allowOverwrite, declaringClass, name, argumentTypes);


 751     /**
 752      * Gets the plugin for a given method.
 753      *
 754      * @param method the method to lookup
 755      * @return the plugin associated with {@code method} or {@code null} if none exists
 756      */
 757     public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
 758         if (parent != null) {
 759             InvocationPlugin plugin = parent.lookupInvocation(method);
 760             if (plugin != null) {
 761                 return plugin;
 762             }
 763         }
 764         return get(method);
 765     }
 766 
 767     /**
 768      * Gets the set of methods for which invocation plugins have been registered. Once this method
 769      * is called, no further registrations can be made.
 770      */
 771     public Set<ResolvedJavaMethod> getMethods() {
 772         Set<ResolvedJavaMethod> res = new HashSet<>();
 773         if (parent != null) {
 774             res.addAll(parent.getMethods());
 775         }
 776         flushDeferrables();
 777         for (ClassPlugins cp : registrations.values()) {
 778             for (ResolvedJavaMethodKey key : cp.entries.keySet()) {
 779                 res.add(key.method);
 780             }
 781         }
 782         return res;
 783     }
 784 
 785     /**
 786      * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
 787      * before searching in this object.
 788      */
 789     public InvocationPlugins getParent() {
 790         return parent;
 791     }
 792 
 793     @Override
 794     public String toString() {
 795         StringBuilder buf = new StringBuilder();
 796         registrations.forEach((name, cp) -> buf.append(name).append('.').append(cp).append(", "));




 797         String s = buf.toString();
 798         if (buf.length() != 0) {
 799             s = s.substring(buf.length() - ", ".length());
 800         }
 801         return s + " / parent: " + this.parent;
 802     }
 803 
 804     private static class Checker {
 805         private static final int MAX_ARITY = 5;
 806         /**
 807          * The set of all {@link InvocationPlugin#apply} method signatures.
 808          */
 809         static final Class<?>[][] SIGS;
 810 
 811         static {
 812             ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
 813             for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
 814                 if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
 815                     Class<?>[] sig = method.getParameterTypes();
 816                     assert sig[0] == GraphBuilderContext.class;
 817                     assert sig[1] == ResolvedJavaMethod.class;
 818                     assert sig[2] == InvocationPlugin.Receiver.class;
 819                     assert Arrays.asList(sig).subList(3, sig.length).stream().allMatch(c -> c == ValueNode.class);
 820                     while (sigs.size() < sig.length - 2) {
 821                         sigs.add(null);
 822                     }
 823                     sigs.set(sig.length - 3, sig);
 824                 }
 825             }




  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 package org.graalvm.compiler.nodes.graphbuilderconf;
  24 
  25 import static java.lang.String.format;
  26 
  27 import java.lang.reflect.Executable;
  28 import java.lang.reflect.Method;
  29 import java.lang.reflect.Modifier;
  30 import java.lang.reflect.Type;
  31 import java.util.ArrayList;
  32 import java.util.Arrays;



  33 import java.util.List;
  34 import java.util.Map;


  35 import org.graalvm.compiler.api.replacements.MethodSubstitution;
  36 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
  37 import org.graalvm.compiler.bytecode.BytecodeProvider;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.graph.Node;
  40 import org.graalvm.compiler.graph.iterators.NodeIterable;
  41 import org.graalvm.compiler.nodes.ValueNode;
  42 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
  43 import org.graalvm.util.Equivalence;
  44 import org.graalvm.util.EconomicMap;
  45 import org.graalvm.util.EconomicSet;
  46 import org.graalvm.util.UnmodifiableMapCursor;
  47 
  48 import jdk.vm.ci.meta.MetaAccessProvider;
  49 import jdk.vm.ci.meta.MetaUtil;
  50 import jdk.vm.ci.meta.ResolvedJavaMethod;
  51 
  52 /**
  53  * Manages a set of {@link InvocationPlugin}s.
  54  */
  55 public class InvocationPlugins {
  56 
  57     public static class InvocationPluginReceiver implements InvocationPlugin.Receiver {
  58         private final GraphBuilderContext parser;
  59         private ValueNode[] args;
  60         private ValueNode value;
  61 
  62         public InvocationPluginReceiver(GraphBuilderContext parser) {
  63             this.parser = parser;
  64         }
  65 
  66         @Override


 242          * Registers a plugin for a method with 4 arguments.
 243          *
 244          * @param name the name of the method
 245          * @param plugin the plugin to be registered
 246          */
 247         public void register4(String name, Type arg1, Type arg2, Type arg3, Type arg4, InvocationPlugin plugin) {
 248             plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4);
 249         }
 250 
 251         /**
 252          * Registers a plugin for a method with 5 arguments.
 253          *
 254          * @param name the name of the method
 255          * @param plugin the plugin to be registered
 256          */
 257         public void register5(String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, InvocationPlugin plugin) {
 258             plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5);
 259         }
 260 
 261         /**
 262          * Registers a plugin for a method with 6 arguments.
 263          *
 264          * @param name the name of the method
 265          * @param plugin the plugin to be registered
 266          */
 267         public void register6(String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, Type arg6, InvocationPlugin plugin) {
 268             plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5, arg6);
 269         }
 270 
 271         /**
 272          * Registers a plugin for a method with 7 arguments.
 273          *
 274          * @param name the name of the method
 275          * @param plugin the plugin to be registered
 276          */
 277         public void register7(String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, Type arg6, Type arg7, InvocationPlugin plugin) {
 278             plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
 279         }
 280 
 281         /**
 282          * Registers a plugin for an optional method with no arguments.
 283          *
 284          * @param name the name of the method
 285          * @param plugin the plugin to be registered
 286          */
 287         public void registerOptional0(String name, InvocationPlugin plugin) {
 288             plugins.register(plugin, true, allowOverwrite, declaringType, name);
 289         }
 290 
 291         /**
 292          * Registers a plugin for an optional method with 1 argument.
 293          *
 294          * @param name the name of the method
 295          * @param plugin the plugin to be registered
 296          */
 297         public void registerOptional1(String name, Type arg, InvocationPlugin plugin) {
 298             plugins.register(plugin, true, allowOverwrite, declaringType, name, arg);
 299         }
 300 
 301         /**


 339          *            {@code declaringClass}
 340          */
 341         @Override
 342         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
 343             registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
 344         }
 345 
 346         /**
 347          * Registers a plugin that implements a method based on the bytecode of a substitute method.
 348          *
 349          * @param substituteDeclaringClass the class declaring the substitute method
 350          * @param name the name of both the original method
 351          * @param substituteName the name of the substitute method
 352          * @param argumentTypes the argument types of the method. Element 0 of this array must be
 353          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
 354          *            is non-static. Upon returning, element 0 will have been rewritten to
 355          *            {@code declaringClass}
 356          */
 357         @Override
 358         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {
 359             MethodSubstitutionPlugin plugin = createMethodSubstitution(substituteDeclaringClass, substituteName, argumentTypes);
 360             plugins.register(plugin, false, allowOverwrite, declaringType, name, argumentTypes);
 361         }
 362 
 363         public MethodSubstitutionPlugin createMethodSubstitution(Class<?> substituteDeclaringClass, String substituteName, Type... argumentTypes) {
 364             assert methodSubstitutionBytecodeProvider != null : "Registration used for method substitutions requires a non-null methodSubstitutionBytecodeProvider";
 365             MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(methodSubstitutionBytecodeProvider, substituteDeclaringClass, substituteName, argumentTypes);
 366             return plugin;
 367         }
 368 
 369     }
 370 
 371     /**
 372      * Key for a {@linkplain ClassPlugins#entries resolved} plugin registration. Due to the
 373      * possibility of class redefinition, we cannot directly use {@link ResolvedJavaMethod}s as
 374      * keys. A {@link ResolvedJavaMethod} implementation might implement {@code equals()} and
 375      * {@code hashCode()} based on internal representation subject to change by class redefinition.
 376      */
 377     static final class ResolvedJavaMethodKey {
 378         private final ResolvedJavaMethod method;
 379 
 380         ResolvedJavaMethodKey(ResolvedJavaMethod method) {
 381             this.method = method;
 382         }
 383 
 384         @Override
 385         public boolean equals(Object obj) {
 386             if (obj instanceof ResolvedJavaMethodKey) {
 387                 ResolvedJavaMethodKey that = (ResolvedJavaMethodKey) obj;
 388                 if (this.method.isStatic() == that.method.isStatic()) {


 502                 }
 503                 throw new InternalError(e);
 504             }
 505         }
 506 
 507         @Override
 508         public String toString() {
 509             StringBuilder sb = new StringBuilder(name).append('(');
 510             for (Type p : argumentTypes) {
 511                 if (sb.charAt(sb.length() - 1) != '(') {
 512                     sb.append(", ");
 513                 }
 514                 sb.append(p.getTypeName());
 515             }
 516             return sb.append(')').toString();
 517         }
 518     }
 519 
 520     private final MetaAccessProvider metaAccess;
 521 
 522     private final EconomicMap<String, ClassPlugins> registrations = EconomicMap.create(Equivalence.DEFAULT);
 523 
 524     /**
 525      * Deferred registrations as well as guard for initialization. The guard uses double-checked
 526      * locking which is why this field is {@code volatile}.
 527      */
 528     private volatile List<Runnable> deferredRegistrations = new ArrayList<>();
 529 
 530     /**
 531      * Adds a {@link Runnable} for doing registration deferred until the first time
 532      * {@link #get(ResolvedJavaMethod)} or {@link #closeRegistration()} is called on this object.
 533      */
 534     public void defer(Runnable deferrable) {
 535         assert deferredRegistrations != null : "registration is closed";
 536         deferredRegistrations.add(deferrable);
 537     }
 538 
 539     /**
 540      * Per-class invocation plugins.
 541      */
 542     protected static class ClassPlugins {
 543         private final Type declaringType;
 544 
 545         private final List<MethodKey> registrations = new ArrayList<>();
 546 
 547         public ClassPlugins(Type declaringClass) {
 548             this.declaringType = declaringClass;
 549         }
 550 
 551         /**
 552          * Entry map that is initialized upon first call to {@link #get(ResolvedJavaMethod)}.
 553          *
 554          * Note: this must be volatile as threads may race to initialize it.
 555          */
 556         private volatile EconomicMap<ResolvedJavaMethodKey, InvocationPlugin> entries;
 557 
 558         void initializeMap() {
 559             if (!isClosed()) {
 560                 if (registrations.isEmpty()) {
 561                     entries = EconomicMap.create(Equivalence.DEFAULT);
 562                 } else {
 563                     Class<?> declaringClass = resolveType(declaringType, true);
 564                     if (declaringClass == null) {
 565                         // An optional type that could not be resolved
 566                         entries = EconomicMap.create(Equivalence.DEFAULT);
 567                     } else {
 568                         EconomicMap<ResolvedJavaMethodKey, InvocationPlugin> newEntries = EconomicMap.create(Equivalence.DEFAULT);
 569                         for (MethodKey methodKey : registrations) {
 570                             ResolvedJavaMethod m = methodKey.resolve(declaringClass);
 571                             if (m != null) {
 572                                 newEntries.put(new ResolvedJavaMethodKey(m), methodKey.value);
 573                                 if (entries != null) {
 574                                     // Another thread finished initializing entries first
 575                                     return;
 576                                 }
 577                             }
 578                         }
 579                         entries = newEntries;
 580                     }
 581                 }
 582             }
 583         }
 584 
 585         public InvocationPlugin get(ResolvedJavaMethod method) {
 586             if (!isClosed()) {
 587                 initializeMap();
 588             }
 589             return entries.get(new ResolvedJavaMethodKey(method));
 590         }
 591 
 592         public void register(MethodKey methodKey, boolean allowOverwrite) {
 593             assert !isClosed() : "registration is closed: " + methodKey;
 594             if (allowOverwrite) {
 595                 int index = registrations.indexOf(methodKey);
 596                 if (index >= 0) {
 597                     registrations.set(index, methodKey);
 598                     return;
 599                 }
 600             } else {
 601                 assert !registrations.contains(methodKey) : "a value is already registered for " + declaringType + "." + methodKey;
 602             }
 603             registrations.add(methodKey);
 604         }
 605 
 606         public boolean isClosed() {
 607             return entries != null;
 608         }
 609     }
 610 
 611     /**
 612      * Adds an entry to this map for a specified method.
 613      *


 647     InvocationPlugin get(ResolvedJavaMethod method) {
 648         flushDeferrables();
 649         String internalName = method.getDeclaringClass().getName();
 650         ClassPlugins classPlugins = registrations.get(internalName);
 651         if (classPlugins != null) {
 652             return classPlugins.get(method);
 653         }
 654         return null;
 655     }
 656 
 657     private void flushDeferrables() {
 658         if (deferredRegistrations != null) {
 659             synchronized (this) {
 660                 if (deferredRegistrations != null) {
 661                     for (Runnable deferrable : deferredRegistrations) {
 662                         deferrable.run();
 663                     }
 664                     deferredRegistrations = null;
 665                 }
 666             }
 667             for (ClassPlugins e : registrations.getValues()) {
 668                 e.initializeMap();
 669             }
 670         }
 671     }
 672 
 673     /**
 674      * Disallows new registrations of new plugins, and creates the internal tables for method
 675      * lookup.
 676      */
 677     public void closeRegistration() {
 678         flushDeferrables();
 679         for (ClassPlugins e : registrations.getValues()) {
 680             e.initializeMap();
 681         }
 682     }
 683 
 684     public int size() {
 685         return registrations.size();
 686     }
 687 
 688     /**
 689      * The plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} before searching in
 690      * this object.
 691      */
 692     protected final InvocationPlugins parent;
 693 
 694     private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess) {
 695         this.metaAccess = metaAccess;
 696         InvocationPlugins p = parent;
 697         this.parent = p;
 698     }
 699 
 700     /**


 702      */
 703     public InvocationPlugins(InvocationPlugins parent) {
 704         this(parent, parent.getMetaAccess());
 705     }
 706 
 707     public InvocationPlugins(Map<ResolvedJavaMethod, InvocationPlugin> plugins, InvocationPlugins parent, MetaAccessProvider metaAccess) {
 708         this.metaAccess = metaAccess;
 709         this.parent = parent;
 710 
 711         this.deferredRegistrations = null;
 712 
 713         for (Map.Entry<ResolvedJavaMethod, InvocationPlugin> entry : plugins.entrySet()) {
 714             ResolvedJavaMethod method = entry.getKey();
 715             InvocationPlugin plugin = entry.getValue();
 716 
 717             String internalName = method.getDeclaringClass().getName();
 718             ClassPlugins classPlugins = registrations.get(internalName);
 719             if (classPlugins == null) {
 720                 classPlugins = new ClassPlugins(null);
 721                 registrations.put(internalName, classPlugins);
 722                 classPlugins.entries = EconomicMap.create(Equivalence.DEFAULT);
 723             }
 724 
 725             classPlugins.entries.put(new ResolvedJavaMethodKey(method), plugin);
 726         }
 727     }
 728 
 729     public MetaAccessProvider getMetaAccess() {
 730         return metaAccess;
 731     }
 732 
 733     public InvocationPlugins(MetaAccessProvider metaAccess) {
 734         this(null, metaAccess);
 735     }
 736 
 737     protected void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
 738         boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
 739         if (!isStatic) {
 740             argumentTypes[0] = declaringClass;
 741         }
 742         MethodKey methodKey = put(plugin, isStatic, isOptional, allowOverwrite, declaringClass, name, argumentTypes);


 776     /**
 777      * Gets the plugin for a given method.
 778      *
 779      * @param method the method to lookup
 780      * @return the plugin associated with {@code method} or {@code null} if none exists
 781      */
 782     public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
 783         if (parent != null) {
 784             InvocationPlugin plugin = parent.lookupInvocation(method);
 785             if (plugin != null) {
 786                 return plugin;
 787             }
 788         }
 789         return get(method);
 790     }
 791 
 792     /**
 793      * Gets the set of methods for which invocation plugins have been registered. Once this method
 794      * is called, no further registrations can be made.
 795      */
 796     public EconomicSet<ResolvedJavaMethod> getMethods() {
 797         EconomicSet<ResolvedJavaMethod> res = EconomicSet.create(Equivalence.DEFAULT);
 798         if (parent != null) {
 799             res.addAll(parent.getMethods());
 800         }
 801         flushDeferrables();
 802         for (ClassPlugins cp : registrations.getValues()) {
 803             for (ResolvedJavaMethodKey key : cp.entries.getKeys()) {
 804                 res.add(key.method);
 805             }
 806         }
 807         return res;
 808     }
 809 
 810     /**
 811      * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
 812      * before searching in this object.
 813      */
 814     public InvocationPlugins getParent() {
 815         return parent;
 816     }
 817 
 818     @Override
 819     public String toString() {
 820         StringBuilder buf = new StringBuilder();
 821         UnmodifiableMapCursor<String, ClassPlugins> entries = registrations.getEntries();
 822         while (entries.advance()) {
 823             buf.append(entries.getKey()).append('.').append(entries.getValue()).append(", ");
 824         }
 825 
 826         String s = buf.toString();
 827         if (buf.length() != 0) {
 828             s = s.substring(buf.length() - ", ".length());
 829         }
 830         return s + " / parent: " + this.parent;
 831     }
 832 
 833     private static class Checker {
 834         private static final int MAX_ARITY = 7;
 835         /**
 836          * The set of all {@link InvocationPlugin#apply} method signatures.
 837          */
 838         static final Class<?>[][] SIGS;
 839 
 840         static {
 841             ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
 842             for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
 843                 if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
 844                     Class<?>[] sig = method.getParameterTypes();
 845                     assert sig[0] == GraphBuilderContext.class;
 846                     assert sig[1] == ResolvedJavaMethod.class;
 847                     assert sig[2] == InvocationPlugin.Receiver.class;
 848                     assert Arrays.asList(sig).subList(3, sig.length).stream().allMatch(c -> c == ValueNode.class);
 849                     while (sigs.size() < sig.length - 2) {
 850                         sigs.add(null);
 851                     }
 852                     sigs.set(sig.length - 3, sig);
 853                 }
 854             }


src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File