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.truffle.TruffleCompilerOptions.*;
026
027import java.util.*;
028import java.util.concurrent.*;
029
030import jdk.internal.jvmci.code.*;
031import jdk.internal.jvmci.code.stack.*;
032import jdk.internal.jvmci.meta.*;
033import jdk.internal.jvmci.service.*;
034
035import com.oracle.graal.api.runtime.*;
036import com.oracle.graal.debug.*;
037import com.oracle.graal.debug.Debug.Scope;
038import com.oracle.graal.nodes.*;
039import com.oracle.graal.truffle.debug.*;
040import com.oracle.graal.truffle.unsafe.*;
041import com.oracle.truffle.api.*;
042import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
043import com.oracle.truffle.api.frame.*;
044import com.oracle.truffle.api.nodes.*;
045import com.oracle.truffle.api.unsafe.*;
046
047public abstract class GraalTruffleRuntime implements TruffleRuntime {
048
049    public static TruffleRuntime alternateRuntime;
050
051    private ArrayList<String> includes;
052    private ArrayList<String> excludes;
053
054    private StackIntrospection stackIntrospection;
055    protected ResolvedJavaMethod[] callNodeMethod;
056    protected ResolvedJavaMethod[] callTargetMethod;
057    protected ResolvedJavaMethod[] anyFrameMethod;
058
059    private final List<GraalTruffleCompilationListener> compilationListeners = new ArrayList<>();
060    private final GraalTruffleCompilationListener compilationNotify = new DispatchTruffleCompilationListener();
061
062    protected TruffleCompiler truffleCompiler;
063    protected LoopNodeFactory loopNodeFactory;
064
065    public GraalTruffleRuntime() {
066        Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
067    }
068
069    public abstract TruffleCompiler getTruffleCompiler();
070
071    private static <T extends PrioritizedServiceProvider> T loadPrioritizedServiceProvider(Class<T> clazz) {
072        Iterable<T> providers = Services.load(clazz);
073        T bestFactory = null;
074        for (T factory : providers) {
075            if (bestFactory == null) {
076                bestFactory = factory;
077            } else if (factory.getPriority() > bestFactory.getPriority()) {
078                bestFactory = factory;
079            }
080        }
081        if (bestFactory == null) {
082            throw new IllegalStateException("Unable to load a factory for " + clazz.getName());
083        }
084        return bestFactory;
085    }
086
087    public void log(String message) {
088        TTY.out().println(message);
089    }
090
091    protected void installDefaultListeners() {
092        TraceCompilationFailureListener.install(this);
093        TraceCompilationListener.install(this);
094        TraceCompilationPolymorphismListener.install(this);
095        TraceCompilationCallTreeListener.install(this);
096        TracePerformanceWarningsListener.install(this);
097        TraceInliningListener.install(this);
098        TraceSplittingListener.install(this);
099        PrintCallTargetProfiling.install(this);
100        CompilationStatisticsListener.install(this);
101        compilationNotify.notifyStartup(this);
102    }
103
104    protected void lookupCallMethods(MetaAccessProvider metaAccess) {
105        callNodeMethod = new ResolvedJavaMethod[]{metaAccess.lookupJavaMethod(GraalFrameInstance.CallNodeFrame.METHOD)};
106        callTargetMethod = new ResolvedJavaMethod[]{metaAccess.lookupJavaMethod(GraalFrameInstance.CallTargetFrame.METHOD)};
107        anyFrameMethod = new ResolvedJavaMethod[]{callNodeMethod[0], callTargetMethod[0]};
108    }
109
110    @Override
111    public LoopNode createLoopNode(RepeatingNode repeatingNode) {
112        if (!(repeatingNode instanceof Node)) {
113            throw new IllegalArgumentException("Repeating node must be of type Node.");
114        }
115        return getLoopNodeFactory().create(repeatingNode);
116    }
117
118    protected LoopNodeFactory getLoopNodeFactory() {
119        if (loopNodeFactory == null) {
120            loopNodeFactory = loadPrioritizedServiceProvider(LoopNodeFactory.class);
121        }
122        return loopNodeFactory;
123    }
124
125    @Override
126    public DirectCallNode createDirectCallNode(CallTarget target) {
127        if (target instanceof OptimizedCallTarget) {
128            return new OptimizedDirectCallNode(this, (OptimizedCallTarget) target);
129        } else {
130            throw new IllegalStateException(String.format("Unexpected call target class %s!", target.getClass()));
131        }
132    }
133
134    @Override
135    public IndirectCallNode createIndirectCallNode() {
136        return new OptimizedIndirectCallNode();
137    }
138
139    @Override
140    public VirtualFrame createVirtualFrame(Object[] arguments, FrameDescriptor frameDescriptor) {
141        return OptimizedCallTarget.createFrame(frameDescriptor, arguments);
142    }
143
144    @Override
145    public MaterializedFrame createMaterializedFrame(Object[] arguments) {
146        return createMaterializedFrame(arguments, new FrameDescriptor());
147    }
148
149    @Override
150    public MaterializedFrame createMaterializedFrame(Object[] arguments, FrameDescriptor frameDescriptor) {
151        if (TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue()) {
152            return new FrameWithoutBoxing(frameDescriptor, arguments);
153        } else {
154            return new FrameWithBoxing(frameDescriptor, arguments);
155        }
156    }
157
158    @Override
159    public CompilerOptions createCompilerOptions() {
160        return new GraalCompilerOptions();
161    }
162
163    @Override
164    public Assumption createAssumption() {
165        return createAssumption(null);
166    }
167
168    @Override
169    public Assumption createAssumption(String name) {
170        return new OptimizedAssumption(name);
171    }
172
173    public GraalTruffleCompilationListener getCompilationNotify() {
174        return compilationNotify;
175    }
176
177    @TruffleBoundary
178    @Override
179    public <T> T iterateFrames(FrameInstanceVisitor<T> visitor) {
180        initStackIntrospection();
181
182        InspectedFrameVisitor<T> inspectedFrameVisitor = new InspectedFrameVisitor<T>() {
183            private boolean skipNext = false;
184
185            public T visitFrame(InspectedFrame frame) {
186                if (skipNext) {
187                    assert frame.isMethod(callTargetMethod[0]);
188                    skipNext = false;
189                    return null;
190                }
191
192                if (frame.isMethod(callNodeMethod[0])) {
193                    skipNext = true;
194                    return visitor.visitFrame(new GraalFrameInstance.CallNodeFrame(frame));
195                } else {
196                    assert frame.isMethod(callTargetMethod[0]);
197                    return visitor.visitFrame(new GraalFrameInstance.CallTargetFrame(frame, false));
198                }
199
200            }
201        };
202        return stackIntrospection.iterateFrames(anyFrameMethod, anyFrameMethod, 1, inspectedFrameVisitor);
203    }
204
205    private void initStackIntrospection() {
206        if (stackIntrospection == null) {
207            stackIntrospection = Graal.getRequiredCapability(StackIntrospection.class);
208        }
209    }
210
211    @Override
212    public FrameInstance getCallerFrame() {
213        return iterateFrames(frame -> frame);
214    }
215
216    @TruffleBoundary
217    @Override
218    public FrameInstance getCurrentFrame() {
219        initStackIntrospection();
220
221        return stackIntrospection.iterateFrames(callTargetMethod, callTargetMethod, 0, frame -> new GraalFrameInstance.CallTargetFrame(frame, true));
222    }
223
224    public <T> T getCapability(Class<T> capability) {
225        if (capability == UnsafeAccessFactory.class) {
226            return capability.cast(new UnsafeAccessFactoryImpl());
227        }
228        return null;
229    }
230
231    protected boolean acceptForCompilation(RootNode rootNode) {
232        if (TruffleCompileOnly.getValue() != null) {
233            if (includes == null) {
234                parseCompileOnly();
235            }
236
237            String name = rootNode.toString();
238            boolean included = includes.isEmpty();
239            for (int i = 0; !included && i < includes.size(); i++) {
240                if (name.contains(includes.get(i))) {
241                    included = true;
242                }
243            }
244            if (!included) {
245                return false;
246            }
247            for (String exclude : excludes) {
248                if (name.contains(exclude)) {
249                    return false;
250                }
251            }
252        }
253        return true;
254    }
255
256    protected void parseCompileOnly() {
257        includes = new ArrayList<>();
258        excludes = new ArrayList<>();
259
260        String[] items = TruffleCompileOnly.getValue().split(",");
261        for (String item : items) {
262            if (item.startsWith("~")) {
263                excludes.add(item.substring(1));
264            } else {
265                includes.add(item);
266            }
267        }
268    }
269
270    public abstract RootCallTarget createClonedCallTarget(OptimizedCallTarget sourceCallTarget, RootNode root);
271
272    public void addCompilationListener(GraalTruffleCompilationListener listener) {
273        compilationListeners.add(listener);
274    }
275
276    public void removeCompilationListener(GraalTruffleCompilationListener listener) {
277        compilationListeners.remove(listener);
278    }
279
280    private void shutdown() {
281        getCompilationNotify().notifyShutdown(this);
282    }
283
284    public abstract Collection<OptimizedCallTarget> getQueuedCallTargets();
285
286    public abstract void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous);
287
288    protected void doCompile(OptimizedCallTarget optimizedCallTarget) {
289        boolean success = true;
290        try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) {
291            truffleCompiler.compileMethod(optimizedCallTarget);
292        } catch (Throwable e) {
293            optimizedCallTarget.notifyCompilationFailed(e);
294            success = false;
295        } finally {
296            optimizedCallTarget.notifyCompilationFinished(success);
297        }
298    }
299
300    public abstract boolean cancelInstalledTask(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason);
301
302    public abstract void waitForCompilation(OptimizedCallTarget optimizedCallTarget, long timeout) throws ExecutionException, TimeoutException;
303
304    public abstract boolean isCompiling(OptimizedCallTarget optimizedCallTarget);
305
306    public abstract void invalidateInstalledCode(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason);
307
308    public abstract void reinstallStubs();
309
310    public final boolean enableInfopoints() {
311        /* Currently infopoints can change code generation so don't enable them automatically */
312        return platformEnableInfopoints() && TruffleEnableInfopoints.getValue();
313    }
314
315    protected abstract boolean platformEnableInfopoints();
316
317    private final class DispatchTruffleCompilationListener implements GraalTruffleCompilationListener {
318
319        public void notifyCompilationQueued(OptimizedCallTarget target) {
320            compilationListeners.forEach(l -> l.notifyCompilationQueued(target));
321        }
322
323        public void notifyCompilationInvalidated(OptimizedCallTarget target, Object source, CharSequence reason) {
324            compilationListeners.forEach(l -> l.notifyCompilationInvalidated(target, source, reason));
325        }
326
327        public void notifyCompilationDequeued(OptimizedCallTarget target, Object source, CharSequence reason) {
328            compilationListeners.forEach(l -> l.notifyCompilationDequeued(target, source, reason));
329        }
330
331        public void notifyCompilationFailed(OptimizedCallTarget target, StructuredGraph graph, Throwable t) {
332            compilationListeners.forEach(l -> l.notifyCompilationFailed(target, graph, t));
333        }
334
335        public void notifyCompilationSplit(OptimizedDirectCallNode callNode) {
336            compilationListeners.forEach(l -> l.notifyCompilationSplit(callNode));
337        }
338
339        public void notifyCompilationGraalTierFinished(OptimizedCallTarget target, StructuredGraph graph) {
340            compilationListeners.forEach(l -> l.notifyCompilationGraalTierFinished(target, graph));
341        }
342
343        public void notifyCompilationSuccess(OptimizedCallTarget target, StructuredGraph graph, CompilationResult result) {
344            compilationListeners.forEach(l -> l.notifyCompilationSuccess(target, graph, result));
345        }
346
347        public void notifyCompilationStarted(OptimizedCallTarget target) {
348            compilationListeners.forEach(l -> l.notifyCompilationStarted(target));
349        }
350
351        public void notifyCompilationTruffleTierFinished(OptimizedCallTarget target, StructuredGraph graph) {
352            compilationListeners.forEach(l -> l.notifyCompilationTruffleTierFinished(target, graph));
353        }
354
355        public void notifyShutdown(GraalTruffleRuntime runtime) {
356            compilationListeners.forEach(l -> l.notifyShutdown(runtime));
357        }
358
359        public void notifyStartup(GraalTruffleRuntime runtime) {
360            compilationListeners.forEach(l -> l.notifyStartup(runtime));
361        }
362
363    }
364}