changeset 19104:81be933b83eb

use anonymous classes for GraphBuilderPlugins instead of enums to common out registration logic and add better static checking
author Doug Simon <doug.simon@oracle.com>
date Tue, 03 Feb 2015 21:22:33 +0100
parents ccabd82be35c
children b4441fd15166
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java
diffstat 9 files changed, 408 insertions(+), 255 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Tue Feb 03 18:30:07 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Tue Feb 03 21:22:33 2015 +0100
@@ -25,6 +25,9 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,17 +38,9 @@
 @ServiceProvider(GraphBuilderPluginsProvider.class)
 public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
     public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, ObjectPlugin.class);
-    }
-
-    /**
-     * HotSpot specific plugins for {@link Object}.
-     */
-    enum ObjectPlugin implements GraphBuilderPlugin {
-        getClass() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                assert args.length == 1;
-                ValueNode rcvr = args[0];
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("getClass", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
                 GuardingPiNode pi = builder.append(new GuardingPiNode(rcvr));
                 StampProvider stampProvider = builder.getStampProvider();
                 LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, pi));
@@ -53,10 +48,6 @@
                 builder.push(Kind.Object, mirror);
                 return true;
             }
-        };
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, name());
-        }
+        });
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java	Tue Feb 03 21:22:33 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import java.util.*;
+import java.util.stream.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Default implementation of {@link GraphBuilderPlugins} that uses a map.
+ */
+public class DefaultGraphBuilderPlugins implements GraphBuilderPlugins {
+
+    private final Map<ResolvedJavaMethod, InvocationPlugin> plugins = new HashMap<>();
+
+    /**
+     * Registers an invocation plugin for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     */
+    public void register(ResolvedJavaMethod method, InvocationPlugin plugin) {
+        assert InvocationPluginChecker.check(method, plugin);
+        GraphBuilderPlugin oldValue = plugins.put(method, plugin);
+        // System.out.println("registered: " + plugin);
+        assert oldValue == null;
+    }
+
+    /**
+     * Gets the plugin for a given method.
+     *
+     * @param method the method to lookup
+     * @return the plugin associated with {@code method} or {@code null} if none exists
+     */
+    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
+        return plugins.get(method);
+    }
+
+    @Override
+    public String toString() {
+        return plugins.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java	Tue Feb 03 18:30:07 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-
-/**
- * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
- */
-@ServiceProvider(GraphBuilderPluginsProvider.class)
-public class DefaultGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
-    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, ObjectPlugin.class);
-        plugins.register(metaAccess, BoxingPlugin.class);
-    }
-
-    /**
-     * Plugins for {@link Object}.
-     */
-    enum ObjectPlugin implements GraphBuilderPlugin {
-        init() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode object = args[0];
-                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
-                    builder.append(new RegisterFinalizerNode(object));
-                }
-                return true;
-            }
-
-            public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-                return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, "<init>");
-            }
-        };
-
-        @Override
-        public String toString() {
-            return Object.class.getName() + "." + name() + "()";
-        }
-    }
-
-    /**
-     * Plugins for the standard primitive box classes (e.g., {@link Integer} and friends).
-     */
-    enum BoxingPlugin implements GraphBuilderPlugin {
-        valueOf$Boolean(Kind.Boolean),
-        booleanValue$Boolean(Kind.Boolean),
-        valueOf$Byte(Kind.Byte),
-        byteValue$Byte(Kind.Byte),
-        valueOf$Short(Kind.Short),
-        shortValue$Short(Kind.Short),
-        valueOf$Char(Kind.Char),
-        charValue$Char(Kind.Char),
-        valueOf$Int(Kind.Int),
-        intValue$Int(Kind.Int),
-        valueOf$Long(Kind.Long),
-        longValue$Long(Kind.Long),
-        valueOf$Float(Kind.Float),
-        floatValue$Float(Kind.Float),
-        valueOf$Double(Kind.Double),
-        doubleValue$Double(Kind.Double);
-
-        BoxingPlugin(Kind kind) {
-            assert name().startsWith("valueOf$") || name().startsWith(kind.getJavaName() + "Value$");
-            this.kind = kind;
-            this.box = name().charAt(0) == 'v';
-        }
-
-        private final Kind kind;
-        private final boolean box;
-
-        public final boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-            if (box) {
-                ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
-                builder.push(Kind.Object, builder.append(new BoxNode(args[0], resultType, kind)));
-            } else {
-                builder.push(kind, builder.append(new UnboxNode(args[0], kind)));
-            }
-            return true;
-        }
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            Class<?>[] parameterTypes = box ? new Class<?>[]{kind.toJavaClass()} : new Class<?>[0];
-            return GraphBuilderPlugin.resolveTarget(metaAccess, kind.toBoxedJavaClass(), name(), parameterTypes);
-        }
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Feb 03 18:30:07 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Feb 03 21:22:33 2015 +0100
@@ -42,6 +42,7 @@
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
@@ -63,7 +64,7 @@
 
     public GraphBuilderPhase(GraphBuilderConfiguration config) {
         this.graphBuilderConfig = config;
-        this.graphBuilderPlugins = new GraphBuilderPlugins();
+        this.graphBuilderPlugins = new DefaultGraphBuilderPlugins();
     }
 
     @Override
