1/*
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.replacements;
24
25import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
26
27import org.graalvm.compiler.bytecode.BytecodeProvider;
28import org.graalvm.compiler.debug.DebugContext;
29import org.graalvm.compiler.java.GraphBuilderPhase;
30import org.graalvm.compiler.nodes.EncodedGraph;
31import org.graalvm.compiler.nodes.GraphEncoder;
32import org.graalvm.compiler.nodes.StructuredGraph;
33import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
34import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
35import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
36import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
37import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
38import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin;
39import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
40import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
41import org.graalvm.compiler.phases.OptimisticOptimizations;
42import org.graalvm.compiler.phases.common.CanonicalizerPhase;
43import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
44import org.graalvm.compiler.phases.tiers.PhaseContext;
45import org.graalvm.compiler.phases.util.Providers;
46import org.graalvm.util.EconomicMap;
47
48import jdk.vm.ci.code.Architecture;
49import jdk.vm.ci.meta.ResolvedJavaMethod;
50
51/**
52 * A graph decoder that provides all necessary encoded graphs on-the-fly (by parsing the methods and
53 * encoding the graphs).
54 */
55public class CachingPEGraphDecoder extends PEGraphDecoder {
56
57    protected final Providers providers;
58    protected final GraphBuilderConfiguration graphBuilderConfig;
59    protected final OptimisticOptimizations optimisticOpts;
60    private final AllowAssumptions allowAssumptions;
61    private final EconomicMap<ResolvedJavaMethod, EncodedGraph> graphCache;
62
63    public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
64                    AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
65                    ParameterPlugin parameterPlugin,
66                    NodePlugin[] nodePlugins) {
67        super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), loopExplosionPlugin,
68                        invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins);
69
70        this.providers = providers;
71        this.graphBuilderConfig = graphBuilderConfig;
72        this.optimisticOpts = optimisticOpts;
73        this.allowAssumptions = allowAssumptions;
74        this.graphCache = EconomicMap.create();
75    }
76
77    protected GraphBuilderPhase.Instance createGraphBuilderPhaseInstance(IntrinsicContext initialIntrinsicContext) {
78        return new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), graphBuilderConfig,
79                        optimisticOpts, initialIntrinsicContext);
80    }
81
82    @SuppressWarnings("try")
83    private EncodedGraph createGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) {
84        StructuredGraph graphToEncode = new StructuredGraph.Builder(options, debug, allowAssumptions).useProfilingInfo(false).method(method).build();
85        try (DebugContext.Scope scope = debug.scope("createGraph", graphToEncode)) {
86            IntrinsicContext initialIntrinsicContext = intrinsicBytecodeProvider != null ? new IntrinsicContext(method, method, intrinsicBytecodeProvider, INLINE_AFTER_PARSING) : null;
87            GraphBuilderPhase.Instance graphBuilderPhaseInstance = createGraphBuilderPhaseInstance(initialIntrinsicContext);
88            graphBuilderPhaseInstance.apply(graphToEncode);
89
90            PhaseContext context = new PhaseContext(providers);
91            new CanonicalizerPhase().apply(graphToEncode, context);
92            /*
93             * ConvertDeoptimizeToGuardPhase reduces the number of merges in the graph, so that
94             * fewer frame states will be created. This significantly reduces the number of nodes in
95             * the initial graph.
96             */
97            new ConvertDeoptimizeToGuardPhase().apply(graphToEncode, context);
98
99            EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graphToEncode, architecture);
100            graphCache.put(method, encodedGraph);
101            return encodedGraph;
102
103        } catch (Throwable ex) {
104            throw debug.handle(ex);
105        }
106    }
107
108    @Override
109    protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) {
110        EncodedGraph result = graphCache.get(method);
111        if (result == null && method.hasBytecodes()) {
112            result = createGraph(method, intrinsicBytecodeProvider);
113        }
114        return result;
115    }
116}
117