001/*
002 * Copyright (c) 2012, 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.hotspot.stubs;
024
025import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
026
027import java.lang.reflect.*;
028
029import jdk.internal.jvmci.common.*;
030import com.oracle.graal.debug.*;
031import com.oracle.graal.debug.Debug.*;
032import jdk.internal.jvmci.meta.*;
033
034import com.oracle.graal.graphbuilderconf.*;
035import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
036import com.oracle.graal.hotspot.*;
037import com.oracle.graal.hotspot.meta.*;
038import com.oracle.graal.java.*;
039import com.oracle.graal.nodes.*;
040import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
041import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
042import com.oracle.graal.nodes.spi.*;
043import com.oracle.graal.phases.*;
044import com.oracle.graal.phases.common.*;
045import com.oracle.graal.phases.tiers.*;
046import com.oracle.graal.replacements.*;
047import com.oracle.graal.replacements.Snippet.ConstantParameter;
048
049/**
050 * Base class for a stub defined by a snippet.
051 */
052public abstract class SnippetStub extends Stub implements Snippets {
053
054    protected final ResolvedJavaMethod method;
055
056    /**
057     * Creates a new snippet stub.
058     *
059     * @param snippetMethodName name of the single {@link Snippet} annotated method in the class of
060     *            this object
061     * @param linkage linkage details for a call to the stub
062     */
063    public SnippetStub(String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
064        this(null, snippetMethodName, providers, linkage);
065    }
066
067    /**
068     * Creates a new snippet stub.
069     *
070     * @param snippetDeclaringClass this class in which the {@link Snippet} annotated method is
071     *            declared. If {@code null}, this the class of this object is used.
072     * @param snippetMethodName name of the single {@link Snippet} annotated method in
073     *            {@code snippetDeclaringClass}
074     * @param linkage linkage details for a call to the stub
075     */
076    public SnippetStub(Class<? extends Snippets> snippetDeclaringClass, String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
077        super(providers, linkage);
078        Method javaMethod = SnippetTemplate.AbstractTemplates.findMethod(snippetDeclaringClass == null ? getClass() : snippetDeclaringClass, snippetMethodName, null);
079        this.method = providers.getMetaAccess().lookupJavaMethod(javaMethod);
080    }
081
082    @SuppressWarnings("all")
083    private static boolean assertionsEnabled() {
084        boolean enabled = false;
085        assert enabled = true;
086        return enabled;
087    }
088
089    public static final ThreadLocal<StructuredGraph> SnippetGraphUnderConstruction = assertionsEnabled() ? new ThreadLocal<>() : null;
090
091    @Override
092    protected StructuredGraph getGraph() {
093        Plugins defaultPlugins = providers.getGraphBuilderPlugins();
094        MetaAccessProvider metaAccess = providers.getMetaAccess();
095        Plugins plugins = new Plugins(defaultPlugins);
096        plugins.prependParameterPlugin(new ConstantBindingParameterPlugin(makeConstArgs(), metaAccess, providers.getSnippetReflection()));
097        GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
098
099        // Stubs cannot have optimistic assumptions since they have
100        // to be valid for the entire run of the VM. Nor can they be
101        // evolved or have breakpoints.
102        final StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO);
103        graph.disableInlinedMethodRecording();
104        graph.disableUnsafeAccessTracking();
105
106        if (SnippetGraphUnderConstruction != null) {
107            assert SnippetGraphUnderConstruction.get() == null : SnippetGraphUnderConstruction.get().toString() + " " + graph;
108            SnippetGraphUnderConstruction.set(graph);
109        }
110
111        try {
112            IntrinsicContext initialIntrinsicContext = new IntrinsicContext(method, method, INLINE_AFTER_PARSING);
113            new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph);
114
115        } finally {
116            if (SnippetGraphUnderConstruction != null) {
117                SnippetGraphUnderConstruction.set(null);
118            }
119        }
120
121        graph.setGuardsStage(GuardsStage.FLOATING_GUARDS);
122        try (Scope s = Debug.scope("LoweringStub", graph)) {
123            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, new PhaseContext(providers));
124        } catch (Throwable e) {
125            throw Debug.handle(e);
126        }
127
128        return graph;
129    }
130
131    protected boolean checkConstArg(int index, String expectedName) {
132        assert method.getParameterAnnotation(ConstantParameter.class, index) != null : String.format("parameter %d of %s is expected to be constant", index, method.format("%H.%n(%p)"));
133        LocalVariableTable lvt = method.getLocalVariableTable();
134        if (lvt != null) {
135            Local local = lvt.getLocal(index, 0);
136            assert local != null;
137            String actualName = local.getName();
138            assert actualName.equals(expectedName) : String.format("parameter %d of %s is expected to be named %s, not %s", index, method.format("%H.%n(%p)"), expectedName, actualName);
139        }
140        return true;
141    }
142
143    protected Object[] makeConstArgs() {
144        int count = method.getSignature().getParameterCount(false);
145        Object[] args = new Object[count];
146        for (int i = 0; i < args.length; i++) {
147            if (method.getParameterAnnotation(ConstantParameter.class, i) != null) {
148                args[i] = getConstantParameterValue(i, null);
149            }
150        }
151        return args;
152    }
153
154    protected Object getConstantParameterValue(int index, String name) {
155        throw new JVMCIError("%s must override getConstantParameterValue() to provide a value for parameter %d%s", getClass().getName(), index, name == null ? "" : " (" + name + ")");
156    }
157
158    @Override
159    protected Object debugScopeContext() {
160        return getInstalledCodeOwner();
161    }
162
163    @Override
164    public ResolvedJavaMethod getInstalledCodeOwner() {
165        return method;
166    }
167
168    @Override
169    public String toString() {
170        return "Stub<" + getInstalledCodeOwner().format("%h.%n") + ">";
171    }
172}