001/*
002 * Copyright (c) 2013, 2014, 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.truffle;
024
025import static com.oracle.graal.compiler.GraalCompiler.*;
026import static jdk.internal.jvmci.code.CodeUtil.*;
027
028import java.util.*;
029
030import jdk.internal.jvmci.code.*;
031import jdk.internal.jvmci.code.CallingConvention.*;
032import com.oracle.graal.debug.*;
033import com.oracle.graal.debug.Debug.*;
034import jdk.internal.jvmci.meta.*;
035import jdk.internal.jvmci.meta.Assumptions.Assumption;
036
037import com.oracle.graal.compiler.target.*;
038import com.oracle.graal.graphbuilderconf.*;
039import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
040import com.oracle.graal.lir.asm.*;
041import com.oracle.graal.lir.phases.*;
042import com.oracle.graal.nodes.*;
043import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
044import com.oracle.graal.phases.*;
045import com.oracle.graal.phases.tiers.*;
046import com.oracle.graal.phases.util.*;
047import com.oracle.graal.truffle.nodes.*;
048import com.oracle.truffle.api.*;
049import com.oracle.truffle.api.nodes.*;
050
051/**
052 * Implementation of the Truffle compiler using Graal.
053 */
054public abstract class TruffleCompiler {
055
056    protected final Providers providers;
057    protected final Suites suites;
058    protected final GraphBuilderConfiguration config;
059    protected final LIRSuites lirSuites;
060    protected final PartialEvaluator partialEvaluator;
061    protected final Backend backend;
062    protected final GraalTruffleCompilationListener compilationNotify;
063
064    // @formatter:off
065    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{
066        UnexpectedResultException.class,
067        SlowPathException.class,
068        ArithmeticException.class,
069        IllegalArgumentException.class,
070        VirtualMachineError.class,
071        StringIndexOutOfBoundsException.class,
072        ClassCastException.class
073    };
074    // @formatter:on
075
076    public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
077                    OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
078
079    public TruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) {
080        GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime());
081        this.compilationNotify = graalTruffleRuntime.getCompilationNotify();
082        this.backend = backend;
083        Providers backendProviders = backend.getProviders();
084        ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess());
085        this.providers = backendProviders.copyWith(constantReflection);
086        this.suites = suites;
087        this.lirSuites = lirSuites;
088
089        ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
090
091        GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(new Plugins(plugins))
092                        : GraphBuilderConfiguration.getDefault(new Plugins(plugins));
093        this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes).withOmitAssertions(TruffleCompilerOptions.TruffleExcludeAssertions.getValue());
094
095        this.partialEvaluator = createPartialEvaluator();
096
097        if (Debug.isEnabled()) {
098            DebugEnvironment.initialize(System.out);
099        }
100    }
101
102    public GraphBuilderConfiguration getGraphBuilderConfiguration() {
103        return config;
104    }
105
106    protected abstract PartialEvaluator createPartialEvaluator();
107
108    public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) {
109        ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length];
110        for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) {
111            skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]);
112        }
113        return skippedExceptionTypes;
114    }
115
116    public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime");
117    public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
118    public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
119
120    public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse");
121    public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse");
122    public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse");
123
124    public void compileMethod(final OptimizedCallTarget compilable) {
125        StructuredGraph graph = null;
126
127        compilationNotify.notifyCompilationStarted(compilable);
128
129        try {
130            PhaseSuite<HighTierContext> graphBuilderSuite = createGraphBuilderSuite();
131
132            try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) {
133                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES);
134            }
135
136            if (Thread.currentThread().isInterrupted()) {
137                return;
138            }
139
140            compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph);
141            CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable);
142            compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult);
143        } catch (Throwable t) {
144            System.out.println("compilation failed!?");
145            compilationNotify.notifyCompilationFailed(compilable, graph, t);
146            throw t;
147        }
148    }
149
150    public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite<HighTierContext> graphBuilderSuite, InstalledCode predefinedInstalledCode) {
151        try (Scope s = Debug.scope("TruffleFinal")) {
152            Debug.dump(1, graph, "After TruffleTier");
153        } catch (Throwable e) {
154            throw Debug.handle(e);
155        }
156
157        CompilationResult result = null;
158        try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) {
159            SpeculationLog speculationLog = graph.getSpeculationLog();
160            if (speculationLog != null) {
161                speculationLog.collectFailedSpeculations();
162            }
163
164            CodeCacheProvider codeCache = providers.getCodeCache();
165            CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
166            CompilationResult compilationResult = new CompilationResult(name);
167            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), suites, lirSuites,
168                            compilationResult, CompilationResultBuilderFactory.Default);
169        } catch (Throwable e) {
170            throw Debug.handle(e);
171        }
172
173        compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph);
174
175        if (graph.isInlinedMethodRecordingEnabled()) {
176            result.setMethods(graph.method(), graph.getInlinedMethods());
177            result.setBytecodeSize(graph.getBytecodeSize());
178        } else {
179            assert result.getMethods() == null;
180        }
181
182        List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
183        Set<Assumption> newAssumptions = new HashSet<>();
184        for (Assumption assumption : graph.getAssumptions()) {
185            processAssumption(newAssumptions, assumption, validAssumptions);
186        }
187
188        if (result.getAssumptions() != null) {
189            for (Assumption assumption : result.getAssumptions()) {
190                processAssumption(newAssumptions, assumption, validAssumptions);
191            }
192        }
193
194        result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()]));
195
196        InstalledCode installedCode;
197        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) {
198            installedCode = providers.getCodeCache().addMethod(graph.method(), result, graph.getSpeculationLog(), predefinedInstalledCode);
199        } catch (Throwable e) {
200            throw Debug.handle(e);
201        }
202
203        for (AssumptionValidAssumption a : validAssumptions) {
204            a.getAssumption().registerInstalledCode(installedCode);
205        }
206
207        return result;
208    }
209
210    protected abstract PhaseSuite<HighTierContext> createGraphBuilderSuite();
211
212    public void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
213        if (assumption != null) {
214            if (assumption instanceof AssumptionValidAssumption) {
215                AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption;
216                manual.add(assumptionValidAssumption);
217            } else {
218                newAssumptions.add(assumption);
219            }
220        }
221    }
222
223    public PartialEvaluator getPartialEvaluator() {
224        return partialEvaluator;
225    }
226}