< 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




   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   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 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
  68         public ValueNode get(boolean performNullCheck) {
  69             assert args != null : "Cannot get the receiver of a static method";
  70             if (!performNullCheck) {
  71                 return args[0];
  72             }
  73             if (value == null) {
  74                 value = parser.nullCheckedValue(args[0]);


 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()) {
 364                     if (this.method.getDeclaringClass().equals(that.method.getDeclaringClass())) {
 365                         if (this.method.getName().equals(that.method.getName())) {
 366                             if (this.method.getSignature().equals(that.method.getSignature())) {
 367                                 return true;
 368                             }
 369                         }
 370                     }
 371                 }
 372             }
 373             return false;













 374         }
 375 
 376         @Override
 377         public int hashCode() {
 378             return this.method.getName().hashCode();



 379         }
 380 
 381         @Override
 382         public String toString() {
 383             return "ResolvedJavaMethodKey<" + method + ">";


 384         }
 385     }
 386 
 387     /**
 388      * Key for {@linkplain ClassPlugins#registrations registering} an {@link InvocationPlugin} for a
 389      * specific method.
 390      */
 391     static class MethodKey {
 392         final boolean isStatic;



 393 
 394         /**
 395          * This method is optional. This is used for new API methods not present in previous JDK
 396          * versions.
 397          */
 398         final boolean isOptional;
 399 
 400         final String name;
 401         final Type[] argumentTypes;
 402         final InvocationPlugin value;

 403 
 404         /**
 405          * Used to lazily initialize {@link #resolved}.



 406          */
 407         private final MetaAccessProvider metaAccess;
 408 
 409         private volatile ResolvedJavaMethod resolved;



 410 
 411         MethodKey(MetaAccessProvider metaAccess, InvocationPlugin data, boolean isStatic, boolean isOptional, String name, Type... argumentTypes) {
 412             this.metaAccess = metaAccess;
 413             this.value = data;
 414             this.isStatic = isStatic;
 415             this.isOptional = isOptional;
 416             this.name = name;
 417             this.argumentTypes = argumentTypes;
 418         }
 419 
 420         @Override
 421         public boolean equals(Object obj) {
 422             if (obj instanceof MethodKey) {
 423                 MethodKey that = (MethodKey) obj;
 424                 boolean res = this.name.equals(that.name) && areEqual(this.argumentTypes, that.argumentTypes);
 425                 assert !res || this.isStatic == that.isStatic;
 426                 return res;
 427             }
 428             return false;
 429         }
 430 
 431         private static boolean areEqual(Type[] args1, Type[] args2) {
 432             if (args1.length == args2.length) {
 433                 for (int i = 0; i < args1.length; i++) {
 434                     if (!args1[i].getTypeName().equals(args2[i].getTypeName())) {
 435                         return false;
 436                     }
 437                 }
 438                 return true;
 439             }
 440             return false;
 441         }
 442 
 443         public int getDeclaredParameterCount() {
 444             return isStatic ? argumentTypes.length : argumentTypes.length - 1;
 445         }
 446 
 447         @Override
 448         public int hashCode() {
 449             return name.hashCode();
 450         }
 451 
 452         private ResolvedJavaMethod resolve(Class<?> declaringClass) {
 453             if (resolved == null) {
 454                 Executable method = resolveJava(declaringClass);
 455                 if (method == null) {
 456                     return null;
 457                 }
 458                 resolved = metaAccess.lookupJavaMethod(method);
 459             }
 460             return resolved;
 461         }
 462 
 463         private Executable resolveJava(Class<?> declaringClass) {
 464             try {
 465                 Executable res;
 466                 Class<?>[] parameterTypes = resolveTypes(argumentTypes, isStatic ? 0 : 1, argumentTypes.length);
 467                 if (name.equals("<init>")) {
 468                     res = declaringClass.getDeclaredConstructor(parameterTypes);
 469                 } else {
 470                     res = declaringClass.getDeclaredMethod(name, parameterTypes);
 471                 }
 472                 assert Modifier.isStatic(res.getModifiers()) == isStatic : res;
 473                 return res;
 474             } catch (NoSuchMethodException | SecurityException e) {
 475                 if (isOptional) {
 476                     return null;
 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      *
 589      * @param value value to be associated with the specified method
 590      * @param isStatic specifies if the method is static
 591      * @param isOptional specifies if the method is optional
 592      * @param declaringClass the class declaring the method
 593      * @param name the name of the method
 594      * @param argumentTypes the argument types of the method. Element 0 of this array must be
 595      *            {@code declaringClass} iff the method is non-static.
 596      * @return an object representing the method
 597      */
 598     MethodKey put(InvocationPlugin value, boolean isStatic, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {


 599         assert isStatic || argumentTypes[0] == declaringClass;

 600 
 601         String internalName = MetaUtil.toInternalName(declaringClass.getTypeName());
 602         ClassPlugins classPlugins = registrations.get(internalName);
 603         if (classPlugins == null) {
 604             classPlugins = new ClassPlugins(declaringClass);
 605             registrations.put(internalName, classPlugins);
 606         }
 607         assert isStatic || argumentTypes[0] == declaringClass;
 608         MethodKey methodKey = new MethodKey(metaAccess, value, isStatic, isOptional, name, argumentTypes);
 609         classPlugins.register(methodKey, allowOverwrite);
 610         return methodKey;
 611     }
 612 
 613     /**
 614      * Determines if a method denoted by a given {@link MethodKey} is in this map.
 615      */
 616     boolean containsKey(Type declaringType, MethodKey key) {
 617         String internalName = MetaUtil.toInternalName(declaringType.getTypeName());
 618         ClassPlugins classPlugins = registrations.get(internalName);
 619         return classPlugins != null && classPlugins.registrations.contains(key);
 620     }
 621 
 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     /**
 676      * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}.


 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);
 718         assert Checker.check(this, declaringClass, methodKey, plugin);

 719     }
 720 
 721     /**
 722      * Registers an invocation plugin for a given method. There must be no plugin currently
 723      * registered for {@code method}.
 724      *
 725      * @param argumentTypes the argument types of the method. Element 0 of this array must be the
 726      *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
 727      *            non-static. Upon returning, element 0 will have been rewritten to
 728      *            {@code declaringClass}
 729      */
 730     public void register(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
 731         register(plugin, false, false, declaringClass, name, argumentTypes);
 732     }
 733 
 734     public void register(InvocationPlugin plugin, String declaringClass, String name, Type... argumentTypes) {
 735         register(plugin, false, false, new OptionalLazySymbol(declaringClass), name, argumentTypes);
 736     }
 737 
 738     /**


 748         register(plugin, true, false, declaringClass, name, argumentTypes);
 749     }
 750 
 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             }
 826             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),
 827                             ValueNode.class.getSimpleName());
 828             SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
 829         }
 830 
 831         public static boolean check(InvocationPlugins plugins, Type declaringType, MethodKey method, InvocationPlugin plugin) {







 832             InvocationPlugins p = plugins.parent;
 833             while (p != null) {
 834                 assert !p.containsKey(declaringType, method) : "a plugin is already registered for " + method;
 835                 p = p.parent;
 836             }
 837             if (plugin instanceof ForeignCallPlugin || plugin instanceof GeneratedInvocationPlugin) {
 838                 return true;
 839             }
 840             if (plugin instanceof MethodSubstitutionPlugin) {
 841                 MethodSubstitutionPlugin msplugin = (MethodSubstitutionPlugin) plugin;
 842                 Method substitute = msplugin.getJavaSubstitute();
 843                 assert substitute.getAnnotation(MethodSubstitution.class) != null : format("Substitute method must be annotated with @%s: %s", MethodSubstitution.class.getSimpleName(), substitute);
 844                 return true;
 845             }
 846             int arguments = method.getDeclaredParameterCount();
 847             assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method);
 848             for (Method m : plugin.getClass().getDeclaredMethods()) {
 849                 if (m.getName().equals("apply")) {
 850                     Class<?>[] parameterTypes = m.getParameterTypes();
 851                     if (Arrays.equals(SIGS[arguments], parameterTypes)) {
 852                         return true;
 853                     }
 854                 }
 855             }
 856             throw new AssertionError(format("graph builder plugin for %s not found", method));

















 857         }
 858     }
 859 
 860     /**
 861      * Checks a set of nodes added to the graph by an {@link InvocationPlugin}.
 862      *
 863      * @param b the graph builder that applied the plugin
 864      * @param plugin a plugin that was just applied
 865      * @param newNodes the nodes added to the graph by {@code plugin}
 866      * @throws AssertionError if any check fail
 867      */
 868     public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
 869         if (parent != null) {
 870             parent.checkNewNodes(b, plugin, newNodes);
 871         }
 872     }
 873 
 874     /**
 875      * Resolves a name to a class.
 876      *


 887             return Class.forName(className, false, cl);
 888         } catch (ClassNotFoundException e) {
 889             if (optional) {
 890                 return null;
 891             }
 892             throw new GraalError("Could not resolve type " + className);
 893         }
 894     }
 895 
 896     /**
 897      * Resolves a {@link Type} to a {@link Class}.
 898      *
 899      * @param type the type to resolve
 900      * @param optional if true, resolution failure returns null
 901      * @return the resolved class or null if resolution fails and {@code optional} is true
 902      */
 903     public static Class<?> resolveType(Type type, boolean optional) {
 904         if (type instanceof Class) {
 905             return (Class<?>) type;
 906         }
 907         if (optional && type instanceof OptionalLazySymbol) {
 908             return ((OptionalLazySymbol) type).resolve();
 909         }
 910         return resolveClass(type.getTypeName(), optional);
 911     }
 912 
 913     private static final Class<?>[] NO_CLASSES = {};






 914 
 915     /**
 916      * Resolves an array of {@link Type}s to an array of {@link Class}es.



 917      *
 918      * @param types the types to resolve
 919      * @param from the initial index of the range to be resolved, inclusive
 920      * @param to the final index of the range to be resolved, exclusive
 921      * @return the resolved class or null if resolution fails and {@code optional} is true






































 922      */
 923     public static Class<?>[] resolveTypes(Type[] types, int from, int to) {
 924         int length = to - from;
 925         if (length <= 0) {
 926             return NO_CLASSES;
 927         }
 928         Class<?>[] classes = new Class<?>[length];
 929         for (int i = 0; i < length; i++) {
 930             classes[i] = resolveType(types[i + from], false);


 931         }
 932         return classes;







































 933     }
 934 }
< prev index next >