GraalCompiler.java revision 13083:b9a173f12fe6
1/*
2 * Copyright (c) 2009, 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.core;
24
25import java.util.Collection;
26import java.util.List;
27
28import org.graalvm.compiler.code.CompilationResult;
29import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext;
30import org.graalvm.compiler.core.common.GraalOptions;
31import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder;
32import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
33import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
34import org.graalvm.compiler.core.common.util.CompilationAlarm;
35import org.graalvm.compiler.core.target.Backend;
36import org.graalvm.compiler.debug.Debug;
37import org.graalvm.compiler.debug.Debug.Scope;
38import org.graalvm.compiler.debug.DebugCloseable;
39import org.graalvm.compiler.debug.DebugCounter;
40import org.graalvm.compiler.debug.DebugTimer;
41import org.graalvm.compiler.debug.GraalError;
42import org.graalvm.compiler.debug.MethodFilter;
43import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo;
44import org.graalvm.compiler.lir.LIR;
45import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
46import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
47import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
48import org.graalvm.compiler.lir.framemap.FrameMap;
49import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
50import org.graalvm.compiler.lir.gen.LIRGenerationResult;
51import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
52import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
53import org.graalvm.compiler.lir.phases.LIRSuites;
54import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
55import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
56import org.graalvm.compiler.nodes.StructuredGraph;
57import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
58import org.graalvm.compiler.nodes.cfg.Block;
59import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
60import org.graalvm.compiler.phases.OptimisticOptimizations;
61import org.graalvm.compiler.phases.PhaseSuite;
62import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
63import org.graalvm.compiler.phases.tiers.HighTierContext;
64import org.graalvm.compiler.phases.tiers.LowTierContext;
65import org.graalvm.compiler.phases.tiers.MidTierContext;
66import org.graalvm.compiler.phases.tiers.Suites;
67import org.graalvm.compiler.phases.tiers.TargetProvider;
68import org.graalvm.compiler.phases.util.Providers;
69import org.graalvm.util.EconomicSet;
70
71import jdk.vm.ci.code.RegisterConfig;
72import jdk.vm.ci.code.TargetDescription;
73import jdk.vm.ci.code.site.ConstantReference;
74import jdk.vm.ci.code.site.DataPatch;
75import jdk.vm.ci.meta.Assumptions;
76import jdk.vm.ci.meta.JavaConstant;
77import jdk.vm.ci.meta.JavaKind;
78import jdk.vm.ci.meta.ProfilingInfo;
79import jdk.vm.ci.meta.ResolvedJavaField;
80import jdk.vm.ci.meta.ResolvedJavaMethod;
81import jdk.vm.ci.meta.VMConstant;
82
83/**
84 * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}.
85 */
86public class GraalCompiler {
87
88    private static final DebugTimer CompilerTimer = Debug.timer("GraalCompiler");
89    private static final DebugTimer FrontEnd = Debug.timer("FrontEnd");
90    private static final DebugTimer BackEnd = Debug.timer("BackEnd");
91    private static final DebugTimer EmitLIR = Debug.timer("EmitLIR");
92    private static final DebugTimer EmitCode = Debug.timer("EmitCode");
93
94    /**
95     * Encapsulates all the inputs to a {@linkplain GraalCompiler#compile(Request) compilation}.
96     */
97    public static class Request<T extends CompilationResult> {
98        public final StructuredGraph graph;
99        public final ResolvedJavaMethod installedCodeOwner;
100        public final Providers providers;
101        public final Backend backend;
102        public final PhaseSuite<HighTierContext> graphBuilderSuite;
103        public final OptimisticOptimizations optimisticOpts;
104        public final ProfilingInfo profilingInfo;
105        public final Suites suites;
106        public final LIRSuites lirSuites;
107        public final T compilationResult;
108        public final CompilationResultBuilderFactory factory;
109
110        /**
111         * @param graph the graph to be compiled
112         * @param installedCodeOwner the method the compiled code will be associated with once
113         *            installed. This argument can be null.
114         * @param providers
115         * @param backend
116         * @param graphBuilderSuite
117         * @param optimisticOpts
118         * @param profilingInfo
119         * @param suites
120         * @param lirSuites
121         * @param compilationResult
122         * @param factory
123         */
124        public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite,
125                        OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) {
126            this.graph = graph;
127            this.installedCodeOwner = installedCodeOwner;
128            this.providers = providers;
129            this.backend = backend;
130            this.graphBuilderSuite = graphBuilderSuite;
131            this.optimisticOpts = optimisticOpts;
132            this.profilingInfo = profilingInfo;
133            this.suites = suites;
134            this.lirSuites = lirSuites;
135            this.compilationResult = compilationResult;
136            this.factory = factory;
137        }
138
139        /**
140         * Executes this compilation request.
141         *
142         * @return the result of the compilation
143         */
144        public T execute() {
145            return GraalCompiler.compile(this);
146        }
147    }
148
149    /**
150     * Requests compilation of a given graph.
151     *
152     * @param graph the graph to be compiled
153     * @param installedCodeOwner the method the compiled code will be associated with once
154     *            installed. This argument can be null.
155     * @return the result of the compilation
156     */
157    public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
158                    PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult,
159                    CompilationResultBuilderFactory factory) {
160        return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory));
161    }
162
163    /**
164     * Services a given compilation request.
165     *
166     * @return the result of the compilation
167     */
168    @SuppressWarnings("try")
169    public static <T extends CompilationResult> T compile(Request<T> r) {
170        try (Scope s = MethodMetricsRootScopeInfo.createRootScopeIfAbsent(r.installedCodeOwner);
171                        CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(r.graph.getOptions())) {
172            assert !r.graph.isFrozen();
173            try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start()) {
174                emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
175                emitBackEnd(r.graph, null, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, null, r.lirSuites);
176            } catch (Throwable e) {
177                throw Debug.handle(e);
178            }
179            checkForRequestedCrash(r.graph);
180            return r.compilationResult;
181        }
182    }
183
184    /**
185     * Checks whether the {@link GraalCompilerOptions#CrashAt} option indicates that the compilation
186     * of {@code graph} should result in an exception.
187     *
188     * @param graph a graph currently being compiled
189     * @throws RuntimeException if the value of {@link GraalCompilerOptions#CrashAt} matches
190     *             {@code graph.method()} or {@code graph.name}
191     */
192    private static void checkForRequestedCrash(StructuredGraph graph) {
193        String methodPattern = GraalCompilerOptions.CrashAt.getValue(graph.getOptions());
194        if (methodPattern != null) {
195            String crashLabel = null;
196            if (graph.name != null && graph.name.contains(methodPattern)) {
197                crashLabel = graph.name;
198            }
199            if (crashLabel == null) {
200                ResolvedJavaMethod method = graph.method();
201                MethodFilter[] filters = MethodFilter.parse(methodPattern);
202                for (MethodFilter filter : filters) {
203                    if (filter.matches(method)) {
204                        crashLabel = method.format("%H.%n(%p)");
205                    }
206                }
207            }
208            if (crashLabel != null) {
209                throw new RuntimeException("Forced crash after compiling " + crashLabel);
210            }
211        }
212    }
213
214    /**
215     * Builds the graph, optimizes it.
216     */
217    @SuppressWarnings("try")
218    public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
219                    ProfilingInfo profilingInfo, Suites suites) {
220        try (Scope s = Debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start()) {
221            HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
222            if (graph.start().next() == null) {
223                graphBuilderSuite.apply(graph, highTierContext);
224                new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph);
225                Debug.dump(Debug.BASIC_LEVEL, graph, "After parsing");
226            } else {
227                Debug.dump(Debug.INFO_LEVEL, graph, "initial state");
228            }
229
230            suites.getHighTier().apply(graph, highTierContext);
231            graph.maybeCompress();
232            Debug.dump(Debug.BASIC_LEVEL, graph, "After high tier");
233
234            MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo);
235            suites.getMidTier().apply(graph, midTierContext);
236            graph.maybeCompress();
237            Debug.dump(Debug.BASIC_LEVEL, graph, "After mid tier");
238
239            LowTierContext lowTierContext = new LowTierContext(providers, target);
240            suites.getLowTier().apply(graph, lowTierContext);
241            Debug.dump(Debug.BASIC_LEVEL, graph, "After low tier");
242
243            Debug.dump(Debug.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
244        } catch (Throwable e) {
245            throw Debug.handle(e);
246        } finally {
247            graph.checkCancellation();
248        }
249    }
250
251    @SuppressWarnings("try")
252    public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, ResolvedJavaMethod installedCodeOwner, Backend backend, T compilationResult,
253                    CompilationResultBuilderFactory factory, RegisterConfig registerConfig, LIRSuites lirSuites) {
254        try (Scope s = Debug.scope("BackEnd", graph.getLastSchedule()); DebugCloseable a = BackEnd.start()) {
255            LIRGenerationResult lirGen = null;
256            lirGen = emitLIR(backend, graph, stub, registerConfig, lirSuites);
257            try (Scope s2 = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
258                int bytecodeSize = graph.method() == null ? 0 : graph.getBytecodeSize();
259                compilationResult.setHasUnsafeAccess(graph.hasUnsafeAccess());
260                emitCode(backend, graph.getAssumptions(), graph.method(), graph.getMethods(), graph.getFields(), bytecodeSize, lirGen, compilationResult, installedCodeOwner, factory);
261            } catch (Throwable e) {
262                throw Debug.handle(e);
263            }
264        } catch (Throwable e) {
265            throw Debug.handle(e);
266        } finally {
267            graph.checkCancellation();
268        }
269    }
270
271    @SuppressWarnings("try")
272    public static LIRGenerationResult emitLIR(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites) {
273        String registerPressure = GraalOptions.RegisterPressure.getValue(graph.getOptions());
274        String[] allocationRestrictedTo = registerPressure == null ? null : registerPressure.split(",");
275        try {
276            return emitLIR0(backend, graph, stub, registerConfig, lirSuites, allocationRestrictedTo);
277        } catch (OutOfRegistersException e) {
278            if (allocationRestrictedTo != null) {
279                allocationRestrictedTo = null;
280                return emitLIR0(backend, graph, stub, registerConfig, lirSuites, allocationRestrictedTo);
281            }
282            /* If the re-execution fails we convert the exception into a "hard" failure */
283            throw new GraalError(e);
284        } finally {
285            graph.checkCancellation();
286        }
287    }
288
289    @SuppressWarnings("try")
290    private static LIRGenerationResult emitLIR0(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites,
291                    String[] allocationRestrictedTo) {
292        try (Scope ds = Debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start()) {
293            assert !graph.hasValueProxies();
294            ScheduleResult schedule = graph.getLastSchedule();
295            Block[] blocks = schedule.getCFG().getBlocks();
296            Block startBlock = schedule.getCFG().getStartBlock();
297            assert startBlock != null;
298            assert startBlock.getPredecessorCount() == 0;
299
300            AbstractBlockBase<?>[] codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
301            AbstractBlockBase<?>[] linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
302            LIR lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder, graph.getOptions());
303
304            FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
305            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(graph.compilationId(), lir, frameMapBuilder, graph, stub);
306            LIRGeneratorTool lirGen = backend.newLIRGenerator(lirGenRes);
307            NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
308
309            // LIR generation
310            LIRGenerationContext context = new LIRGenerationContext(lirGen, nodeLirGen, graph, schedule);
311            new LIRGenerationPhase().apply(backend.getTarget(), lirGenRes, context);
312
313            try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) {
314                // Dump LIR along with HIR (the LIR is looked up from context)
315                Debug.dump(Debug.BASIC_LEVEL, graph.getLastSchedule(), "After LIR generation");
316                LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig, allocationRestrictedTo));
317                return result;
318            } catch (Throwable e) {
319                throw Debug.handle(e);
320            }
321        } catch (Throwable e) {
322            throw Debug.handle(e);
323        } finally {
324            graph.checkCancellation();
325        }
326    }
327
328    protected static <T extends CompilationResult> String getCompilationUnitName(StructuredGraph graph, T compilationResult) {
329        if (compilationResult != null && compilationResult.getName() != null) {
330            return compilationResult.getName();
331        }
332        ResolvedJavaMethod method = graph.method();
333        if (method == null) {
334            return "<unknown>";
335        }
336        return method.format("%H.%n(%p)");
337    }
338
339    public static LIRGenerationResult emitLowLevel(TargetDescription target, LIRGenerationResult lirGenRes, LIRGeneratorTool lirGen, LIRSuites lirSuites,
340                    RegisterAllocationConfig registerAllocationConfig) {
341        PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen);
342        lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, preAllocOptContext);
343        Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "After PreAllocationOptimizationStage");
344
345        AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig);
346        lirSuites.getAllocationStage().apply(target, lirGenRes, allocContext);
347        Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "After AllocationStage");
348
349        PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen);
350        lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, postAllocOptContext);
351        Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "After PostAllocationOptimizationStage");
352
353        return lirGenRes;
354    }
355
356    @SuppressWarnings("try")
357    public static void emitCode(Backend backend, Assumptions assumptions, ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods, EconomicSet<ResolvedJavaField> accessedFields,
358                    int bytecodeSize, LIRGenerationResult lirGenRes,
359                    CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, CompilationResultBuilderFactory factory) {
360        try (DebugCloseable a = EmitCode.start()) {
361            FrameMap frameMap = lirGenRes.getFrameMap();
362            CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, frameMap, compilationResult, factory);
363            backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner);
364            if (assumptions != null && !assumptions.isEmpty()) {
365                compilationResult.setAssumptions(assumptions.toArray());
366            }
367            if (rootMethod != null) {
368                compilationResult.setMethods(rootMethod, inlinedMethods);
369                compilationResult.setFields(accessedFields);
370                compilationResult.setBytecodeSize(bytecodeSize);
371            }
372            crb.finish();
373            if (Debug.isCountEnabled()) {
374                List<DataPatch> ldp = compilationResult.getDataPatches();
375                JavaKind[] kindValues = JavaKind.values();
376                DebugCounter[] dms = new DebugCounter[kindValues.length];
377                for (int i = 0; i < dms.length; i++) {
378                    dms[i] = Debug.counter("DataPatches-%s", kindValues[i]);
379                }
380
381                for (DataPatch dp : ldp) {
382                    JavaKind kind = JavaKind.Illegal;
383                    if (dp.reference instanceof ConstantReference) {
384                        VMConstant constant = ((ConstantReference) dp.reference).getConstant();
385                        if (constant instanceof JavaConstant) {
386                            kind = ((JavaConstant) constant).getJavaKind();
387                        }
388                    }
389                    dms[kind.ordinal()].add(1);
390                }
391
392                Debug.counter("CompilationResults").increment();
393                Debug.counter("CodeBytesEmitted").add(compilationResult.getTargetCodeSize());
394                Debug.counter("InfopointsEmitted").add(compilationResult.getInfopoints().size());
395                Debug.counter("DataPatches").add(ldp.size());
396                Debug.counter("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size());
397            }
398
399            Debug.dump(Debug.BASIC_LEVEL, compilationResult, "After code generation");
400        }
401    }
402}
403