@@ -773,11 +774,22 @@
                 if (GraalOptions.InlineDuringParsing.getValue() && invokeKind.isDirect()) {
 
                     if (graphBuilderPlugins != null) {
-                        GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod);
+                        InvocationPlugin plugin = graphBuilderPlugins.lookupInvocation(targetMethod);
                         if (plugin != null) {
                             int beforeStackSize = frameState.stackSize;
-                            if (plugin.handleInvocation(this, args)) {
-                                // System.out.println("used plugin: " + plugin);
+                            boolean handled;
+                            if (args.length == 0) {
+                                handled = plugin.apply(this);
+                            } else if (args.length == 1) {
+                                handled = plugin.apply(this, args[0]);
+                            } else if (args.length == 2) {
+                                handled = plugin.apply(this, args[0], args[1]);
+                            } else if (args.length == 3) {
+                                handled = plugin.apply(this, args[0], args[1], args[2]);
+                            } else {
+                                throw GraalInternalError.shouldNotReachHere();
+                            }
+                            if (handled) {
                                 assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize;
                                 return;
                             }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Tue Feb 03 18:30:07 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Tue Feb 03 21:22:33 2015 +0100
@@ -22,43 +22,14 @@
  */
 package com.oracle.graal.java;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
-
 /**
- * Extensions for handling certain bytecode instructions while building a
- * {@linkplain StructuredGraph graph} from a bytecode stream.
+ * Marker interface for graph builder plugins.
+ *
+ * Concrete plugins implement one of the sub-interfaces of this interface.
+ *
+ * @see GraphBuilderPluginsProvider
+ * @see GraphBuilderPlugins
+ * @see GraphBuilderPlugins.Registration
  */
 public interface GraphBuilderPlugin {
-
-    /**
-     * Processes an invocation parsed in a bytecode stream and add nodes to a graph being
-     * constructed that implement the semantics of the invocation.
-     *
-     * @param builder object being used to build a graph
-     * @param args the arguments to the invocation
-     */
-    boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args);
-
-    /**
-     * Gets the method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} .
-     */
-    ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess);
-
-    /**
-     * Looks up a {@link ResolvedJavaMethod}.
-     *
-     * @param methodNameBase the name of the method is the prefix of this value up to the first '$'
-     *            character
-     */
-    static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class<?> declaringClass, String methodNameBase, Class<?>... parameterTypes) {
-        int index = methodNameBase.indexOf('$');
-        String methodName = index == -1 ? methodNameBase : methodNameBase.substring(0, index);
-        try {
-            return metaAccess.lookupJavaMethod(methodName.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(methodName, parameterTypes));
-        } catch (NoSuchMethodException | SecurityException e) {
-            throw new GraalInternalError(e);
-        }
-    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Tue Feb 03 18:30:07 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Tue Feb 03 21:22:33 2015 +0100
@@ -22,45 +22,202 @@
  */
 package com.oracle.graal.java;
 
+import static java.lang.String.*;
+
+import java.lang.reflect.*;
 import java.util.*;
-import java.util.stream.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.nodes.*;
 
 /**
- * A repository of {@link GraphBuilderPlugin}s.
+ * Interface for managing a set of graph builder {@link GraphBuilderPlugin}s.
  */
-public class GraphBuilderPlugins {
-
-    private final Map<ResolvedJavaMethod, GraphBuilderPlugin> map = new HashMap<>();
+public interface GraphBuilderPlugins {
 
     /**
-     * Registers all the constants of an enum that implements {@link GraphBuilderPlugin}.
+     * Plugin for handling a method invocation.
      */
-    public <T extends Enum<T> & GraphBuilderPlugin> void register(MetaAccessProvider metaAccess, Class<T> enumClass) {
-        assert Enum.class.isAssignableFrom(enumClass);
-        Object[] enumConstants = enumClass.getEnumConstants();
-        for (Object o : enumConstants) {
-            GraphBuilderPlugin gbp = (GraphBuilderPlugin) o;
-            ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess);
-            GraphBuilderPlugin oldValue = map.put(target, gbp);
-            // System.out.println("registered: " + gbp);
-            assert oldValue == null;
+    public interface InvocationPlugin extends GraphBuilderPlugin {
+        /**
+         * Tries to handle an invocation to a method with no arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder) {
+            throw invalidHandler(builder);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with one argument.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg) {
+            throw invalidHandler(builder, arg);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with two arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
+            throw invalidHandler(builder, arg1, arg2);
+        }
+
+        /**
+         * Tries to handle an invocation to a method with three arguments.
+         *
+         * @return {@code true} this plugin handled the invocation
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+            throw invalidHandler(builder, arg1, arg2, arg3);
+        }
+
+        default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext builder, ValueNode... args) {
+            return new GraalInternalError("Invocation plugin %s does not handle invocations with %d arguments", getClass().getSimpleName(), args.length);
         }
     }
 
     /**
-     * Gets the plugin for a given method registered in the object.
+     * Utility for {@linkplain GraphBuilderPlugins#register(ResolvedJavaMethod, InvocationPlugin)
+     * registration} of plugins.
+     */
+    public static class Registration {
+
+        /**
+         * Sentinel class for use with {@link Registration#register1},
+         * {@link Registration#register2} or {@link Registration#register3} to denote the receiver
+         * argument for a non-static method.
+         */
+        public static final class Receiver {
+            private Receiver() {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        private final GraphBuilderPlugins plugins;
+        private final MetaAccessProvider metaAccess;
+        private final Class<?> declaringClass;
+
+        /**
+         * Creates an object for registering plugins for methods declared by a given class.
+         *
+         * @param plugins where to register the plugins
+         * @param metaAccess used to resolve classes and methods
+         * @param declaringClass the class declaring the methods for which plugins will be
+         *            registered via this object
+         */
+        public Registration(GraphBuilderPlugins plugins, MetaAccessProvider metaAccess, Class<?> declaringClass) {
+            this.plugins = plugins;
+            this.metaAccess = metaAccess;
+            this.declaringClass = declaringClass;
+        }
+
+        /**
+         * Registers a plugin for a method with no arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register0(String name, InvocationPlugin plugin) {
+            plugins.register(resolve(metaAccess, declaringClass, name), plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 1 argument.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 2 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 3 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Resolves a method given a declaring class, name and parameter types.
+         */
+        public static ResolvedJavaMethod resolve(MetaAccessProvider metaAccess, Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+            try {
+                return metaAccess.lookupJavaMethod(name.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(name, parameterTypes));
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new GraalInternalError(e);
+            }
+        }
+    }
+
+    public static class InvocationPluginChecker {
+        static final Class<?>[] APPLY0 = {GraphBuilderContext.class};
+        static final Class<?>[] APPLY1 = {GraphBuilderContext.class, ValueNode.class};
+        static final Class<?>[] APPLY2 = {GraphBuilderContext.class, ValueNode.class, ValueNode.class};
+        static final Class<?>[] APPLY3 = {GraphBuilderContext.class, ValueNode.class, ValueNode.class, ValueNode.class};
+        static final Class<?>[][] SIGS = {APPLY0, APPLY1, APPLY2, APPLY3};
+
+        public static boolean check(ResolvedJavaMethod method, InvocationPlugin plugin) {
+            int arguments = method.getSignature().getParameterCount(!method.isStatic());
+            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method.format("%H.%n(%p)"));
+            Method expected = null;
+            for (Method m : plugin.getClass().getDeclaredMethods()) {
+                if (m.getName().equals("apply")) {
+                    Class<?>[] parameterTypes = m.getParameterTypes();
+                    assert Arrays.equals(SIGS[arguments], parameterTypes) : format("graph builder plugin for %s has wrong signature%nexpected: (%s)%n  actual: (%s)", method.format("%H.%n(%p)"),
+                                    sigString(SIGS[arguments]), sigString(m.getParameterTypes()));
+                    expected = m;
+                }
+            }
+            assert expected != null : format("graph builder plugin %s must define exactly one \"apply\" method, none found", plugin);
+            return true;
+        }
+
+        protected static String sigString(Class<?>... sig) {
+            StringBuilder sb = new StringBuilder();
+            for (Class<?> t : sig) {
+                if (sb.length() != 0) {
+                    sb.append(", ");
+                }
+                sb.append(t.getSimpleName());
+            }
+            return sb.toString();
+        }
+
+    }
+
+    /**
+     * Registers an {@link InvocationPlugin} for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     */
+    void register(ResolvedJavaMethod method, InvocationPlugin plugin);
+
+    /**
+     * Gets the {@link InvocationPlugin} for a given method.
      *
      * @param method the method to lookup
      * @return the plugin associated with {@code method} or {@code null} if none exists
      */
-    public GraphBuilderPlugin getPlugin(ResolvedJavaMethod method) {
-        return map.get(method);
-    }
-
-    @Override
-    public String toString() {
-        return map.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
-    }
+    InvocationPlugin lookupInvocation(ResolvedJavaMethod method);
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Tue Feb 03 18:30:07 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Tue Feb 03 21:22:33 2015 +0100
@@ -30,9 +30,7 @@
  */
 public interface GraphBuilderPluginsProvider extends Service {
     /**
-     * Registers the plugins provided by this object with a plugins registry.
-     *
-     * @param plugins registry of plugins
+     * Registers the plugins provided by this object.
      */
     void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java	Tue Feb 03 21:22:33 2015 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
+ */
+@ServiceProvider(GraphBuilderPluginsProvider.class)
+public class StandardGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
+    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("<init>", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode object) {
+                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
+                    builder.append(new RegisterFinalizerNode(object));
+                }
+                return true;
+            }
+        });
+
+        for (Kind kind : Kind.values()) {
+            if (kind.isPrimitive() && kind != Kind.Void) {
+                new BoxPlugin(kind).register(metaAccess, plugins);
+                new UnboxPlugin(kind).register(metaAccess, plugins);
+            }
+        }
+    }
+
+    static class BoxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        BoxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
+            builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind)));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
+            plugins.register(method, this);
+        }
+    }
+
+    static class UnboxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        UnboxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            builder.push(kind, builder.append(new UnboxNode(value, kind)));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+            String name = kind.toJavaClass().getSimpleName() + "Value";
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
+            plugins.register(method, this);
+        }
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java	Tue Feb 03 18:30:07 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java	Tue Feb 03 21:22:33 2015 +0100
@@ -28,6 +28,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.truffle.nodes.frame.*;
@@ -39,96 +41,69 @@
 @ServiceProvider(GraphBuilderPluginsProvider.class)
 public class TruffleGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
     public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        plugins.register(metaAccess, CompilerDirectivesPlugin.class);
