# HG changeset patch # User Doug Simon # Date 1428169624 -7200 # Node ID ba0f264a71cfc505d3136d0395d5d8a007ef717f # Parent 6adad2a0a24db67665b68cb993f6f2987adb202b added support for inlining graphs derived from InvocationPlugins diff -r 6adad2a0a24d -r ba0f264a71cf graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Fri Apr 03 17:49:43 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Sat Apr 04 19:47:04 2015 +0200 @@ -58,7 +58,9 @@ /** * Determines if the receiver is constant. */ - boolean isConstant(); + default boolean isConstant() { + return false; + } } /** diff -r 6adad2a0a24d -r ba0f264a71cf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Fri Apr 03 17:49:43 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Sat Apr 04 19:47:04 2015 +0200 @@ -68,11 +68,29 @@ void notifyAfterConstantsBound(StructuredGraph specializedSnippet); /** - * Gets the graph that is a substitution for a given method. + * Gets a graph that is a substitution for a given method. * * @return the graph, if any, that is a substitution for {@code method} */ - StructuredGraph getMethodSubstitution(ResolvedJavaMethod method); + default StructuredGraph getMethodSubstitution(ResolvedJavaMethod method) { + return getMethodSubstitution(method, false); + } + + /** + * Gets a graph that is a substitution for a given method. + * + * @param fromBytecodeOnly only return a graph created by parsing the bytecode of another method + * @return the graph, if any, that is a substitution for {@code method} + */ + StructuredGraph getMethodSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly); + + /** + * Determines if there is a {@linkplain #getMethodSubstitution(ResolvedJavaMethod) substitution + * graph} for a given method. + * + * @return true iff there is a substitution graph available for {@code method} + */ + boolean hasMethodSubstitution(ResolvedJavaMethod method); /** * Gets the method that is a substitution for a given method. diff -r 6adad2a0a24d -r ba0f264a71cf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Fri Apr 03 17:49:43 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Sat Apr 04 19:47:04 2015 +0200 @@ -574,7 +574,7 @@ } public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) { - return replacements.getMethodSubstitutionMethod(target) != null; + return replacements.hasMethodSubstitution(target); } public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) { diff -r 6adad2a0a24d -r ba0f264a71cf graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java Sat Apr 04 19:47:04 2015 +0200 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2011, 2013, 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.replacements; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.util.*; + +/** + * Implementation of {@link GraphBuilderContext} used to produce a graph for a method based on an + * {@link InvocationPlugin} for the method. + */ +public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver { + + private final Providers providers; + private final SnippetReflectionProvider snippetReflection; + private final StructuredGraph graph; + private final ResolvedJavaMethod method; + private FixedWithNextNode lastInstr; + private ValueNode[] arguments; + private ValueNode returnValue; + + public IntrinsicGraphBuilder(Providers providers, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod method) { + this.providers = providers; + this.snippetReflection = snippetReflection; + this.graph = new StructuredGraph(method, AllowAssumptions.YES); + this.method = method; + this.lastInstr = graph.start(); + + Signature sig = method.getSignature(); + int max = sig.getParameterCount(false); + this.arguments = new ValueNode[max + (method.isStatic() ? 0 : 1)]; + + int javaIndex = 0; + int index = 0; + if (!method.isStatic()) { + // add the receiver + Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass()); + FloatingNode receiver = graph.addWithoutUnique(new ParameterNode(javaIndex, receiverStamp)); + arguments[index] = receiver; + javaIndex = 1; + index = 1; + } + ResolvedJavaType accessingClass = method.getDeclaringClass(); + for (int i = 0; i < max; i++) { + JavaType type = sig.getParameterType(i, accessingClass).resolve(accessingClass); + Kind kind = type.getKind(); + Stamp stamp; + if (kind == Kind.Object && type instanceof ResolvedJavaType) { + stamp = StampFactory.declared((ResolvedJavaType) type); + } else { + stamp = StampFactory.forKind(kind); + } + FloatingNode param = graph.addWithoutUnique(new ParameterNode(index, stamp)); + arguments[index] = param; + javaIndex += kind.getSlotCount(); + index++; + } + } + + private void updateLastInstruction(T v) { + if (v instanceof FixedNode) { + FixedNode fixedNode = (FixedNode) v; + lastInstr.setNext(fixedNode); + if (fixedNode instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; + assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; + lastInstr = fixedWithNextNode; + } else { + lastInstr = null; + } + } + } + + public T append(T v) { + if (v.graph() != null) { + return v; + } + T added = graph.addOrUnique(v); + if (added == v) { + updateLastInstruction(v); + } + return added; + } + + public T recursiveAppend(T v) { + if (v.graph() != null) { + return v; + } + T added = graph.addOrUniqueWithInputs(v); + if (added == v) { + updateLastInstruction(v); + } + return added; + } + + public void push(Kind kind, ValueNode value) { + assert kind != Kind.Void; + assert returnValue == null; + returnValue = value; + } + + public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) { + throw GraalInternalError.shouldNotReachHere(); + } + + public StampProvider getStampProvider() { + return providers.getStampProvider(); + } + + public MetaAccessProvider getMetaAccess() { + return providers.getMetaAccess(); + } + + public Assumptions getAssumptions() { + return graph.getAssumptions(); + } + + public ConstantReflectionProvider getConstantReflection() { + return providers.getConstantReflection(); + } + + public SnippetReflectionProvider getSnippetReflection() { + return snippetReflection; + } + + public StructuredGraph getGraph() { + return graph; + } + + public FrameState createStateAfter() { + return getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI)); + } + + public GraphBuilderContext getParent() { + return null; + } + + public ResolvedJavaMethod getRootMethod() { + return method; + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + public int bci() { + return -1; + } + + public InvokeKind getInvokeKind() { + return method.isStatic() ? InvokeKind.Static : InvokeKind.Virtual; + } + + public JavaType getInvokeReturnType() { + return method.getSignature().getReturnType(method.getDeclaringClass()); + } + + public int getDepth() { + return 0; + } + + public boolean parsingReplacement() { + return true; + } + + public Replacement getReplacement() { + throw GraalInternalError.shouldNotReachHere(); + } + + public boolean eagerResolving() { + return true; + } + + public BailoutException bailout(String string) { + throw GraalInternalError.shouldNotReachHere(); + } + + public ValueNode get() { + return arguments[0]; + } + + public StructuredGraph buildGraph(InvocationPlugin plugin) { + Receiver receiver = method.isStatic() ? null : this; + InvocationPlugin.execute(this, method, plugin, receiver, arguments); + assert (returnValue != null) == (method.getSignature().getReturnKind() != Kind.Void); + append(new ReturnNode(returnValue)); + return graph; + } +} diff -r 6adad2a0a24d -r ba0f264a71cf graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Fri Apr 03 17:49:43 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sat Apr 04 19:47:04 2015 +0200 @@ -46,8 +46,7 @@ import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; -import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement; import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.*; @@ -90,8 +89,8 @@ * Determines whether a given method should be inlined based on whether it has a substitution or * whether the inlining context is already within a substitution. * - * @return an {@link InlineInfo} object specifying how {@code method} is to be inlined or null - * if it should not be inlined based on substitution related criteria + * @return an object specifying how {@code method} is to be inlined or null if it should not be + * inlined based on substitution related criteria */ public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { ResolvedJavaMethod subst = getMethodSubstitutionMethod(method); @@ -337,7 +336,13 @@ } @Override - public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) { + public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original, boolean fromBytecodeOnly) { + if (!fromBytecodeOnly) { + InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(original); + if (plugin != null) { + return new IntrinsicGraphBuilder(providers, snippetReflection, original).buildGraph(plugin); + } + } ClassReplacements cr = getClassReplacements(original.getDeclaringClass().getName()); ResolvedJavaMethod substitute = cr == null ? null : cr.methodSubstitutions.get(original); if (substitute == null) { @@ -623,7 +628,7 @@ // to be valid for the entire run of the VM. final StructuredGraph graph = new StructuredGraph(methodToParse, AllowAssumptions.NO); - // They will also never be never be evolved or have breakpoints set in them + // They will also never evolve or have breakpoints set in them graph.disableInlinedMethodRecording(); try (Scope s = Debug.scope("buildInitialGraph", graph)) { @@ -795,6 +800,10 @@ return cr != null && cr.forcedSubstitutions.contains(method); } + public boolean hasMethodSubstitution(ResolvedJavaMethod method) { + return graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method) != null || getMethodSubstitutionMethod(method) != null; + } + @Override public ResolvedJavaMethod getMethodSubstitutionMethod(ResolvedJavaMethod original) { ClassReplacements cr = getClassReplacements(original.getDeclaringClass().getName()); diff -r 6adad2a0a24d -r ba0f264a71cf graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Fri Apr 03 17:49:43 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Sat Apr 04 19:47:04 2015 +0200 @@ -108,7 +108,7 @@ * lowered}. */ protected StructuredGraph getLoweredSubstitutionGraph(LoweringTool tool) { - StructuredGraph methodSubstitution = tool.getReplacements().getMethodSubstitution(getTargetMethod()); + StructuredGraph methodSubstitution = tool.getReplacements().getMethodSubstitution(getTargetMethod(), true); if (methodSubstitution != null) { methodSubstitution = methodSubstitution.copy(); if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) {