Mercurial > hg > graal-compiler
view graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java @ 19846:93b74f0db076
don't treat Truffle method inlining substitutions as graph builder replacements
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Fri, 13 Mar 2015 23:27:53 +0100 |
parents | 1e27e31aca11 |
children |
line wrap: on
line source
/* * 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.lang.reflect.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin.InlineInfo; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; /** * Marker interface for graph builder plugins. */ public interface GraphBuilderPlugin { public interface LoadFieldPlugin extends GraphBuilderPlugin { @SuppressWarnings("unused") default boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) { return false; } @SuppressWarnings("unused") default boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) { return false; } default boolean tryConstantFold(GraphBuilderContext b, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ResolvedJavaField field, JavaConstant receiver) { JavaConstant result = constantReflection.readConstantFieldValue(field, receiver); if (result != null) { ConstantNode constantNode = b.append(ConstantNode.forConstant(result, metaAccess)); b.push(constantNode.getKind().getStackKind(), constantNode); return true; } return false; } } public interface LoadIndexedPlugin extends GraphBuilderPlugin { @SuppressWarnings("unused") default boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) { return false; } } /** * Plugin for specifying what is inlined during graph parsing or for post-processing non-inlined * invocations that result in {@link Invoke} nodes. */ public interface InlineInvokePlugin extends GraphBuilderPlugin { public static class InlineInfo { /** * The method to be inlined. */ public final ResolvedJavaMethod methodToInline; /** * Specifies if {@link #methodToInline} is to be considered a * {@linkplain GraphBuilderContext.Replacement replacement} for the {@code method} * passed to {@link InlineInvokePlugin#getInlineInfo}. */ public final boolean isReplacement; /** * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so, * any {@link StateSplit} node created in the (recursive) inlining scope will be given a * frame state that restarts the interpreter just before the intrinsified invocation. */ public final boolean isIntrinsic; public InlineInfo(ResolvedJavaMethod methodToInline, boolean isReplacement, boolean isIntrinsic) { this.methodToInline = methodToInline; this.isIntrinsic = isIntrinsic; this.isReplacement = isReplacement; assert !isIntrinsic || isReplacement : "cannot be an intrinsic without also being a replacement"; } } /** * Determines whether a call to a given method is to be inlined. * * @param method the target method of an invoke * @param args the arguments to the invoke * @param returnType the return type derived from {@code method}'s signature */ default InlineInfo getInlineInfo(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { return null; } /** * @param inlinedTargetMethod */ default void postInline(ResolvedJavaMethod inlinedTargetMethod) { } /** * Notifies this plugin of the {@link Invoke} node created for a method that was not inlined * per {@link #getInlineInfo}. * * @param method the method that was not inlined * @param invoke the invoke node created for the call to {@code method} */ default void notifyOfNoninlinedInvoke(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { } } public interface LoopExplosionPlugin extends GraphBuilderPlugin { boolean shouldExplodeLoops(ResolvedJavaMethod method); boolean shouldMergeExplosions(ResolvedJavaMethod method); } public interface ParameterPlugin extends GraphBuilderPlugin { FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp); } /** * Plugin for handling an invocation based on some property of the method being invoked such as * any annotations it may have. */ public interface GenericInvocationPlugin extends GraphBuilderPlugin { /** * Executes this plugin for an invocation of a given method with a given set of arguments. * * @return {@code true} if this plugin handled the invocation, {@code false} if not */ boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args); } /** * Plugin for handling a specific method invocation. */ public interface InvocationPlugin extends GraphBuilderPlugin { /** * @see #execute */ default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { throw invalidHandler(b, targetMethod); } /** * @see #execute */ default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { throw invalidHandler(b, targetMethod, arg); } /** * @see #execute */ default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2) { throw invalidHandler(b, targetMethod, arg1, arg2); } /** * @see #execute */ default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3) { throw invalidHandler(b, targetMethod, arg1, arg2, arg3); } /** * @see #execute */ default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) { throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4); } /** * @see #execute */ default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) { throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4, arg5); } default ResolvedJavaMethod getSubstitute() { return null; } boolean ALLOW_INVOCATION_PLUGIN_TO_DO_INLINING = false; /** * Executes a given plugin against a set of invocation arguments by dispatching to the * {@code apply(...)} method that matches the number of arguments. * * @param targetMethod the method for which plugin is being applied * @return {@code true} if the plugin handled the invocation of {@code targetMethod} * {@code false} if the graph builder should process the invoke further (e.g., by * inlining it or creating an {@link Invoke} node). A plugin that does not handle an * invocation must not modify the graph being constructed. */ static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, ValueNode[] args) { if (ALLOW_INVOCATION_PLUGIN_TO_DO_INLINING) { ResolvedJavaMethod subst = plugin.getSubstitute(); if (subst != null) { return ((BytecodeParser) b).inline(null, targetMethod, new InlineInfo(subst, true, false), args); } } if (args.length == 0) { return plugin.apply(b, targetMethod); } else if (args.length == 1) { return plugin.apply(b, targetMethod, args[0]); } else if (args.length == 2) { return plugin.apply(b, targetMethod, args[0], args[1]); } else if (args.length == 3) { return plugin.apply(b, targetMethod, args[0], args[1], args[2]); } else if (args.length == 4) { return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3]); } else if (args.length == 5) { return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3], args[4]); } else { throw plugin.invalidHandler(b, targetMethod, args); } } default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode... args) { return new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length); } default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) { Class<?> c = getClass(); for (Method m : c.getDeclaredMethods()) { if (m.getName().equals("apply")) { return metaAccess.lookupJavaMethod(m).asStackTraceElement(0); } } throw new GraalInternalError("could not find method named \"apply\" in " + c.getName()); } } }