001/* 002 * Copyright (c) 2015, 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 com.oracle.truffle.api.*; 026import com.oracle.truffle.api.frame.*; 027import com.oracle.truffle.api.nodes.*; 028 029public final class OptimizedOSRLoopNode extends LoopNode implements ReplaceObserver { 030 031 private int interpreterLoopCount; 032 private OptimizedCallTarget compiledTarget; 033 034 @Child private RepeatingNode repeatableNode; 035 036 private OptimizedOSRLoopNode(RepeatingNode repeatableNode) { 037 this.repeatableNode = repeatableNode; 038 } 039 040 @Override 041 public Node copy() { 042 OptimizedOSRLoopNode copy = (OptimizedOSRLoopNode) super.copy(); 043 copy.compiledTarget = null; 044 copy.interpreterLoopCount = 0; 045 return copy; 046 } 047 048 @Override 049 public RepeatingNode getRepeatingNode() { 050 return repeatableNode; 051 } 052 053 @Override 054 public void executeLoop(VirtualFrame frame) { 055 if (CompilerDirectives.inInterpreter()) { 056 boolean done = false; 057 while (!done) { 058 if (compiledTarget == null) { 059 done = profilingLoop(frame); 060 } else { 061 done = compilingLoop(frame); 062 } 063 } 064 } else { 065 while (repeatableNode.executeRepeating(frame)) { 066 if (CompilerDirectives.inInterpreter()) { 067 // compiled method got invalidated. We might need OSR again. 068 executeLoop(frame); 069 return; 070 } 071 } 072 } 073 } 074 075 private boolean profilingLoop(VirtualFrame frame) { 076 int osrThreshold = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue(); 077 int overflowLoopCount = Integer.MAX_VALUE - osrThreshold + interpreterLoopCount; 078 try { 079 while (repeatableNode.executeRepeating(frame)) { 080 try { 081 overflowLoopCount = Math.incrementExact(overflowLoopCount); 082 } catch (ArithmeticException e) { 083 compileLoop(frame); 084 return false; 085 } 086 } 087 } finally { 088 reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + osrThreshold - interpreterLoopCount); 089 } 090 return true; 091 } 092 093 private boolean compilingLoop(VirtualFrame frame) { 094 int iterations = 0; 095 try { 096 do { 097 OptimizedCallTarget target = compiledTarget; 098 if (target == null) { 099 return false; 100 } else if (target.isValid()) { 101 Object result = target.callDirect(new Object[]{frame}); 102 if (result == Boolean.TRUE) { 103 // loop is done. No further repetitions necessary. 104 return true; 105 } else { 106 invalidate(this, "OSR compilation got invalidated"); 107 return false; 108 } 109 } else if (!target.isCompiling()) { 110 invalidate(this, "OSR compilation failed or cancelled"); 111 return false; 112 } 113 iterations++; 114 } while (repeatableNode.executeRepeating(frame)); 115 } finally { 116 reportLoopCount(iterations); 117 } 118 return true; 119 } 120 121 private void compileLoop(VirtualFrame frame) { 122 atomic(new Runnable() { 123 public void run() { 124 /* 125 * Compilations need to run atomically as they may be scheduled by multiple threads 126 * at the same time. This strategy lets the first thread win. Later threads will not 127 * issue compiles. 128 */ 129 if (compiledTarget == null) { 130 compiledTarget = compileImpl(frame); 131 if (compiledTarget == null) { 132 interpreterLoopCount = 0; 133 } 134 } 135 } 136 }); 137 } 138 139 private OptimizedCallTarget compileImpl(VirtualFrame frame) { 140 Node parent = getParent(); 141 OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new OSRRootNode(this)); 142 // to avoid a deopt on first call we provide some profiling information 143 target.profileReturnType(Boolean.TRUE); 144 target.profileReturnType(Boolean.FALSE); 145 target.profileArguments(new Object[]{frame}); 146 // let the old parent re-adopt the children 147 parent.adoptChildren(); 148 target.compile(); 149 return target; 150 } 151 152 private void reportLoopCount(int reportIterations) { 153 if (reportIterations != 0) { 154 interpreterLoopCount += reportIterations; 155 getRootNode().reportLoopCount(reportIterations); 156 } 157 } 158 159 public boolean nodeReplaced(Node oldNode, Node newNode, CharSequence reason) { 160 invalidate(newNode, reason); 161 return false; 162 } 163 164 private void invalidate(Object source, CharSequence reason) { 165 OptimizedCallTarget target = this.compiledTarget; 166 if (target != null) { 167 target.invalidate(source, reason); 168 compiledTarget = null; 169 interpreterLoopCount = 0; 170 } 171 } 172 173 public static LoopNode create(RepeatingNode repeat) { 174 if (TruffleCompilerOptions.TruffleOSR.getValue()) { 175 return new OptimizedOSRLoopNode(repeat); 176 } else { 177 return new OptimizedLoopNode(repeat); 178 } 179 } 180 181 private static class OSRRootNode extends RootNode { 182 183 @Child private OptimizedOSRLoopNode loopNode; 184 185 public OSRRootNode(OptimizedOSRLoopNode loop) { 186 super(TruffleLanguage.class, loop.getSourceSection(), loop.getRootNode().getFrameDescriptor()); 187 this.loopNode = loop; 188 } 189 190 @Override 191 public Object execute(VirtualFrame frame) { 192 VirtualFrame parentFrame = (VirtualFrame) frame.getArguments()[0]; 193 while (loopNode.getRepeatingNode().executeRepeating(parentFrame)) { 194 if (CompilerDirectives.inInterpreter()) { 195 return Boolean.FALSE; 196 } 197 } 198 return Boolean.TRUE; 199 } 200 201 @Override 202 public boolean isCloningAllowed() { 203 return false; 204 } 205 206 @Override 207 public String toString() { 208 return loopNode.getRepeatingNode().toString() + "<OSR>"; 209 } 210 211 } 212 213}