src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java
changeset 58877 aec7bf35d6f5
parent 58299 6df94ce3ab2f
child 59095 03fbcd06b4c0
equal deleted inserted replaced
58876:1a8d65e71a66 58877:aec7bf35d6f5
    44 import jdk.internal.vm.compiler.collections.MapCursor;
    44 import jdk.internal.vm.compiler.collections.MapCursor;
    45 import jdk.internal.vm.compiler.collections.Pair;
    45 import jdk.internal.vm.compiler.collections.Pair;
    46 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
    46 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
    47 import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor;
    47 import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor;
    48 import org.graalvm.compiler.api.replacements.MethodSubstitution;
    48 import org.graalvm.compiler.api.replacements.MethodSubstitution;
    49 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
       
    50 import org.graalvm.compiler.bytecode.BytecodeProvider;
    49 import org.graalvm.compiler.bytecode.BytecodeProvider;
    51 import org.graalvm.compiler.core.common.SuppressFBWarnings;
    50 import org.graalvm.compiler.core.common.SuppressFBWarnings;
    52 import org.graalvm.compiler.debug.Assertions;
    51 import org.graalvm.compiler.debug.Assertions;
    53 import org.graalvm.compiler.debug.GraalError;
    52 import org.graalvm.compiler.debug.GraalError;
    54 import org.graalvm.compiler.graph.Node;
    53 import org.graalvm.compiler.graph.Node;
    55 import org.graalvm.compiler.graph.iterators.NodeIterable;
    54 import org.graalvm.compiler.graph.iterators.NodeIterable;
    56 import org.graalvm.compiler.nodes.ValueNode;
    55 import org.graalvm.compiler.nodes.ValueNode;
    57 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
    56 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
       
    57 import org.graalvm.compiler.nodes.spi.Replacements;
    58 
    58 
    59 import jdk.vm.ci.meta.MetaUtil;
    59 import jdk.vm.ci.meta.MetaUtil;
    60 import jdk.vm.ci.meta.ResolvedJavaMethod;
    60 import jdk.vm.ci.meta.ResolvedJavaMethod;
    61 import jdk.vm.ci.meta.ResolvedJavaType;
    61 import jdk.vm.ci.meta.ResolvedJavaType;
    62 import jdk.vm.ci.meta.Signature;
    62 import jdk.vm.ci.meta.Signature;
   173             return name;
   173             return name;
   174         }
   174         }
   175     }
   175     }
   176 
   176 
   177     /**
   177     /**
   178      * Utility for {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
   178      * Utility for {@linkplain InvocationPlugins#register registration} of invocation plugins.
   179      * registration} of invocation plugins.
   179      */
   180      */
   180     public static class Registration {
   181     public static class Registration implements MethodSubstitutionRegistry {
       
   182 
   181 
   183         private final InvocationPlugins plugins;
   182         private final InvocationPlugins plugins;
       
   183 
   184         private final Type declaringType;
   184         private final Type declaringType;
   185         private final BytecodeProvider methodSubstitutionBytecodeProvider;
   185         private final Replacements replacements;
       
   186         private final BytecodeProvider bytecodeProvider;
   186         private boolean allowOverwrite;
   187         private boolean allowOverwrite;
   187 
   188 
   188         @Override
       
   189         public Class<?> getReceiverType() {
   189         public Class<?> getReceiverType() {
   190             return Receiver.class;
   190             return Receiver.class;
       
   191         }
       
   192 
       
   193         public Type getDeclaringType() {
       
   194             return declaringType;
   191         }
   195         }
   192 
   196 
   193         /**
   197         /**
   194          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
   198          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
   195          * given class.
   199          * given class.
   199          *            via this object
   203          *            via this object
   200          */
   204          */
   201         public Registration(InvocationPlugins plugins, Type declaringType) {
   205         public Registration(InvocationPlugins plugins, Type declaringType) {
   202             this.plugins = plugins;
   206             this.plugins = plugins;
   203             this.declaringType = declaringType;
   207             this.declaringType = declaringType;
   204             this.methodSubstitutionBytecodeProvider = null;
   208             this.replacements = null;
       
   209             this.bytecodeProvider = null;
   205         }
   210         }
   206 
   211 
   207         /**
   212         /**
   208          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
   213          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
   209          * given class.
   214          * given class.
   210          *
   215          *
   211          * @param plugins where to register the plugins
   216          * @param plugins where to register the plugins
   212          * @param declaringType the class declaring the methods for which plugins will be registered
   217          * @param declaringType the class declaring the methods for which plugins will be registered
   213          *            via this object
   218          *            via this object
   214          * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
   219          * @param replacements the current Replacements provider
   215          *            method substitutions
   220          */
   216          */
   221         public Registration(InvocationPlugins plugins, Type declaringType, Replacements replacements) {
   217         public Registration(InvocationPlugins plugins, Type declaringType, BytecodeProvider methodSubstitutionBytecodeProvider) {
       
   218             this.plugins = plugins;
   222             this.plugins = plugins;
   219             this.declaringType = declaringType;
   223             this.declaringType = declaringType;
   220             this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
   224             this.replacements = replacements;
       
   225             this.bytecodeProvider = replacements != null ? replacements.getDefaultReplacementBytecodeProvider() : null;
       
   226         }
       
   227 
       
   228         /**
       
   229          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
       
   230          * given class.
       
   231          *
       
   232          * @param plugins where to register the plugins
       
   233          * @param declaringType the class declaring the methods for which plugins will be registered
       
   234          *            via this object
       
   235          * @param replacements the current Replacements provider
       
   236          */
       
   237         public Registration(InvocationPlugins plugins, Type declaringType, Replacements replacements, BytecodeProvider bytecodeProvider) {
       
   238             this.plugins = plugins;
       
   239             this.declaringType = declaringType;
       
   240             this.replacements = replacements;
       
   241             this.bytecodeProvider = bytecodeProvider;
   221         }
   242         }
   222 
   243 
   223         /**
   244         /**
   224          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
   245          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
   225          * given class.
   246          * given class.
   229          *            plugins will be registered via this object
   250          *            plugins will be registered via this object
   230          */
   251          */
   231         public Registration(InvocationPlugins plugins, String declaringClassName) {
   252         public Registration(InvocationPlugins plugins, String declaringClassName) {
   232             this.plugins = plugins;
   253             this.plugins = plugins;
   233             this.declaringType = new OptionalLazySymbol(declaringClassName);
   254             this.declaringType = new OptionalLazySymbol(declaringClassName);
   234             this.methodSubstitutionBytecodeProvider = null;
   255             this.replacements = null;
       
   256             this.bytecodeProvider = null;
   235         }
   257         }
   236 
   258 
   237         /**
   259         /**
   238          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
   260          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
   239          * given class.
   261          * given class.
   240          *
   262          *
   241          * @param plugins where to register the plugins
   263          * @param plugins where to register the plugins
   242          * @param declaringClassName the name of the class class declaring the methods for which
   264          * @param declaringClassName the name of the class class declaring the methods for which
   243          *            plugins will be registered via this object
   265          *            plugins will be registered via this object
   244          * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
   266          * @param replacements the current Replacements provider
   245          *            method substitutions
   267          */
   246          */
   268         public Registration(InvocationPlugins plugins, String declaringClassName, Replacements replacements) {
   247         public Registration(InvocationPlugins plugins, String declaringClassName, BytecodeProvider methodSubstitutionBytecodeProvider) {
       
   248             this.plugins = plugins;
   269             this.plugins = plugins;
   249             this.declaringType = new OptionalLazySymbol(declaringClassName);
   270             this.declaringType = new OptionalLazySymbol(declaringClassName);
   250             this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
   271             this.replacements = replacements;
       
   272             this.bytecodeProvider = replacements != null ? replacements.getDefaultReplacementBytecodeProvider() : null;
   251         }
   273         }
   252 
   274 
   253         /**
   275         /**
   254          * Configures this registration to allow or disallow overwriting of invocation plugins.
   276          * Configures this registration to allow or disallow overwriting of invocation plugins.
   255          */
   277          */
   334          * @param name the name of the method
   356          * @param name the name of the method
   335          * @param plugin the plugin to be registered
   357          * @param plugin the plugin to be registered
   336          */
   358          */
   337         public void register7(String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, Type arg6, Type arg7, InvocationPlugin plugin) {
   359         public void register7(String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, Type arg6, Type arg7, InvocationPlugin plugin) {
   338             plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
   360             plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
       
   361         }
       
   362 
       
   363         /**
       
   364          * Registers a plugin for a method with no arguments that is conditionally enabled. This
       
   365          * ensures that {@code Replacements} is aware of this plugin.
       
   366          *
       
   367          * @param name the name of the method
       
   368          * @param plugin the plugin to be registered
       
   369          */
       
   370         public void registerConditional0(boolean isEnabled, String name, InvocationPlugin plugin) {
       
   371             replacements.registerConditionalPlugin(plugin);
       
   372             if (isEnabled) {
       
   373                 plugins.register(plugin, false, allowOverwrite, declaringType, name);
       
   374             }
       
   375         }
       
   376 
       
   377         /**
       
   378          * Registers a plugin for a method with 1 argument that is conditionally enabled. This
       
   379          * ensures that {@code Replacements} is aware of this plugin.
       
   380          *
       
   381          * @param name the name of the method
       
   382          * @param plugin the plugin to be registered
       
   383          */
       
   384         public void registerConditional1(boolean isEnabled, String name, Type arg, InvocationPlugin plugin) {
       
   385             replacements.registerConditionalPlugin(plugin);
       
   386             if (isEnabled) {
       
   387                 plugins.register(plugin, false, allowOverwrite, declaringType, name, arg);
       
   388             }
       
   389         }
       
   390 
       
   391         /**
       
   392          * Registers a plugin for a method with 2 arguments that is conditionally enabled. This
       
   393          * ensures that {@code Replacements} is aware of this plugin.
       
   394          *
       
   395          * @param name the name of the method
       
   396          * @param plugin the plugin to be registered
       
   397          */
       
   398         public void registerConditional2(boolean isEnabled, String name, Type arg1, Type arg2, InvocationPlugin plugin) {
       
   399             replacements.registerConditionalPlugin(plugin);
       
   400             if (isEnabled) {
       
   401                 plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2);
       
   402             }
       
   403         }
       
   404 
       
   405         /**
       
   406          * Registers a plugin for a method with 3 arguments that is conditionally enabled. This
       
   407          * ensures that {@code Replacements} is aware of this plugin.
       
   408          *
       
   409          * @param name the name of the method
       
   410          * @param plugin the plugin to be registered
       
   411          */
       
   412         public void registerConditional3(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, InvocationPlugin plugin) {
       
   413             replacements.registerConditionalPlugin(plugin);
       
   414             if (isEnabled) {
       
   415                 plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3);
       
   416             }
       
   417         }
       
   418 
       
   419         /**
       
   420          * Registers a plugin for a method with 4 arguments that is conditionally enabled. This
       
   421          * ensures that {@code Replacements} is aware of this plugin.
       
   422          *
       
   423          * @param name the name of the method
       
   424          * @param plugin the plugin to be registered
       
   425          */
       
   426         public void registerConditional4(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, Type arg4, InvocationPlugin plugin) {
       
   427             replacements.registerConditionalPlugin(plugin);
       
   428             if (isEnabled) {
       
   429                 plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4);
       
   430             }
       
   431         }
       
   432 
       
   433         /**
       
   434          * Registers a plugin for a method with 5 arguments that is conditionally enabled. This
       
   435          * ensures that {@code Replacements} is aware of this plugin.
       
   436          *
       
   437          * @param name the name of the method
       
   438          * @param plugin the plugin to be registered
       
   439          */
       
   440         public void registerConditional5(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, InvocationPlugin plugin) {
       
   441             replacements.registerConditionalPlugin(plugin);
       
   442             if (isEnabled) {
       
   443                 plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5);
       
   444             }
       
   445         }
       
   446 
       
   447         /**
       
   448          * Registers a plugin for a method with 6 arguments that is conditionally enabled. This
       
   449          * ensures that {@code Replacements} is aware of this plugin.
       
   450          *
       
   451          * @param name the name of the method
       
   452          * @param plugin the plugin to be registered
       
   453          */
       
   454         public void registerConditional6(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, Type arg6, InvocationPlugin plugin) {
       
   455             replacements.registerConditionalPlugin(plugin);
       
   456             if (isEnabled) {
       
   457                 plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5, arg6);
       
   458             }
       
   459         }
       
   460 
       
   461         /**
       
   462          * Registers a plugin for a method with 7 arguments that is conditionally enabled. This
       
   463          * ensures that {@code Replacements} is aware of this plugin.
       
   464          *
       
   465          * @param name the name of the method
       
   466          * @param plugin the plugin to be registered
       
   467          */
       
   468         public void registerConditional7(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, Type arg6, Type arg7, InvocationPlugin plugin) {
       
   469             replacements.registerConditionalPlugin(plugin);
       
   470             if (isEnabled) {
       
   471                 plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
       
   472             }
   339         }
   473         }
   340 
   474 
   341         /**
   475         /**
   342          * Registers a plugin for an optional method with no arguments.
   476          * Registers a plugin for an optional method with no arguments.
   343          *
   477          *
   396          * @param argumentTypes the argument types of the method. Element 0 of this array must be
   530          * @param argumentTypes the argument types of the method. Element 0 of this array must be
   397          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
   531          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
   398          *            is non-static. Upon returning, element 0 will have been rewritten to
   532          *            is non-static. Upon returning, element 0 will have been rewritten to
   399          *            {@code declaringClass}
   533          *            {@code declaringClass}
   400          */
   534          */
   401         @Override
       
   402         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
   535         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
   403             registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
   536             registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
   404         }
   537         }
   405 
   538 
   406         /**
   539         /**
   407          * Registers a plugin that implements a method based on the bytecode of a substitute method.
   540          * Registers a plugin that implements a method based on the bytecode of a substitute method.
   408          *
   541          *
   409          * @param substituteDeclaringClass the class declaring the substitute method
   542          * @param substituteDeclaringClass the class declaring the substitute method
   410          * @param name the name of both the original method
   543          * @param name the name of the original method
   411          * @param substituteName the name of the substitute method
   544          * @param substituteName the name of the substitute method
   412          * @param argumentTypes the argument types of the method. Element 0 of this array must be
   545          * @param argumentTypes the argument types of the method. Element 0 of this array must be
   413          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
   546          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
   414          *            is non-static. Upon returning, element 0 will have been rewritten to
   547          *            is non-static. Upon returning, element 0 will have been rewritten to
   415          *            {@code declaringClass}
   548          *            {@code declaringClass}
   416          */
   549          */
   417         @Override
       
   418         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {
   550         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {
   419             MethodSubstitutionPlugin plugin = createMethodSubstitution(substituteDeclaringClass, substituteName, argumentTypes);
   551             doMethodSubstitutionRegistration(false, true, substituteDeclaringClass, name, substituteName, argumentTypes);
   420             plugins.register(plugin, false, allowOverwrite, declaringType, name, argumentTypes);
   552         }
   421         }
   553 
   422 
   554         /**
   423         public MethodSubstitutionPlugin createMethodSubstitution(Class<?> substituteDeclaringClass, String substituteName, Type... argumentTypes) {
   555          * Registers a plugin that implements a method based on the bytecode of a substitute method
   424             assert methodSubstitutionBytecodeProvider != null : "Registration used for method substitutions requires a non-null methodSubstitutionBytecodeProvider";
   556          * that is conditinally enabled. This ensures that {@code Replacements} is aware of this
   425             MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(methodSubstitutionBytecodeProvider, substituteDeclaringClass, substituteName, argumentTypes);
   557          * plugin.
   426             return plugin;
   558          *
   427         }
   559          * @param isEnabled whether the plugin is enabled in the current compiler
   428 
   560          * @param substituteDeclaringClass the class declaring the substitute method
       
   561          * @param name the name of both the original and substitute method
       
   562          * @param argumentTypes the argument types of the method. Element 0 of this array must be
       
   563          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
       
   564          *            is non-static. Upon returning, element 0 will have been rewritten to
       
   565          *            {@code declaringClass}
       
   566          */
       
   567         public void registerConditionalMethodSubstitution(boolean isEnabled, Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
       
   568             registerConditionalMethodSubstitution(isEnabled, substituteDeclaringClass, name, name, argumentTypes);
       
   569         }
       
   570 
       
   571         /**
       
   572          * Registers a plugin that implements a method based on the bytecode of a substitute method
       
   573          * that is conditinally enabled. This ensures that {@code Replacements} is aware of this
       
   574          * plugin.
       
   575          *
       
   576          * @param isEnabled whether the plugin is enabled in the current compiler
       
   577          * @param substituteDeclaringClass the class declaring the substitute method
       
   578          * @param name the name of the original method
       
   579          * @param substituteName the name of the substitute method
       
   580          * @param argumentTypes the argument types of the method. Element 0 of this array must be
       
   581          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
       
   582          *            is non-static. Upon returning, element 0 will have been rewritten to
       
   583          *            {@code declaringClass}
       
   584          */
       
   585         public void registerConditionalMethodSubstitution(boolean isEnabled, Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {
       
   586             doMethodSubstitutionRegistration(true, isEnabled, substituteDeclaringClass, name, substituteName, argumentTypes);
       
   587         }
       
   588 
       
   589         private void doMethodSubstitutionRegistration(boolean isConditional, boolean isEnabled, Class<?> substituteDeclaringClass, String name, String substituteName, Type[] argumentTypes) {
       
   590             MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(this, bytecodeProvider, name, substituteDeclaringClass, substituteName, argumentTypes);
       
   591             replacements.registerMethodSubstitution(plugin);
       
   592             if (isConditional) {
       
   593                 // Notify Replacements about the plugin even if it's not current enabled
       
   594                 replacements.registerConditionalPlugin(plugin);
       
   595             }
       
   596             if (isEnabled) {
       
   597                 plugins.register(plugin, false, allowOverwrite, declaringType, name, argumentTypes);
       
   598             }
       
   599         }
   429     }
   600     }
   430 
   601 
   431     /**
   602     /**
   432      * Utility for registering plugins after Graal may have been initialized. Registrations made via
   603      * Utility for registering plugins after Graal may have been initialized. Registrations made via
   433      * this class are not finalized until {@link #close} is called.
   604      * this class are not finalized until {@link #close} is called.
   517 
   688 
   518         Binding(InvocationPlugin data, boolean isStatic, String name, Type... argumentTypes) {
   689         Binding(InvocationPlugin data, boolean isStatic, String name, Type... argumentTypes) {
   519             this.plugin = data;
   690             this.plugin = data;
   520             this.isStatic = isStatic;
   691             this.isStatic = isStatic;
   521             this.name = name;
   692             this.name = name;
   522             StringBuilder buf = new StringBuilder();
   693             this.argumentsDescriptor = toArgumentDescriptor(isStatic, argumentTypes);
   523             buf.append('(');
       
   524             for (int i = isStatic ? 0 : 1; i < argumentTypes.length; i++) {
       
   525                 buf.append(MetaUtil.toInternalName(argumentTypes[i].getTypeName()));
       
   526             }
       
   527             buf.append(')');
       
   528             this.argumentsDescriptor = buf.toString();
       
   529             assert !name.equals("<init>") || !isStatic : this;
   694             assert !name.equals("<init>") || !isStatic : this;
   530         }
   695         }
   531 
   696 
   532         Binding(ResolvedJavaMethod resolved, InvocationPlugin data) {
   697         Binding(ResolvedJavaMethod resolved, InvocationPlugin data) {
   533             this.plugin = data;
   698             this.plugin = data;
   542 
   707 
   543         @Override
   708         @Override
   544         public String toString() {
   709         public String toString() {
   545             return name + argumentsDescriptor;
   710             return name + argumentsDescriptor;
   546         }
   711         }
       
   712     }
       
   713 
       
   714     static String toArgumentDescriptor(boolean isStatic, Type[] argumentTypes) {
       
   715         StringBuilder buf = new StringBuilder();
       
   716         buf.append('(');
       
   717         for (int i = isStatic ? 0 : 1; i < argumentTypes.length; i++) {
       
   718             buf.append(MetaUtil.toInternalName(argumentTypes[i].getTypeName()));
       
   719         }
       
   720         buf.append(')');
       
   721         return buf.toString();
   547     }
   722     }
   548 
   723 
   549     /**
   724     /**
   550      * Plugin registrations for already resolved methods. If non-null, then {@link #registrations}
   725      * Plugin registrations for already resolved methods. If non-null, then {@link #registrations}
   551      * is null and no further registrations can be made.
   726      * is null and no further registrations can be made.