changeset 19885:b950967f74c7

replaced HashMap with a side-table (i.e., an array) for looking up InvocationPlugins
author Doug Simon <doug.simon@oracle.com>
date Tue, 17 Mar 2015 12:05:49 +0100
parents 87736c089259
children 87c62a38f843
files graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPluginIdHolder.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java
diffstat 8 files changed, 177 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Sun Mar 15 11:48:14 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Tue Mar 17 12:05:49 2015 +0100
@@ -41,7 +41,7 @@
 
         /**
          * Creates a copy of a given set of plugins. The {@link InvocationPlugins} in
-         * {@code copyFrom} become the {@linkplain InvocationPlugins#getDefaults() default}
+         * {@code copyFrom} become the {@linkplain InvocationPlugins#getParent() default}
          * {@linkplain #getInvocationPlugins() invocation plugins} in this object.
          */
         public Plugins(Plugins copyFrom) {
@@ -164,7 +164,7 @@
 
     /**
      * Creates a copy of this configuration with all its plugins. The {@link InvocationPlugins} in
-     * this configuration become the {@linkplain InvocationPlugins#getDefaults defaults} of the
+     * this configuration become the {@linkplain InvocationPlugins#getParent() parent} of the
      * {@link InvocationPlugins} in the copy.
      */
     public GraphBuilderConfiguration copy() {
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Sun Mar 15 11:48:14 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Tue Mar 17 12:05:49 2015 +0100
@@ -32,6 +32,7 @@
  * Plugin for handling a specific method invocation.
  */
 public interface InvocationPlugin extends GraphBuilderPlugin {
+
     /**
      * @see #execute
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPluginIdHolder.java	Tue Mar 17 12:05:49 2015 +0100
@@ -0,0 +1,42 @@
+/*
+ * 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.graphbuilderconf;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * {@link ResolvedJavaMethod}s that can assign themselves an identifier for use in a side table
+ * mapping methods to {@link InvocationPlugin}s.
+ */
+public interface InvocationPluginIdHolder extends ResolvedJavaMethod {
+    /**
+     * Sets the unique, positive, non-zero identifier for this method.
+     */
+    void setInvocationPluginId(int id);
+
+    /**
+     * Gets the identifier set by {@link #setInvocationPluginId(int)} or 0 if no
+     * {@link InvocationPlugin} identifier was assigned to this method.
+     */
+    int getInvocationPluginId();
+}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Sun Mar 15 11:48:14 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Tue Mar 17 12:05:49 2015 +0100
@@ -132,24 +132,31 @@
         }
     }
 
-    public static final class MethodInfo {
-        public final boolean isStatic;
-        public final Class<?> declaringClass;
-        public final String name;
-        public final Class<?>[] argumentTypes;
+    static final class MethodInfo {
+        final boolean isStatic;
+        final Class<?> declaringClass;
+        final String name;
+        final Class<?>[] argumentTypes;
+        final InvocationPlugin plugin;
 
-        public MethodInfo(Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+        int id;
+
+        MethodInfo(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+            this.plugin = plugin;
             this.isStatic = argumentTypes.length == 0 || argumentTypes[0] != Receiver.class;
             this.declaringClass = declaringClass;
             this.name = name;
             this.argumentTypes = argumentTypes;
+            if (!isStatic) {
+                argumentTypes[0] = declaringClass;
+            }
         }
 
         @Override
         public boolean equals(Object obj) {
             if (obj instanceof MethodInfo) {
                 MethodInfo that = (MethodInfo) obj;
-                boolean res = this.declaringClass == that.declaringClass && this.name.equals(that.name) && Arrays.equals(this.argumentTypes, that.argumentTypes);
+                boolean res = this.name.equals(that.name) && this.declaringClass.equals(that.declaringClass) && Arrays.equals(this.argumentTypes, that.argumentTypes);
                 assert !res || this.isStatic == that.isStatic;
                 return res;
             }
@@ -162,17 +169,17 @@
             return declaringClass.getName().hashCode() ^ name.hashCode();
         }
 
-        public ResolvedJavaMethod resolve(MetaAccessProvider metaAccess) {
+        ResolvedJavaMethod resolve(MetaAccessProvider metaAccess) {
             try {
+                ResolvedJavaMethod method;
                 Class<?>[] parameterTypes = isStatic ? argumentTypes : Arrays.copyOfRange(argumentTypes, 1, argumentTypes.length);
-                ResolvedJavaMethod resolved;
                 if (name.equals("<init>")) {
-                    resolved = metaAccess.lookupJavaMethod(declaringClass.getDeclaredConstructor(parameterTypes));
+                    method = metaAccess.lookupJavaMethod(declaringClass.getDeclaredConstructor(parameterTypes));
                 } else {
-                    resolved = metaAccess.lookupJavaMethod(declaringClass.getDeclaredMethod(name, parameterTypes));
+                    method = metaAccess.lookupJavaMethod(declaringClass.getDeclaredMethod(name, parameterTypes));
                 }
-                assert resolved.isStatic() == isStatic;
-                return resolved;
+                assert method.isStatic() == isStatic;
+                return method;
             } catch (NoSuchMethodException | SecurityException e) {
                 throw new GraalInternalError(e);
             }
@@ -192,45 +199,54 @@
     }
 
     protected final MetaAccessProvider metaAccess;
-
-    private final Map<MethodInfo, InvocationPlugin> registrations;
-
+    private final List<MethodInfo> registrations;
     private final Thread registrationThread;
 
     /**
-     * Null while registration is open, non-null when registration is closed.
+     * The minimum {@linkplain InvocationPluginIdHolder#getInvocationPluginId() id} for a method
+     * associated with a plugin in {@link #plugins}.
      */
-    private volatile Map<ResolvedJavaMethod, InvocationPlugin> plugins;
+    private int minId = Integer.MAX_VALUE;
 
     /**
-     * The invocation plugins deferred to if a plugin is not found in this object.
+     * Resolved methods to plugins map. The keys (i.e., indexes) are derived from
+     * {@link InvocationPluginIdHolder#getInvocationPluginId()}.
      */
-    private InvocationPlugins defaults;
+    private volatile InvocationPlugin[] plugins;
 
     /**
-     * Creates a set of invocation plugins with a given non-null set of plugins as the
-     * {@linkplain #getDefaults defaults}.
+     * The plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} before searching in
+     * this object.
      */
-    public InvocationPlugins(InvocationPlugins defaults) {
+    private InvocationPlugins parent;
+
+    private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess, int estimatePluginCount) {
         this.registrationThread = Thread.currentThread();
-        this.metaAccess = defaults.getMetaAccess();
-        this.registrations = new HashMap<>();
-        InvocationPlugins defs = defaults;
-        // Only adopt non-empty defaults
-        while (defs != null && defs.size() == 0) {
-            defs = defs.defaults;
+        this.metaAccess = metaAccess;
+        this.registrations = new ArrayList<>(estimatePluginCount);
+        InvocationPlugins p = parent;
+        // Only adopt a non-empty parent
+        while (p != null && p.size() == 0) {
+            p = p.parent;
         }
-        this.defaults = defs;
+        this.parent = p;
+    }
+
+    private static final int DEFAULT_ESTIMATE_PLUGIN_COUNT = 16;
+
+    /**
+     * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}.
+     */
+    public InvocationPlugins(InvocationPlugins parent) {
+        this(parent, parent.metaAccess, DEFAULT_ESTIMATE_PLUGIN_COUNT);
     }
 
     public InvocationPlugins(MetaAccessProvider metaAccess) {
-        this(metaAccess, 16);
+        this(metaAccess, DEFAULT_ESTIMATE_PLUGIN_COUNT);
     }
 
     public InvocationPlugins(MetaAccessProvider metaAccess, int estimatePluginCount) {
-        this.metaAccess = metaAccess;
-        this.registrations = new HashMap<>(estimatePluginCount);
-        this.registrationThread = Thread.currentThread();
+        this(null, metaAccess, estimatePluginCount);
     }
 
     /**
@@ -239,13 +255,14 @@
      */
     public void register(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
         assert Thread.currentThread() == registrationThread : "invocation plugin registration must be single threaded";
-        MethodInfo method = new MethodInfo(declaringClass, name, argumentTypes);
-        assert Checker.check(method, plugin);
+        MethodInfo methodInfo = new MethodInfo(plugin, declaringClass, name, argumentTypes);
+        assert Checker.check(this, methodInfo, plugin);
         assert plugins == null : "invocation plugin registration is closed";
-        GraphBuilderPlugin oldValue = registrations.put(method, plugin);
-        assert oldValue == null : "a plugin is already registered for " + method;
+        registrations.add(methodInfo);
     }
 
+    private static int nextInvocationPluginId = 1;
+
     /**
      * Gets the plugin for a given method.
      *
@@ -253,40 +270,67 @@
      * @return the plugin associated with {@code method} or {@code null} if none exists
      */
     public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
-        InvocationPlugin res = null;
+        assert method instanceof InvocationPluginIdHolder;
+        if (parent != null) {
+            InvocationPlugin plugin = parent.lookupInvocation(method);
+            if (plugin != null) {
+                return plugin;
+            }
+        }
+        InvocationPluginIdHolder pluggable = (InvocationPluginIdHolder) method;
         if (plugins == null) {
-            synchronized (this) {
+            // Must synchronize across all InvocationPlugins objects to ensure thread safe
+            // allocation of InvocationPlugin identifiers
+            synchronized (InvocationPlugins.class) {
                 if (plugins == null) {
                     if (registrations.isEmpty()) {
-                        plugins = Collections.emptyMap();
+                        plugins = new InvocationPlugin[0];
                     } else {
-                        // System.out.println("resolving " + registrations.size() + " plugins");
-                        plugins = new HashMap<>(registrations.size());
-                        for (Map.Entry<MethodInfo, InvocationPlugin> e : registrations.entrySet()) {
-                            plugins.put(e.getKey().resolve(metaAccess), e.getValue());
+                        int max = Integer.MIN_VALUE;
+                        for (MethodInfo methodInfo : registrations) {
+                            InvocationPluginIdHolder p = (InvocationPluginIdHolder) methodInfo.resolve(metaAccess);
+                            int id = p.getInvocationPluginId();
+                            if (id == 0) {
+                                id = nextInvocationPluginId++;
+                                p.setInvocationPluginId(id);
+                            }
+                            if (id < minId) {
+                                minId = id;
+                            }
+                            if (id > max) {
+                                max = id;
+
+                            }
+                            methodInfo.id = id;
+                        }
+
+                        int length = (max - minId) + 1;
+                        plugins = new InvocationPlugin[length];
+                        for (MethodInfo m : registrations) {
+                            int index = m.id - minId;
+                            plugins[index] = m.plugin;
                         }
                     }
                 }
             }
         }
-        res = plugins.get(method);
-        if (res == null && defaults != null) {
-            return defaults.lookupInvocation(method);
-        }
-        return res;
+
+        int id = pluggable.getInvocationPluginId();
+        int index = id - minId;
+        return index >= 0 && index < plugins.length ? plugins[index] : null;
     }
 
     /**
-     * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} if a
-     * plugin is not found in this object.
+     * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
+     * before searching in this object.
      */
-    public InvocationPlugins getDefaults() {
-        return defaults;
+    public InvocationPlugins getParent() {
+        return parent;
     }
 
     @Override
     public String toString() {
-        return registrations.keySet().stream().map(MethodInfo::toString).collect(Collectors.joining(", ")) + " / defaults: " + this.defaults;
+        return registrations.stream().map(MethodInfo::toString).collect(Collectors.joining(", ")) + " / parent: " + this.parent;
     }
 
     private static class Checker {
@@ -314,7 +358,12 @@
             SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
         }
 
-        public static boolean check(MethodInfo method, InvocationPlugin plugin) {
+        public static boolean check(InvocationPlugins plugins, MethodInfo method, InvocationPlugin plugin) {
+            InvocationPlugins p = plugins;
+            while (p != null) {
+                assert !p.registrations.contains(method) : "a plugin is already registered for " + method;
+                p = p.parent;
+            }
             int arguments = method.argumentTypes.length;
             assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method);
             for (Method m : plugin.getClass().getDeclaredMethods()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Sun Mar 15 11:48:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Tue Mar 17 12:05:49 2015 +0100
@@ -29,7 +29,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Sun Mar 15 11:48:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Tue Mar 17 12:05:49 2015 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.nodes.*;
@@ -41,7 +42,7 @@
 /**
  * Implementation of {@link JavaMethod} for resolved HotSpot methods.
  */
-public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified {
+public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, InvocationPluginIdHolder {
 
     private static final long serialVersionUID = -5486975070147586588L;
 
@@ -740,4 +741,15 @@
         }
         return runtime().getCompilerToVM().hasCompiledCodeForOSR(metaspaceMethod, entryBCI, level);
     }
+
+    private int invocationPluginId;
+
+    public void setInvocationPluginId(int id) {
+        assert invocationPluginId == 0;
+        invocationPluginId = id;
+    }
+
+    public int getInvocationPluginId() {
+        return invocationPluginId;
+    }
 }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Sun Mar 15 11:48:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Mar 17 12:05:49 2015 +0100
@@ -40,9 +40,12 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
@@ -184,12 +187,18 @@
     }
 
     private static CompilationResult compileMethod(ResolvedJavaMethod javaMethod) {
-        Providers providers = getGraalProviders();
-        SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
+        HotSpotProviders providers = getGraalProviders();
+        SuitesProvider suitesProvider = providers.getSuites();
         Suites suites = suitesProvider.createSuites();
         LIRSuites lirSuites = suitesProvider.createLIRSuites();
         removeInliningPhase(suites);
         StructuredGraph graph = new StructuredGraph(javaMethod, AllowAssumptions.NO);
+
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getEagerDefault(plugins);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.ALL, null).apply(graph);
+
         PhaseSuite<HighTierContext> graphBuilderSuite = getGraphBuilderSuite(suitesProvider);
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
@@ -198,9 +207,9 @@
                         suites, lirSuites, new CompilationResult(), factory);
     }
 
-    private static Providers getGraalProviders() {
+    private static HotSpotProviders getGraalProviders() {
         RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class);
-        return runtimeProvider.getHostBackend().getProviders();
+        return (HotSpotProviders) runtimeProvider.getHostBackend().getProviders();
     }
 
     private static PhaseSuite<HighTierContext> getGraphBuilderSuite(SuitesProvider suitesProvider) {
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Sun Mar 15 11:48:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Tue Mar 17 12:05:49 2015 +0100
@@ -34,7 +34,6 @@
     @Override
     protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
         TruffleGraphBuilderPlugins.registerExactMathPlugins(conf.getPlugins().getInvocationPlugins());
-        super.editGraphBuilderConfiguration(conf);
         return super.editGraphBuilderConfiguration(conf);
     }