Mercurial > hg > graal-jvmci-8
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) { |