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}