-    }
-
-    /**
-     * Plugins for {@link CompilerDirectives}.
-     */
-    enum CompilerDirectivesPlugin implements GraphBuilderPlugin {
-        inInterpreter() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(ConstantNode.forBoolean(false));
+        Registration r = new Registration(plugins, metaAccess, CompilerDirectives.class);
+        r.register0("inInterpreter", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(false)));
                 return true;
             }
-        },
-        inCompiledCode() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(ConstantNode.forBoolean(true));
+        });
+        r.register0("inCompiledCode", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true)));
                 return true;
             }
-        },
-        transferToInterpreter() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register0("transferToInterpreter", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
                 builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
-        },
-        transferToInterpreterAndInvalidate() {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
                 builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
-        },
-        interpreterOnly(Runnable.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
                 return true;
             }
-        },
-        interpreterOnly$(Callable.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
+        });
+        r.register1("interpreterOnly", Callable.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
                 return true;
             }
-        },
-        injectBranchProbability(double.class, boolean.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode probability = args[0];
-                ValueNode condition = args[1];
+        });
+        r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
                 builder.append(new BranchProbabilityNode(probability, condition));
                 return true;
             }
-        },
-        bailout(String.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                // TODO: is this too eager? Should a BailoutNode be created instead?
-                ValueNode message = args[0];
+        });
+        r.register1("bailout", String.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode message) {
                 if (message.isConstant()) {
                     throw new BailoutException(message.asConstant().toValueString());
                 }
                 throw new BailoutException("bailout (message is not compile-time constant, so no additional information is available)");
             }
-        },
-
-        isCompilationConstant(Object.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                ValueNode arg0 = args[0];
-                if (arg0 instanceof BoxNode) {
-                    arg0 = ((BoxNode) arg0).getValue();
-                }
-                if (arg0.isConstant()) {
+        });
+        r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
                     builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true)));
                     return true;
                 }
-
-                // Cannot create MacroNodes in a plugin (yet)
                 return false;
             }
-        },
-        materialize(Object.class) {
-            public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) {
-                builder.append(new ForceMaterializeNode(args[0]));
+        });
+        r.register1("materialize", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.append(new ForceMaterializeNode(value));
                 return true;
             }
-        };
-
-        CompilerDirectivesPlugin(Class<?>... parameterTypes) {
-            this.parameterTypes = parameterTypes;
-        }
-
-        private final Class<?>[] parameterTypes;
-
-        public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) {
-            return GraphBuilderPlugin.resolveTarget(metaAccess, CompilerDirectives.class, name(), parameterTypes);
-        }
+        });
     }
 }