comparison graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java @ 6389:2d84f74e394c

enabled type-filter based logging of (snippet-based) monitor operations with the "graal.monitorsnippets.log" system property
author Doug Simon <doug.simon@oracle.com>
date Fri, 14 Sep 2012 10:52:30 +0200
parents abeeb57b655d
children b74402a7079b
comparison
equal deleted inserted replaced
6388:6b74f44c5059 6389:2d84f74e394c
39 import com.oracle.graal.hotspot.nodes.*; 39 import com.oracle.graal.hotspot.nodes.*;
40 import com.oracle.graal.nodes.*; 40 import com.oracle.graal.nodes.*;
41 import com.oracle.graal.nodes.java.*; 41 import com.oracle.graal.nodes.java.*;
42 import com.oracle.graal.nodes.spi.*; 42 import com.oracle.graal.nodes.spi.*;
43 import com.oracle.graal.snippets.*; 43 import com.oracle.graal.snippets.*;
44 import com.oracle.graal.snippets.Snippet.*; 44 import com.oracle.graal.snippets.Snippet.ConstantParameter;
45 import com.oracle.graal.snippets.Snippet.Parameter;
45 import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; 46 import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates;
46 import com.oracle.graal.snippets.SnippetTemplate.Arguments; 47 import com.oracle.graal.snippets.SnippetTemplate.Arguments;
47 import com.oracle.graal.snippets.SnippetTemplate.Key; 48 import com.oracle.graal.snippets.SnippetTemplate.Key;
48 49
49 /** 50 /**
53 * Eliminating synchronization-related atomic operations with biased locking and bulk rebiasing</a> 54 * Eliminating synchronization-related atomic operations with biased locking and bulk rebiasing</a>
54 * by Kenneth Russell and David Detlefs. 55 * by Kenneth Russell and David Detlefs.
55 */ 56 */
56 public class MonitorSnippets implements SnippetsInterface { 57 public class MonitorSnippets implements SnippetsInterface {
57 58
58 private static final boolean LOG = Boolean.getBoolean("graal.monitorsnippets.log"); 59 /**
59 60 * Monitor operations on objects whose type contains this substring will be logged.
60 private static void log(String action, Object object) { 61 */
61 if (LOG) { 62 private static final String LOG_TYPE = System.getProperty("graal.monitorsnippets.log");
63
64 private static void log(boolean enabled, String action, Object object) {
65 if (enabled) {
62 Log.print(action); 66 Log.print(action);
63 Log.print(' '); 67 Log.print(' ');
64 Log.printlnAddress(object); 68 Log.printlnObject(object);
65 } 69 }
66 } 70 }
67 71
68 @Snippet 72 @Snippet
69 public static void monitorenter(@Parameter("object") Object object) { 73 public static void monitorenter(@Parameter("object") Object object, @ConstantParameter("logEnabled") boolean logEnabled) {
70 verifyOop(object); 74 verifyOop(object);
71 75
72 // Load the mark word - this includes a null-check on object 76 // Load the mark word - this includes a null-check on object
73 final Word mark = asWord(loadObject(object, 0, markOffset(), false)); 77 final Word mark = asWord(loadObject(object, 0, markOffset(), false));
74 78
77 if (useBiasedLocking()) { 81 if (useBiasedLocking()) {
78 // See whether the lock is currently biased toward our thread and 82 // See whether the lock is currently biased toward our thread and
79 // whether the epoch is still valid. 83 // whether the epoch is still valid.
80 // Note that the runtime guarantees sufficient alignment of JavaThread 84 // Note that the runtime guarantees sufficient alignment of JavaThread
81 // pointers to allow age to be placed into low bits. 85 // pointers to allow age to be placed into low bits.
82 final Word biasedLockMark = mark.and(biasedLockMaskInPlace()); 86 final Word biasableLockBits = mark.and(biasedLockMaskInPlace());
83 87
84 // First check to see whether biasing is enabled for this object 88 // First check to see whether biasing is enabled for this object
85 if (biasedLockMark.toLong() != biasedLockPattern()) { 89 if (biasableLockBits.toLong() != biasedLockPattern()) {
86 // Biasing not enabled -> fall through to lightweight locking 90 // Biasing not enabled -> fall through to lightweight locking
87 } else { 91 } else {
88 // The bias pattern is present in the object's mark word. Need to check 92 // The bias pattern is present in the object's mark word. Need to check
89 // whether the bias owner and the epoch are both still current. 93 // whether the bias owner and the epoch are both still current.
90 Object hub = loadHub(object); 94 Object hub = loadHub(object);
91 final Word prototypeMarkWord = asWord(loadObject(hub, 0, prototypeMarkWordOffset(), true)); 95 final Word prototypeMarkWord = asWord(loadObject(hub, 0, prototypeMarkWordOffset(), true));
92 final Word thread = asWord(register(threadReg(), wordKind())); 96 final Word thread = asWord(register(threadReg(), wordKind()));
93 final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace()); 97 final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace());
94 if (tmp == Word.zero()) { 98 if (tmp == Word.zero()) {
95 // Object is already biased to current thread -> done 99 // Object is already biased to current thread -> done
96 log("+lock{bias}", object); 100 log(logEnabled, "+lock{bias}", object);
97 return; 101 return;
98 } 102 }
99 103
100 // At this point we know that the mark word has the bias pattern and 104 // At this point we know that the mark word has the bias pattern and
101 // that we are not the bias owner in the current epoch. We need to 105 // that we are not the bias owner in the current epoch. We need to
121 // don't accidentally blow away another thread's valid bias. 125 // don't accidentally blow away another thread's valid bias.
122 Word unbiasedMark = mark.and(biasedLockMaskInPlace() | ageMaskInPlace() | epochMaskInPlace()); 126 Word unbiasedMark = mark.and(biasedLockMaskInPlace() | ageMaskInPlace() | epochMaskInPlace());
123 Word biasedMark = unbiasedMark.or(thread); 127 Word biasedMark = unbiasedMark.or(thread);
124 if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark) == unbiasedMark) { 128 if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark) == unbiasedMark) {
125 // Object is now biased to current thread -> done 129 // Object is now biased to current thread -> done
126 log("+lock{bias}", object); 130 log(logEnabled, "+lock{bias}", object);
127 return; 131 return;
128 } 132 }
129 // If the biasing toward our thread failed, this means that 133 // If the biasing toward our thread failed, this means that
130 // another thread succeeded in biasing it toward itself and we 134 // another thread succeeded in biasing it toward itself and we
131 // need to revoke that bias. The revocation will occur in the 135 // need to revoke that bias. The revocation will occur in the
132 // interpreter runtime in the slow case. 136 // interpreter runtime in the slow case.
133 log("+lock{stub}", object); 137 log(logEnabled, "+lock{stub}", object);
134 MonitorEnterStubCall.call(object, lock); 138 MonitorEnterStubCall.call(object, lock);
135 return; 139 return;
136 } else { 140 } else {
137 // At this point we know the epoch has expired, meaning that the 141 // At this point we know the epoch has expired, meaning that the
138 // current "bias owner", if any, is actually invalid. Under these 142 // current "bias owner", if any, is actually invalid. Under these
141 // bias in the current epoch. In other words, we allow transfer of 145 // bias in the current epoch. In other words, we allow transfer of
142 // the bias from one thread to another directly in this situation. 146 // the bias from one thread to another directly in this situation.
143 Word biasedMark = prototypeMarkWord.or(thread); 147 Word biasedMark = prototypeMarkWord.or(thread);
144 if (compareAndSwap(object, markOffset(), mark, biasedMark) == mark) { 148 if (compareAndSwap(object, markOffset(), mark, biasedMark) == mark) {
145 // Object is now biased to current thread -> done 149 // Object is now biased to current thread -> done
146 log("+lock{bias}", object); 150 log(logEnabled, "+lock{bias}", object);
147 return; 151 return;
148 } 152 }
149 // If the biasing toward our thread failed, then another thread 153 // If the biasing toward our thread failed, then another thread
150 // succeeded in biasing it toward itself and we need to revoke that 154 // succeeded in biasing it toward itself and we need to revoke that
151 // bias. The revocation will occur in the runtime in the slow case. 155 // bias. The revocation will occur in the runtime in the slow case.
152 log("+lock{stub}", object); 156 log(logEnabled, "+lock{stub}", object);
153 MonitorEnterStubCall.call(object, lock); 157 MonitorEnterStubCall.call(object, lock);
154 return; 158 return;
155 } 159 }
156 } else { 160 } else {
157 // The prototype mark word doesn't have the bias bit set any 161 // The prototype mark word doesn't have the bias bit set any
198 // significant 2 bits cleared and page_size is a power of 2 202 // significant 2 bits cleared and page_size is a power of 2
199 final Word alignedMask = Word.fromInt(wordSize() - 1); 203 final Word alignedMask = Word.fromInt(wordSize() - 1);
200 final Word stackPointer = asWord(register(stackPointerReg(), wordKind())); 204 final Word stackPointer = asWord(register(stackPointerReg(), wordKind()));
201 if (currentMark.minus(stackPointer).and(alignedMask.minus(pageSize())) != Word.zero()) { 205 if (currentMark.minus(stackPointer).and(alignedMask.minus(pageSize())) != Word.zero()) {
202 // Most likely not a recursive lock, go into a slow runtime call 206 // Most likely not a recursive lock, go into a slow runtime call
203 log("+lock{stub}", object); 207 log(logEnabled, "+lock{stub}", object);
204 MonitorEnterStubCall.call(object, lock); 208 MonitorEnterStubCall.call(object, lock);
205 return; 209 return;
206 } else { 210 } else {
207 // Recursively locked => write 0 to the lock slot 211 // Recursively locked => write 0 to the lock slot
208 storeWord(lock, lockDisplacedMarkOffset(), 0, Word.zero()); 212 storeWord(lock, lockDisplacedMarkOffset(), 0, Word.zero());
209 log("+lock{recursive}", object); 213 log(logEnabled, "+lock{recursive}", object);
210 } 214 }
211 } else { 215 } else {
212 log("+lock{cas}", object); 216 log(logEnabled, "+lock{cas}", object);
213 } 217 }
214 } 218 }
215 219
216 @Snippet 220 @Snippet
217 public static void monitorenterEliminated(@Parameter("object") Object object) { 221 public static void monitorenterEliminated(@Parameter("object") Object object) {
220 224
221 /** 225 /**
222 * Calls straight out to the monitorenter stub. 226 * Calls straight out to the monitorenter stub.
223 */ 227 */
224 @Snippet 228 @Snippet
225 public static void monitorenterStub(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull) { 229 public static void monitorenterStub(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("logEnabled") boolean logEnabled) {
226 verifyOop(object); 230 verifyOop(object);
227 if (checkNull && object == null) { 231 if (checkNull && object == null) {
228 DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); 232 DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
229 } 233 }
230 // BeginLockScope nodes do not read from object so a use of object 234 // BeginLockScope nodes do not read from object so a use of object
231 // cannot float about the null check above 235 // cannot float about the null check above
232 final Word lock = beginLockScope(object, false, wordKind()); 236 final Word lock = beginLockScope(object, false, wordKind());
233 log("+lock{stub}", object); 237 log(logEnabled, "+lock{stub}", object);
234 MonitorEnterStubCall.call(object, lock); 238 MonitorEnterStubCall.call(object, lock);
235 } 239 }
236 240
237 @Snippet 241 @Snippet
238 public static void monitorexit(@Parameter("object") Object object) { 242 public static void monitorexit(@Parameter("object") Object object, @ConstantParameter("logEnabled") boolean logEnabled) {
239 if (useBiasedLocking()) { 243 if (useBiasedLocking()) {
240 // Check for biased locking unlock case, which is a no-op 244 // Check for biased locking unlock case, which is a no-op
241 // Note: we do not have to check the thread ID for two reasons. 245 // Note: we do not have to check the thread ID for two reasons.
242 // First, the interpreter checks for IllegalMonitorStateException at 246 // First, the interpreter checks for IllegalMonitorStateException at
243 // a higher level. Second, if the bias was revoked while we held the 247 // a higher level. Second, if the bias was revoked while we held the
244 // lock, the object could not be rebiased toward another thread, so 248 // lock, the object could not be rebiased toward another thread, so
245 // the bias bit would be clear. 249 // the bias bit would be clear.
246 final Word mark = asWord(loadObject(object, 0, markOffset(), true)); 250 final Word mark = asWord(loadObject(object, 0, markOffset(), true));
247 if (mark.and(biasedLockMaskInPlace()).toLong() == biasedLockPattern()) { 251 if (mark.and(biasedLockMaskInPlace()).toLong() == biasedLockPattern()) {
248 endLockScope(object, false); 252 endLockScope(object, false);
249 log("-lock{bias}", object); 253 log(logEnabled, "-lock{bias}", object);
250 return; 254 return;
251 } 255 }
252 } 256 }
253 257
254 final Word lock = CurrentLockNode.currentLock(wordKind()); 258 final Word lock = CurrentLockNode.currentLock(wordKind());
256 // Load displaced mark 260 // Load displaced mark
257 final Word displacedMark = loadWord(lock, lockDisplacedMarkOffset()); 261 final Word displacedMark = loadWord(lock, lockDisplacedMarkOffset());
258 262
259 if (displacedMark == Word.zero()) { 263 if (displacedMark == Word.zero()) {
260 // Recursive locking => done 264 // Recursive locking => done
261 log("-lock{recursive}", object); 265 log(logEnabled, "-lock{recursive}", object);
262 } else { 266 } else {
263 verifyOop(object); 267 verifyOop(object);
264 // Test if object's mark word is pointing to the displaced mark word, and if so, restore 268 // Test if object's mark word is pointing to the displaced mark word, and if so, restore
265 // the displaced mark in the object - if the object's mark word is not pointing to 269 // the displaced mark in the object - if the object's mark word is not pointing to
266 // the displaced mark word, get the object mark word instead 270 // the displaced mark word, do unlocking via runtime call.
267 if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark) != lock) { 271 if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark) != lock) {
268 // The object's mark word was not pointing to the displaced header, 272 // The object's mark word was not pointing to the displaced header,
269 // we do unlocking via runtime call 273 // we do unlocking via runtime call.
270 log("-lock{stub}", object); 274 log(logEnabled, "-lock{stub}", object);
271 MonitorExitStubCall.call(object); 275 MonitorExitStubCall.call(object);
272 } else { 276 } else {
273 log("-lock{cas}", object); 277 log(logEnabled, "-lock{cas}", object);
274 } 278 }
275 } 279 }
276 endLockScope(object, false); 280 endLockScope(object, false);
277 } 281 }
278 282
279 /** 283 /**
280 * Calls straight out to the monitorexit stub. 284 * Calls straight out to the monitorexit stub.
281 */ 285 */
282 @Snippet 286 @Snippet
283 public static void monitorexitStub(@Parameter("object") Object object) { 287 public static void monitorexitStub(@Parameter("object") Object object, @ConstantParameter("logEnabled") boolean logEnabled) {
284 verifyOop(object); 288 verifyOop(object);
285 log("-lock{stub}", object); 289 log(logEnabled, "-lock{stub}", object);
286 MonitorExitStubCall.call(object); 290 MonitorExitStubCall.call(object);
287 endLockScope(object, false); 291 endLockScope(object, false);
288 } 292 }
289 293
290 @Snippet 294 @Snippet
302 private final ResolvedJavaMethod monitorexitEliminated; 306 private final ResolvedJavaMethod monitorexitEliminated;
303 private final boolean useFastLocking; 307 private final boolean useFastLocking;
304 308
305 public Templates(CodeCacheProvider runtime, boolean useFastLocking) { 309 public Templates(CodeCacheProvider runtime, boolean useFastLocking) {
306 super(runtime, MonitorSnippets.class); 310 super(runtime, MonitorSnippets.class);
307 monitorenter = snippet("monitorenter", Object.class); 311 monitorenter = snippet("monitorenter", Object.class, boolean.class);
308 monitorexit = snippet("monitorexit", Object.class); 312 monitorexit = snippet("monitorexit", Object.class, boolean.class);
309 monitorenterStub = snippet("monitorenterStub", Object.class, boolean.class); 313 monitorenterStub = snippet("monitorenterStub", Object.class, boolean.class, boolean.class);
310 monitorexitStub = snippet("monitorexitStub", Object.class); 314 monitorexitStub = snippet("monitorexitStub", Object.class, boolean.class);
311 monitorenterEliminated = snippet("monitorenterEliminated", Object.class); 315 monitorenterEliminated = snippet("monitorenterEliminated", Object.class);
312 monitorexitEliminated = snippet("monitorexitEliminated", Object.class); 316 monitorexitEliminated = snippet("monitorexitEliminated", Object.class);
313 this.useFastLocking = useFastLocking; 317 this.useFastLocking = useFastLocking;
318 }
319
320 static boolean isLoggingEnabledFor(ValueNode object) {
321 ResolvedJavaType type = object.objectStamp().type();
322 if (LOG_TYPE == null) {
323 return false;
324 } else {
325 if (LOG_TYPE.length() == 0) {
326 return true;
327 }
328 if (type == null) {
329 return false;
330 }
331 return (type.name().contains(LOG_TYPE));
332 }
314 } 333 }
315 334
316 public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) { 335 public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) {
317 FrameState stateAfter = monitorenterNode.stateAfter(); 336 FrameState stateAfter = monitorenterNode.stateAfter();
318 ResolvedJavaMethod method = monitorenterNode.eliminated() ? monitorenterEliminated : useFastLocking ? monitorenter : monitorenterStub; 337 ResolvedJavaMethod method = monitorenterNode.eliminated() ? monitorenterEliminated : useFastLocking ? monitorenter : monitorenterStub;
319 boolean checkNull = !monitorenterNode.object().stamp().nonNull(); 338 boolean checkNull = !monitorenterNode.object().stamp().nonNull();
320 Key key = new Key(method); 339 Key key = new Key(method);
321 if (method == monitorenterStub) { 340 if (method == monitorenterStub) {
322 key.add("checkNull", checkNull); 341 key.add("checkNull", checkNull);
323 } 342 }
343 if (!monitorenterNode.eliminated()) {
344 key.add("logEnabled", isLoggingEnabledFor(monitorenterNode.object()));
345 }
324 Arguments arguments = arguments("object", monitorenterNode.object()); 346 Arguments arguments = arguments("object", monitorenterNode.object());
325 SnippetTemplate template = cache.get(key); 347 SnippetTemplate template = cache.get(key);
326 Map<Node, Node> nodes = template.instantiate(runtime, monitorenterNode, arguments); 348 Map<Node, Node> nodes = template.instantiate(runtime, monitorenterNode, arguments);
327 for (Node n : nodes.values()) { 349 for (Node n : nodes.values()) {
328 if (n instanceof BeginLockScopeNode) { 350 if (n instanceof BeginLockScopeNode) {
334 356
335 public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) { 357 public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) {
336 FrameState stateAfter = monitorexitNode.stateAfter(); 358 FrameState stateAfter = monitorexitNode.stateAfter();
337 ResolvedJavaMethod method = monitorexitNode.eliminated() ? monitorexitEliminated : useFastLocking ? monitorexit : monitorexitStub; 359 ResolvedJavaMethod method = monitorexitNode.eliminated() ? monitorexitEliminated : useFastLocking ? monitorexit : monitorexitStub;
338 Key key = new Key(method); 360 Key key = new Key(method);
361 if (!monitorexitNode.eliminated()) {
362 key.add("logEnabled", isLoggingEnabledFor(monitorexitNode.object()));
363 }
339 Arguments arguments = arguments("object", monitorexitNode.object()); 364 Arguments arguments = arguments("object", monitorexitNode.object());
340 SnippetTemplate template = cache.get(key); 365 SnippetTemplate template = cache.get(key);
341 Map<Node, Node> nodes = template.instantiate(runtime, monitorexitNode, arguments); 366 Map<Node, Node> nodes = template.instantiate(runtime, monitorexitNode, arguments);
342 for (Node n : nodes.values()) { 367 for (Node n : nodes.values()) {
343 if (n instanceof EndLockScopeNode) { 368 if (n instanceof EndLockScopeNode) {