001/*
002 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.graphbuilderconf;
024
025import java.lang.invoke.*;
026import java.lang.reflect.*;
027
028import jdk.internal.jvmci.common.*;
029import jdk.internal.jvmci.meta.*;
030
031import com.oracle.graal.nodes.*;
032import com.oracle.graal.nodes.type.*;
033
034/**
035 * Plugin for handling a specific method invocation.
036 */
037public interface InvocationPlugin extends GraphBuilderPlugin {
038
039    /**
040     * The receiver in a non-static method. The class literal for this interface must be used with
041     * {@link MethodIdMap#put(Object, boolean, boolean, Class, String, Class...)} to denote the
042     * receiver argument for such a non-static method.
043     */
044    public interface Receiver {
045        /**
046         * Gets the receiver value, null checking it first if necessary.
047         *
048         * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode)
049         *         non-null} stamp
050         */
051        ValueNode get();
052
053        /**
054         * Determines if the receiver is constant.
055         */
056        default boolean isConstant() {
057            return false;
058        }
059    }
060
061    /**
062     * Determines if this plugin is for a method with a polymorphic signature (e.g.
063     * {@link MethodHandle#invokeExact(Object...)}).
064     */
065    default boolean isSignaturePolymorphic() {
066        return false;
067    }
068
069    /**
070     * Determines if this plugin can only be used when inlining the method is it associated with.
071     * That is, this plugin cannot be used when the associated method is the compilation root.
072     */
073    default boolean inlineOnly() {
074        return isSignaturePolymorphic();
075    }
076
077    /**
078     * Handles invocation of a signature polymorphic method.
079     *
080     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
081     * @param argsIncludingReceiver all arguments to the invocation include the raw receiver in
082     *            position 0 if {@code targetMethod} is not static
083     * @see #execute
084     */
085    default boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode... argsIncludingReceiver) {
086        return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
087    }
088
089    /**
090     * @see #execute
091     */
092    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver) {
093        return defaultHandler(b, targetMethod, receiver);
094    }
095
096    /**
097     * @see #execute
098     */
099    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg) {
100        return defaultHandler(b, targetMethod, receiver, arg);
101    }
102
103    /**
104     * @see #execute
105     */
106    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2) {
107        return defaultHandler(b, targetMethod, receiver, arg1, arg2);
108    }
109
110    /**
111     * @see #execute
112     */
113    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
114        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3);
115    }
116
117    /**
118     * @see #execute
119     */
120    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
121        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4);
122    }
123
124    /**
125     * @see #execute
126     */
127    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
128        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5);
129    }
130
131    /**
132     * Executes this plugin against a set of invocation arguments.
133     *
134     * The default implementation in {@link InvocationPlugin} dispatches to the {@code apply(...)}
135     * method that matches the number of arguments or to {@link #applyPolymorphic} if {@code plugin}
136     * is {@linkplain #isSignaturePolymorphic() signature polymorphic}.
137     *
138     * @param targetMethod the method for which this plugin is being applied
139     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
140     * @param argsIncludingReceiver all arguments to the invocation include the receiver in position
141     *            0 if {@code targetMethod} is not static
142     * @return {@code true} if this plugin handled the invocation of {@code targetMethod}
143     *         {@code false} if the graph builder should process the invoke further (e.g., by
144     *         inlining it or creating an {@link Invoke} node). A plugin that does not handle an
145     *         invocation must not modify the graph being constructed.
146     */
147    default boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
148        if (isSignaturePolymorphic()) {
149            return applyPolymorphic(b, targetMethod, receiver, argsIncludingReceiver);
150        } else if (receiver != null) {
151            assert !targetMethod.isStatic();
152            assert argsIncludingReceiver.length > 0;
153            if (argsIncludingReceiver.length == 1) {
154                return apply(b, targetMethod, receiver);
155            } else if (argsIncludingReceiver.length == 2) {
156                return apply(b, targetMethod, receiver, argsIncludingReceiver[1]);
157            } else if (argsIncludingReceiver.length == 3) {
158                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2]);
159            } else if (argsIncludingReceiver.length == 4) {
160                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
161            } else if (argsIncludingReceiver.length == 5) {
162                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
163            } else {
164                return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
165            }
166        } else {
167            assert targetMethod.isStatic();
168            if (argsIncludingReceiver.length == 0) {
169                return apply(b, targetMethod, null);
170            } else if (argsIncludingReceiver.length == 1) {
171                return apply(b, targetMethod, null, argsIncludingReceiver[0]);
172            } else if (argsIncludingReceiver.length == 2) {
173                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1]);
174            } else if (argsIncludingReceiver.length == 3) {
175                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2]);
176            } else if (argsIncludingReceiver.length == 4) {
177                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
178            } else if (argsIncludingReceiver.length == 5) {
179                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
180            } else {
181                return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
182            }
183
184        }
185    }
186
187    /**
188     * Handles an invocation when a specific {@code apply} method is not available.
189     */
190    default boolean defaultHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") InvocationPlugin.Receiver receiver,
191                    ValueNode... args) {
192        throw new JVMCIError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
193    }
194
195    default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
196        Class<?> c = getClass();
197        for (Method m : c.getDeclaredMethods()) {
198            if (m.getName().equals("apply")) {
199                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
200            } else if (m.getName().equals("defaultHandler")) {
201                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
202            }
203        }
204        throw new JVMCIError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName());
205    }
206}