Mercurial > hg > graal-compiler
comparison graal/com.oracle.jvmci.debug/src/com/oracle/jvmci/debug/Debug.java @ 21554:b1530a6cce8c
renamed com.oracle.graal.[debug|options|hotspotvmconfig]* modules to com.oracle.jvmci.[debug|options|hotspotvmconfig]* modules (JBS:GRAAL-53)
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Tue, 26 May 2015 23:21:15 +0200 |
parents | graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java@7d2f6dd603b0 |
children | d563baeca9df |
comparison
equal
deleted
inserted
replaced
21553:0910a9497b02 | 21554:b1530a6cce8c |
---|---|
1 /* | |
2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.oracle.jvmci.debug; | |
24 | |
25 import static com.oracle.jvmci.debug.Debug.Initialization.*; | |
26 import static com.oracle.jvmci.debug.DelegatingDebugConfig.Feature.*; | |
27 import static java.util.FormattableFlags.*; | |
28 | |
29 import java.io.*; | |
30 import java.util.*; | |
31 import java.util.concurrent.*; | |
32 | |
33 import com.oracle.jvmci.debug.DelegatingDebugConfig.Level; | |
34 import com.oracle.jvmci.debug.internal.*; | |
35 | |
36 /** | |
37 * Scope based debugging facility. This facility is {@link #isEnabled()} if assertions are enabled | |
38 * for the {@link Debug} class or the {@value Initialization#INITIALIZER_PROPERTY_NAME} system | |
39 * property is {@code "true"} when {@link Debug} is initialized. | |
40 */ | |
41 public class Debug { | |
42 | |
43 /** | |
44 * Class to assist with initialization of {@link Debug}. | |
45 */ | |
46 public static class Initialization { | |
47 | |
48 public static final String INITIALIZER_PROPERTY_NAME = "graal.debug.enable"; | |
49 | |
50 private static boolean initialized; | |
51 | |
52 /** | |
53 * Determines if {@link Debug} has been initialized. | |
54 */ | |
55 public static boolean isDebugInitialized() { | |
56 return initialized; | |
57 } | |
58 | |
59 } | |
60 | |
61 @SuppressWarnings("all") | |
62 private static boolean initialize() { | |
63 boolean assertionsEnabled = false; | |
64 assert assertionsEnabled = true; | |
65 Initialization.initialized = true; | |
66 return assertionsEnabled || Boolean.getBoolean(INITIALIZER_PROPERTY_NAME); | |
67 } | |
68 | |
69 private static final boolean ENABLED = initialize(); | |
70 | |
71 public static boolean isEnabled() { | |
72 return ENABLED; | |
73 } | |
74 | |
75 public static boolean isDumpEnabledForMethod() { | |
76 if (!ENABLED) { | |
77 return false; | |
78 } | |
79 DebugConfig config = DebugScope.getConfig(); | |
80 if (config == null) { | |
81 return false; | |
82 } | |
83 return config.isDumpEnabledForMethod(); | |
84 } | |
85 | |
86 public static final int DEFAULT_LOG_LEVEL = 2; | |
87 | |
88 public static boolean isDumpEnabled() { | |
89 return isDumpEnabled(DEFAULT_LOG_LEVEL); | |
90 } | |
91 | |
92 public static boolean isDumpEnabled(int dumpLevel) { | |
93 return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel); | |
94 } | |
95 | |
96 /** | |
97 * Determines if verification is enabled in the current method, regardless of the | |
98 * {@linkplain Debug#currentScope() current debug scope}. | |
99 * | |
100 * @see Debug#verify(Object, String) | |
101 */ | |
102 public static boolean isVerifyEnabledForMethod() { | |
103 if (!ENABLED) { | |
104 return false; | |
105 } | |
106 DebugConfig config = DebugScope.getConfig(); | |
107 if (config == null) { | |
108 return false; | |
109 } | |
110 return config.isVerifyEnabledForMethod(); | |
111 } | |
112 | |
113 /** | |
114 * Determines if verification is enabled in the {@linkplain Debug#currentScope() current debug | |
115 * scope}. | |
116 * | |
117 * @see Debug#verify(Object, String) | |
118 */ | |
119 public static boolean isVerifyEnabled() { | |
120 return ENABLED && DebugScope.getInstance().isVerifyEnabled(); | |
121 } | |
122 | |
123 public static boolean isMeterEnabled() { | |
124 return ENABLED && DebugScope.getInstance().isMeterEnabled(); | |
125 } | |
126 | |
127 public static boolean isTimeEnabled() { | |
128 return ENABLED && DebugScope.getInstance().isTimeEnabled(); | |
129 } | |
130 | |
131 public static boolean isMemUseTrackingEnabled() { | |
132 return ENABLED && DebugScope.getInstance().isMemUseTrackingEnabled(); | |
133 } | |
134 | |
135 public static boolean isLogEnabledForMethod() { | |
136 if (!ENABLED) { | |
137 return false; | |
138 } | |
139 DebugConfig config = DebugScope.getConfig(); | |
140 if (config == null) { | |
141 return false; | |
142 } | |
143 return config.isLogEnabledForMethod(); | |
144 } | |
145 | |
146 public static boolean isLogEnabled() { | |
147 return isLogEnabled(DEFAULT_LOG_LEVEL); | |
148 } | |
149 | |
150 public static boolean isLogEnabled(int logLevel) { | |
151 return ENABLED && DebugScope.getInstance().isLogEnabled(logLevel); | |
152 } | |
153 | |
154 @SuppressWarnings("unused") | |
155 public static Runnable decorateDebugRoot(Runnable runnable, String name, DebugConfig config) { | |
156 return runnable; | |
157 } | |
158 | |
159 @SuppressWarnings("unused") | |
160 public static <T> Callable<T> decorateDebugRoot(Callable<T> callable, String name, DebugConfig config) { | |
161 return callable; | |
162 } | |
163 | |
164 @SuppressWarnings("unused") | |
165 public static Runnable decorateScope(Runnable runnable, String name, Object... context) { | |
166 return runnable; | |
167 } | |
168 | |
169 @SuppressWarnings("unused") | |
170 public static <T> Callable<T> decorateScope(Callable<T> callable, String name, Object... context) { | |
171 return callable; | |
172 } | |
173 | |
174 /** | |
175 * Gets a string composed of the names in the current nesting of debug | |
176 * {@linkplain #scope(Object) scopes} separated by {@code '.'}. | |
177 */ | |
178 public static String currentScope() { | |
179 if (ENABLED) { | |
180 return DebugScope.getInstance().getQualifiedName(); | |
181 } else { | |
182 return ""; | |
183 } | |
184 } | |
185 | |
186 /** | |
187 * Represents a debug scope entered by {@link Debug#scope(Object)} or | |
188 * {@link Debug#sandbox(CharSequence, DebugConfig, Object...)}. Leaving the scope is achieved | |
189 * via {@link #close()}. | |
190 */ | |
191 public interface Scope extends AutoCloseable { | |
192 void close(); | |
193 } | |
194 | |
195 /** | |
196 * Creates and enters a new debug scope which will be a child of the current debug scope. | |
197 * <p> | |
198 * It is recommended to use the try-with-resource statement for managing entering and leaving | |
199 * debug scopes. For example: | |
200 * | |
201 * <pre> | |
202 * try (Scope s = Debug.scope("InliningGraph", inlineeGraph)) { | |
203 * ... | |
204 * } catch (Throwable e) { | |
205 * throw Debug.handle(e); | |
206 * } | |
207 * </pre> | |
208 * | |
209 * The {@code name} argument is subject to the following type based conversion before having | |
210 * {@link Object#toString()} called on it: | |
211 * | |
212 * <pre> | |
213 * Type | Conversion | |
214 * ------------------+----------------- | |
215 * java.lang.Class | arg.getSimpleName() | |
216 * | | |
217 * </pre> | |
218 * | |
219 * @param name the name of the new scope | |
220 * @param contextObjects an array of object to be appended to the {@linkplain #context() | |
221 * current} debug context | |
222 * @throws Throwable used to enforce a catch block. | |
223 * @return the scope entered by this method which will be exited when its {@link Scope#close()} | |
224 * method is called | |
225 */ | |
226 public static Scope scope(Object name, Object[] contextObjects) throws Throwable { | |
227 if (ENABLED) { | |
228 return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, contextObjects); | |
229 } else { | |
230 return null; | |
231 } | |
232 } | |
233 | |
234 /** | |
235 * Similar to {@link #scope(Object, Object[])} but without context objects. Therefore the catch | |
236 * block can be omitted. | |
237 * | |
238 * @see #scope(Object, Object[]) | |
239 */ | |
240 public static Scope scope(Object name) { | |
241 if (ENABLED) { | |
242 return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null); | |
243 } else { | |
244 return null; | |
245 } | |
246 } | |
247 | |
248 /** | |
249 * @see #scope(Object, Object[]) | |
250 * @param context an object to be appended to the {@linkplain #context() current} debug context | |
251 */ | |
252 public static Scope scope(Object name, Object context) throws Throwable { | |
253 if (ENABLED) { | |
254 return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context); | |
255 } else { | |
256 return null; | |
257 } | |
258 } | |
259 | |
260 /** | |
261 * @see #scope(Object, Object[]) | |
262 * @param context1 first object to be appended to the {@linkplain #context() current} debug | |
263 * context | |
264 * @param context2 second object to be appended to the {@linkplain #context() current} debug | |
265 * context | |
266 */ | |
267 public static Scope scope(Object name, Object context1, Object context2) throws Throwable { | |
268 if (ENABLED) { | |
269 return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2); | |
270 } else { | |
271 return null; | |
272 } | |
273 } | |
274 | |
275 /** | |
276 * @see #scope(Object, Object[]) | |
277 * @param context1 first object to be appended to the {@linkplain #context() current} debug | |
278 * context | |
279 * @param context2 second object to be appended to the {@linkplain #context() current} debug | |
280 * context | |
281 * @param context3 third object to be appended to the {@linkplain #context() current} debug | |
282 * context | |
283 */ | |
284 public static Scope scope(Object name, Object context1, Object context2, Object context3) throws Throwable { | |
285 if (ENABLED) { | |
286 return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2, context3); | |
287 } else { | |
288 return null; | |
289 } | |
290 } | |
291 | |
292 /** | |
293 * Creates and enters a new debug scope which will be disjoint from the current debug scope. | |
294 * <p> | |
295 * It is recommended to use the try-with-resource statement for managing entering and leaving | |
296 * debug scopes. For example: | |
297 * | |
298 * <pre> | |
299 * try (Scope s = Debug.sandbox("CompilingStub", null, stubGraph)) { | |
300 * ... | |
301 * } catch (Throwable e) { | |
302 * throw Debug.handle(e); | |
303 * } | |
304 * </pre> | |
305 * | |
306 * @param name the name of the new scope | |
307 * @param config the debug configuration to use for the new scope | |
308 * @param context objects to be appended to the {@linkplain #context() current} debug context | |
309 * @return the scope entered by this method which will be exited when its {@link Scope#close()} | |
310 * method is called | |
311 */ | |
312 public static Scope sandbox(CharSequence name, DebugConfig config, Object... context) throws Throwable { | |
313 if (ENABLED) { | |
314 DebugConfig sandboxConfig = config == null ? silentConfig() : config; | |
315 return DebugScope.getInstance().scope(name, sandboxConfig, context); | |
316 } else { | |
317 return null; | |
318 } | |
319 } | |
320 | |
321 public static Scope forceLog() throws Throwable { | |
322 ArrayList<Object> context = new ArrayList<>(); | |
323 for (Object obj : context()) { | |
324 context.add(obj); | |
325 } | |
326 return Debug.sandbox("forceLog", new DelegatingDebugConfig().override(Level.LOG, Integer.MAX_VALUE).enable(LOG_METHOD), context.toArray()); | |
327 } | |
328 | |
329 /** | |
330 * Opens a scope in which exception {@linkplain DebugConfig#interceptException(Throwable) | |
331 * interception} is disabled. It is recommended to use the try-with-resource statement for | |
332 * managing entering and leaving such scopes: | |
333 * | |
334 * <pre> | |
335 * try (DebugConfigScope s = Debug.disableIntercept()) { | |
336 * ... | |
337 * } | |
338 * </pre> | |
339 * | |
340 * This is particularly useful to suppress extraneous output in JUnit tests that are expected to | |
341 * throw an exception. | |
342 */ | |
343 public static DebugConfigScope disableIntercept() { | |
344 return Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); | |
345 } | |
346 | |
347 /** | |
348 * Handles an exception in the context of the debug scope just exited. The just exited scope | |
349 * must have the current scope as its parent which will be the case if the try-with-resource | |
350 * pattern recommended by {@link #scope(Object)} and | |
351 * {@link #sandbox(CharSequence, DebugConfig, Object...)} is used | |
352 * | |
353 * @see #scope(Object, Object[]) | |
354 * @see #sandbox(CharSequence, DebugConfig, Object...) | |
355 */ | |
356 public static RuntimeException handle(Throwable exception) { | |
357 if (ENABLED) { | |
358 return DebugScope.getInstance().handle(exception); | |
359 } else { | |
360 if (exception instanceof Error) { | |
361 throw (Error) exception; | |
362 } | |
363 if (exception instanceof RuntimeException) { | |
364 throw (RuntimeException) exception; | |
365 } | |
366 throw new RuntimeException(exception); | |
367 } | |
368 } | |
369 | |
370 public static void log(String msg) { | |
371 log(DEFAULT_LOG_LEVEL, msg); | |
372 } | |
373 | |
374 /** | |
375 * Prints a message to the current debug scope's logging stream if logging is enabled. | |
376 * | |
377 * @param msg the message to log | |
378 */ | |
379 public static void log(int logLevel, String msg) { | |
380 if (ENABLED) { | |
381 DebugScope.getInstance().log(logLevel, msg); | |
382 } | |
383 } | |
384 | |
385 public static void log(String format, Object arg) { | |
386 log(DEFAULT_LOG_LEVEL, format, arg); | |
387 } | |
388 | |
389 /** | |
390 * Prints a message to the current debug scope's logging stream if logging is enabled. | |
391 * | |
392 * @param format a format string | |
393 * @param arg the argument referenced by the format specifiers in {@code format} | |
394 */ | |
395 public static void log(int logLevel, String format, Object arg) { | |
396 if (ENABLED) { | |
397 DebugScope.getInstance().log(logLevel, format, arg); | |
398 } | |
399 } | |
400 | |
401 public static void log(String format, int arg) { | |
402 log(DEFAULT_LOG_LEVEL, format, arg); | |
403 } | |
404 | |
405 /** | |
406 * Prints a message to the current debug scope's logging stream if logging is enabled. | |
407 * | |
408 * @param format a format string | |
409 * @param arg the argument referenced by the format specifiers in {@code format} | |
410 */ | |
411 public static void log(int logLevel, String format, int arg) { | |
412 if (ENABLED) { | |
413 DebugScope.getInstance().log(logLevel, format, arg); | |
414 } | |
415 } | |
416 | |
417 public static void log(String format, Object arg1, Object arg2) { | |
418 log(DEFAULT_LOG_LEVEL, format, arg1, arg2); | |
419 } | |
420 | |
421 /** | |
422 * @see #log(int, String, Object) | |
423 */ | |
424 public static void log(int logLevel, String format, Object arg1, Object arg2) { | |
425 if (ENABLED) { | |
426 DebugScope.getInstance().log(logLevel, format, arg1, arg2); | |
427 } | |
428 } | |
429 | |
430 public static void log(String format, int arg1, Object arg2) { | |
431 log(DEFAULT_LOG_LEVEL, format, arg1, arg2); | |
432 } | |
433 | |
434 /** | |
435 * @see #log(int, String, Object) | |
436 */ | |
437 public static void log(int logLevel, String format, int arg1, Object arg2) { | |
438 if (ENABLED) { | |
439 DebugScope.getInstance().log(logLevel, format, arg1, arg2); | |
440 } | |
441 } | |
442 | |
443 public static void log(String format, Object arg1, int arg2) { | |
444 log(DEFAULT_LOG_LEVEL, format, arg1, arg2); | |
445 } | |
446 | |
447 /** | |
448 * @see #log(int, String, Object) | |
449 */ | |
450 public static void log(int logLevel, String format, Object arg1, int arg2) { | |
451 if (ENABLED) { | |
452 DebugScope.getInstance().log(logLevel, format, arg1, arg2); | |
453 } | |
454 } | |
455 | |
456 public static void log(String format, int arg1, int arg2) { | |
457 log(DEFAULT_LOG_LEVEL, format, arg1, arg2); | |
458 } | |
459 | |
460 /** | |
461 * @see #log(int, String, Object) | |
462 */ | |
463 public static void log(int logLevel, String format, int arg1, int arg2) { | |
464 if (ENABLED) { | |
465 DebugScope.getInstance().log(logLevel, format, arg1, arg2); | |
466 } | |
467 } | |
468 | |
469 public static void log(String format, Object arg1, Object arg2, Object arg3) { | |
470 log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3); | |
471 } | |
472 | |
473 /** | |
474 * @see #log(int, String, Object) | |
475 */ | |
476 public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3) { | |
477 if (ENABLED) { | |
478 DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3); | |
479 } | |
480 } | |
481 | |
482 public static void log(String format, int arg1, int arg2, int arg3) { | |
483 log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3); | |
484 } | |
485 | |
486 /** | |
487 * @see #log(int, String, Object) | |
488 */ | |
489 public static void log(int logLevel, String format, int arg1, int arg2, int arg3) { | |
490 if (ENABLED) { | |
491 DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3); | |
492 } | |
493 } | |
494 | |
495 public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) { | |
496 log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4); | |
497 } | |
498 | |
499 /** | |
500 * @see #log(int, String, Object) | |
501 */ | |
502 public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4) { | |
503 if (ENABLED) { | |
504 DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4); | |
505 } | |
506 } | |
507 | |
508 public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { | |
509 log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5); | |
510 } | |
511 | |
512 /** | |
513 * @see #log(int, String, Object) | |
514 */ | |
515 public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { | |
516 if (ENABLED) { | |
517 DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5); | |
518 } | |
519 } | |
520 | |
521 public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { | |
522 log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6); | |
523 } | |
524 | |
525 /** | |
526 * @see #log(int, String, Object) | |
527 */ | |
528 public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { | |
529 if (ENABLED) { | |
530 DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6); | |
531 } | |
532 } | |
533 | |
534 public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) { | |
535 log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); | |
536 } | |
537 | |
538 public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) { | |
539 log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); | |
540 } | |
541 | |
542 /** | |
543 * @see #log(int, String, Object) | |
544 */ | |
545 public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) { | |
546 if (ENABLED) { | |
547 DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); | |
548 } | |
549 } | |
550 | |
551 public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) { | |
552 if (ENABLED) { | |
553 DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); | |
554 } | |
555 } | |
556 | |
557 public static void logv(String format, Object... args) { | |
558 logv(DEFAULT_LOG_LEVEL, format, args); | |
559 } | |
560 | |
561 /** | |
562 * Prints a message to the current debug scope's logging stream. This method must only be called | |
563 * if debugging is {@linkplain Debug#isEnabled() enabled} as it incurs allocation at the call | |
564 * site. If possible, call one of the other {@code log()} methods in this class that take a | |
565 * fixed number of parameters. | |
566 * | |
567 * @param format a format string | |
568 * @param args the arguments referenced by the format specifiers in {@code format} | |
569 */ | |
570 public static void logv(int logLevel, String format, Object... args) { | |
571 if (!ENABLED) { | |
572 throw new InternalError("Use of Debug.logv() must be guarded by a test of Debug.isEnabled()"); | |
573 } | |
574 DebugScope.getInstance().log(logLevel, format, args); | |
575 } | |
576 | |
577 /** | |
578 * This override exists to catch cases when {@link #log(String, Object)} is called with one | |
579 * argument bound to a varargs method parameter. It will bind to this method instead of the | |
580 * single arg variant and produce a deprecation warning instead of silently wrapping the | |
581 * Object[] inside of another Object[]. | |
582 */ | |
583 @Deprecated | |
584 public static void log(String format, Object[] args) { | |
585 assert false : "shouldn't use this"; | |
586 log(DEFAULT_LOG_LEVEL, format, args); | |
587 } | |
588 | |
589 /** | |
590 * This override exists to catch cases when {@link #log(int, String, Object)} is called with one | |
591 * argument bound to a varargs method parameter. It will bind to this method instead of the | |
592 * single arg variant and produce a deprecation warning instead of silently wrapping the | |
593 * Object[] inside of another Object[]. | |
594 */ | |
595 @Deprecated | |
596 public static void log(int logLevel, String format, Object[] args) { | |
597 assert false : "shouldn't use this"; | |
598 logv(logLevel, format, args); | |
599 } | |
600 | |
601 public static void dump(Object object, String msg) { | |
602 dump(DEFAULT_LOG_LEVEL, object, msg); | |
603 } | |
604 | |
605 public static void dump(int dumpLevel, Object object, String msg) { | |
606 if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { | |
607 DebugScope.getInstance().dump(dumpLevel, object, msg); | |
608 } | |
609 } | |
610 | |
611 public static void dump(Object object, String format, Object arg) { | |
612 dump(DEFAULT_LOG_LEVEL, object, format, arg); | |
613 } | |
614 | |
615 public static void dump(int dumpLevel, Object object, String format, Object arg) { | |
616 if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { | |
617 DebugScope.getInstance().dump(dumpLevel, object, format, arg); | |
618 } | |
619 } | |
620 | |
621 public static void dump(Object object, String format, Object arg1, Object arg2) { | |
622 dump(DEFAULT_LOG_LEVEL, object, format, arg1, arg2); | |
623 } | |
624 | |
625 public static void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2) { | |
626 if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { | |
627 DebugScope.getInstance().dump(dumpLevel, object, format, arg1, arg2); | |
628 } | |
629 } | |
630 | |
631 public static void dump(Object object, String format, Object arg1, Object arg2, Object arg3) { | |
632 dump(DEFAULT_LOG_LEVEL, object, format, arg1, arg2, arg3); | |
633 } | |
634 | |
635 public static void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2, Object arg3) { | |
636 if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { | |
637 DebugScope.getInstance().dump(dumpLevel, object, format, arg1, arg2, arg3); | |
638 } | |
639 } | |
640 | |
641 /** | |
642 * This override exists to catch cases when {@link #dump(Object, String, Object)} is called with | |
643 * one argument bound to a varargs method parameter. It will bind to this method instead of the | |
644 * single arg variant and produce a deprecation warning instead of silently wrapping the | |
645 * Object[] inside of another Object[]. | |
646 */ | |
647 @Deprecated | |
648 public static void dump(Object object, String format, Object[] args) { | |
649 assert false : "shouldn't use this"; | |
650 dump(DEFAULT_LOG_LEVEL, object, format, args); | |
651 } | |
652 | |
653 /** | |
654 * This override exists to catch cases when {@link #dump(int, Object, String, Object)} is called | |
655 * with one argument bound to a varargs method parameter. It will bind to this method instead of | |
656 * the single arg variant and produce a deprecation warning instead of silently wrapping the | |
657 * Object[] inside of another Object[]. | |
658 */ | |
659 @Deprecated | |
660 public static void dump(int dumpLevel, Object object, String format, Object[] args) { | |
661 assert false : "shouldn't use this"; | |
662 if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { | |
663 DebugScope.getInstance().dump(dumpLevel, object, format, args); | |
664 } | |
665 } | |
666 | |
667 /** | |
668 * Calls all {@link DebugVerifyHandler}s in the current {@linkplain DebugScope#getConfig() | |
669 * config} to perform verification on a given object. | |
670 * | |
671 * @param object object to verify | |
672 * @param message description of verification context | |
673 * | |
674 * @see DebugVerifyHandler#verify(Object, String) | |
675 */ | |
676 public static void verify(Object object, String message) { | |
677 if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) { | |
678 DebugScope.getInstance().verify(object, message); | |
679 } | |
680 } | |
681 | |
682 /** | |
683 * Calls all {@link DebugVerifyHandler}s in the current {@linkplain DebugScope#getConfig() | |
684 * config} to perform verification on a given object. | |
685 * | |
686 * @param object object to verify | |
687 * @param format a format string for the description of the verification context | |
688 * @param arg the argument referenced by the format specifiers in {@code format} | |
689 * | |
690 * @see DebugVerifyHandler#verify(Object, String) | |
691 */ | |
692 public static void verify(Object object, String format, Object arg) { | |
693 if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) { | |
694 DebugScope.getInstance().verify(object, format, arg); | |
695 } | |
696 } | |
697 | |
698 /** | |
699 * This override exists to catch cases when {@link #verify(Object, String, Object)} is called | |
700 * with one argument bound to a varargs method parameter. It will bind to this method instead of | |
701 * the single arg variant and produce a deprecation warning instead of silently wrapping the | |
702 * Object[] inside of another Object[]. | |
703 */ | |
704 @Deprecated | |
705 public static void verify(Object object, String format, Object[] args) { | |
706 assert false : "shouldn't use this"; | |
707 if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) { | |
708 DebugScope.getInstance().verify(object, format, args); | |
709 } | |
710 } | |
711 | |
712 /** | |
713 * Opens a new indentation level (by adding some spaces) based on the current indentation level. | |
714 * This should be used in a {@linkplain Indent try-with-resources} pattern. | |
715 * | |
716 * @return an object that reverts to the current indentation level when | |
717 * {@linkplain Indent#close() closed} or null if debugging is disabled | |
718 * @see #logAndIndent(int, String) | |
719 * @see #logAndIndent(int, String, Object) | |
720 */ | |
721 public static Indent indent() { | |
722 if (ENABLED) { | |
723 DebugScope scope = DebugScope.getInstance(); | |
724 return scope.pushIndentLogger(); | |
725 } | |
726 return null; | |
727 } | |
728 | |
729 public static Indent logAndIndent(String msg) { | |
730 return logAndIndent(DEFAULT_LOG_LEVEL, msg); | |
731 } | |
732 | |
733 /** | |
734 * A convenience function which combines {@link #log(String)} and {@link #indent()}. | |
735 * | |
736 * @param msg the message to log | |
737 * @return an object that reverts to the current indentation level when | |
738 * {@linkplain Indent#close() closed} or null if debugging is disabled | |
739 */ | |
740 public static Indent logAndIndent(int logLevel, String msg) { | |
741 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
742 return logvAndIndentInternal(logLevel, msg); | |
743 } | |
744 return null; | |
745 } | |
746 | |
747 public static Indent logAndIndent(String format, Object arg) { | |
748 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg); | |
749 } | |
750 | |
751 /** | |
752 * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}. | |
753 * | |
754 * @param format a format string | |
755 * @param arg the argument referenced by the format specifiers in {@code format} | |
756 * @return an object that reverts to the current indentation level when | |
757 * {@linkplain Indent#close() closed} or null if debugging is disabled | |
758 */ | |
759 public static Indent logAndIndent(int logLevel, String format, Object arg) { | |
760 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
761 return logvAndIndentInternal(logLevel, format, arg); | |
762 } | |
763 return null; | |
764 } | |
765 | |
766 public static Indent logAndIndent(String format, int arg) { | |
767 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg); | |
768 } | |
769 | |
770 /** | |
771 * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}. | |
772 * | |
773 * @param format a format string | |
774 * @param arg the argument referenced by the format specifiers in {@code format} | |
775 * @return an object that reverts to the current indentation level when | |
776 * {@linkplain Indent#close() closed} or null if debugging is disabled | |
777 */ | |
778 public static Indent logAndIndent(int logLevel, String format, int arg) { | |
779 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
780 return logvAndIndentInternal(logLevel, format, arg); | |
781 } | |
782 return null; | |
783 } | |
784 | |
785 public static Indent logAndIndent(String format, int arg1, Object arg2) { | |
786 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2); | |
787 } | |
788 | |
789 /** | |
790 * @see #logAndIndent(int, String, Object) | |
791 */ | |
792 public static Indent logAndIndent(int logLevel, String format, int arg1, Object arg2) { | |
793 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
794 return logvAndIndentInternal(logLevel, format, arg1, arg2); | |
795 } | |
796 return null; | |
797 } | |
798 | |
799 public static Indent logAndIndent(String format, Object arg1, int arg2) { | |
800 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2); | |
801 } | |
802 | |
803 /** | |
804 * @see #logAndIndent(int, String, Object) | |
805 */ | |
806 public static Indent logAndIndent(int logLevel, String format, Object arg1, int arg2) { | |
807 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
808 return logvAndIndentInternal(logLevel, format, arg1, arg2); | |
809 } | |
810 return null; | |
811 } | |
812 | |
813 public static Indent logAndIndent(String format, int arg1, int arg2) { | |
814 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2); | |
815 } | |
816 | |
817 /** | |
818 * @see #logAndIndent(int, String, Object) | |
819 */ | |
820 public static Indent logAndIndent(int logLevel, String format, int arg1, int arg2) { | |
821 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
822 return logvAndIndentInternal(logLevel, format, arg1, arg2); | |
823 } | |
824 return null; | |
825 } | |
826 | |
827 public static Indent logAndIndent(String format, Object arg1, Object arg2) { | |
828 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2); | |
829 } | |
830 | |
831 /** | |
832 * @see #logAndIndent(int, String, Object) | |
833 */ | |
834 public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2) { | |
835 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
836 return logvAndIndentInternal(logLevel, format, arg1, arg2); | |
837 } | |
838 return null; | |
839 } | |
840 | |
841 public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) { | |
842 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3); | |
843 } | |
844 | |
845 /** | |
846 * @see #logAndIndent(int, String, Object) | |
847 */ | |
848 public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3) { | |
849 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
850 return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3); | |
851 } | |
852 return null; | |
853 } | |
854 | |
855 public static Indent logAndIndent(String format, int arg1, int arg2, int arg3) { | |
856 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3); | |
857 } | |
858 | |
859 /** | |
860 * @see #logAndIndent(int, String, Object) | |
861 */ | |
862 public static Indent logAndIndent(int logLevel, String format, int arg1, int arg2, int arg3) { | |
863 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
864 return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3); | |
865 } | |
866 return null; | |
867 } | |
868 | |
869 public static Indent logAndIndent(String format, Object arg1, int arg2, int arg3) { | |
870 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3); | |
871 } | |
872 | |
873 /** | |
874 * @see #logAndIndent(int, String, Object) | |
875 */ | |
876 public static Indent logAndIndent(int logLevel, String format, Object arg1, int arg2, int arg3) { | |
877 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
878 return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3); | |
879 } | |
880 return null; | |
881 } | |
882 | |
883 public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4) { | |
884 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4); | |
885 } | |
886 | |
887 /** | |
888 * @see #logAndIndent(int, String, Object) | |
889 */ | |
890 public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4) { | |
891 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
892 return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4); | |
893 } | |
894 return null; | |
895 } | |
896 | |
897 public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { | |
898 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5); | |
899 } | |
900 | |
901 /** | |
902 * @see #logAndIndent(int, String, Object) | |
903 */ | |
904 public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { | |
905 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
906 return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4, arg5); | |
907 } | |
908 return null; | |
909 } | |
910 | |
911 public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { | |
912 return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6); | |
913 } | |
914 | |
915 /** | |
916 * @see #logAndIndent(int, String, Object) | |
917 */ | |
918 public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { | |
919 if (ENABLED && Debug.isLogEnabled(logLevel)) { | |
920 return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6); | |
921 } | |
922 return null; | |
923 } | |
924 | |
925 /** | |
926 * A convenience function which combines {@link #logv(int, String, Object...)} and | |
927 * {@link #indent()}. | |
928 * | |
929 * @param format a format string | |
930 * @param args the arguments referenced by the format specifiers in {@code format} | |
931 * @return an object that reverts to the current indentation level when | |
932 * {@linkplain Indent#close() closed} or null if debugging is disabled | |
933 */ | |
934 public static Indent logvAndIndent(int logLevel, String format, Object... args) { | |
935 if (ENABLED) { | |
936 if (Debug.isLogEnabled(logLevel)) { | |
937 return logvAndIndentInternal(logLevel, format, args); | |
938 } | |
939 return null; | |
940 } | |
941 throw new InternalError("Use of Debug.logvAndIndent() must be guarded by a test of Debug.isEnabled()"); | |
942 } | |
943 | |
944 private static Indent logvAndIndentInternal(int logLevel, String format, Object... args) { | |
945 assert ENABLED && Debug.isLogEnabled(logLevel) : "must have checked Debug.isLogEnabled()"; | |
946 DebugScope scope = DebugScope.getInstance(); | |
947 scope.log(logLevel, format, args); | |
948 return scope.pushIndentLogger(); | |
949 } | |
950 | |
951 /** | |
952 * This override exists to catch cases when {@link #logAndIndent(String, Object)} is called with | |
953 * one argument bound to a varargs method parameter. It will bind to this method instead of the | |
954 * single arg variant and produce a deprecation warning instead of silently wrapping the | |
955 * Object[] inside of another Object[]. | |
956 */ | |
957 @Deprecated | |
958 public static void logAndIndent(String format, Object[] args) { | |
959 assert false : "shouldn't use this"; | |
960 logAndIndent(DEFAULT_LOG_LEVEL, format, args); | |
961 } | |
962 | |
963 /** | |
964 * This override exists to catch cases when {@link #logAndIndent(int, String, Object)} is called | |
965 * with one argument bound to a varargs method parameter. It will bind to this method instead of | |
966 * the single arg variant and produce a deprecation warning instead of silently wrapping the | |
967 * Object[] inside of another Object[]. | |
968 */ | |
969 @Deprecated | |
970 public static void logAndIndent(int logLevel, String format, Object[] args) { | |
971 assert false : "shouldn't use this"; | |
972 logvAndIndent(logLevel, format, args); | |
973 } | |
974 | |
975 public static Iterable<Object> context() { | |
976 if (ENABLED) { | |
977 return DebugScope.getInstance().getCurrentContext(); | |
978 } else { | |
979 return Collections.emptyList(); | |
980 } | |
981 } | |
982 | |
983 @SuppressWarnings("unchecked") | |
984 public static <T> List<T> contextSnapshot(Class<T> clazz) { | |
985 if (ENABLED) { | |
986 List<T> result = new ArrayList<>(); | |
987 for (Object o : context()) { | |
988 if (clazz.isInstance(o)) { | |
989 result.add((T) o); | |
990 } | |
991 } | |
992 return result; | |
993 } else { | |
994 return Collections.emptyList(); | |
995 } | |
996 } | |
997 | |
998 /** | |
999 * Searches the current debug scope, bottom up, for a context object that is an instance of a | |
1000 * given type. The first such object found is returned. | |
1001 */ | |
1002 @SuppressWarnings("unchecked") | |
1003 public static <T> T contextLookup(Class<T> clazz) { | |
1004 if (ENABLED) { | |
1005 for (Object o : context()) { | |
1006 if (clazz.isInstance(o)) { | |
1007 return ((T) o); | |
1008 } | |
1009 } | |
1010 } | |
1011 return null; | |
1012 } | |
1013 | |
1014 /** | |
1015 * Creates a {@linkplain DebugMemUseTracker memory use tracker} that is enabled iff debugging is | |
1016 * {@linkplain #isEnabled() enabled}. | |
1017 * <p> | |
1018 * A disabled tracker has virtually no overhead. | |
1019 */ | |
1020 public static DebugMemUseTracker memUseTracker(CharSequence name) { | |
1021 if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) { | |
1022 return VOID_MEM_USE_TRACKER; | |
1023 } | |
1024 return createMemUseTracker("%s", name, null); | |
1025 } | |
1026 | |
1027 /** | |
1028 * Creates a debug memory use tracker. Invoking this method is equivalent to: | |
1029 * | |
1030 * <pre> | |
1031 * Debug.memUseTracker(format, arg, null) | |
1032 * </pre> | |
1033 * | |
1034 * except that the string formatting only happens if metering is enabled. | |
1035 * | |
1036 * @see #metric(String, Object, Object) | |
1037 */ | |
1038 public static DebugMemUseTracker memUseTracker(String format, Object arg) { | |
1039 if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) { | |
1040 return VOID_MEM_USE_TRACKER; | |
1041 } | |
1042 return createMemUseTracker(format, arg, null); | |
1043 } | |
1044 | |
1045 /** | |
1046 * Creates a debug memory use tracker. Invoking this method is equivalent to: | |
1047 * | |
1048 * <pre> | |
1049 * Debug.memUseTracker(String.format(format, arg1, arg2)) | |
1050 * </pre> | |
1051 * | |
1052 * except that the string formatting only happens if memory use tracking is enabled. In | |
1053 * addition, each argument is subject to the following type based conversion before being passed | |
1054 * as an argument to {@link String#format(String, Object...)}: | |
1055 * | |
1056 * <pre> | |
1057 * Type | Conversion | |
1058 * ------------------+----------------- | |
1059 * java.lang.Class | arg.getSimpleName() | |
1060 * | | |
1061 * </pre> | |
1062 * | |
1063 * @see #memUseTracker(CharSequence) | |
1064 */ | |
1065 public static DebugMemUseTracker memUseTracker(String format, Object arg1, Object arg2) { | |
1066 if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) { | |
1067 return VOID_MEM_USE_TRACKER; | |
1068 } | |
1069 return createMemUseTracker(format, arg1, arg2); | |
1070 } | |
1071 | |
1072 private static DebugMemUseTracker createMemUseTracker(String format, Object arg1, Object arg2) { | |
1073 String name = formatDebugName(format, arg1, arg2); | |
1074 return new MemUseTrackerImpl(name, !isUnconditionalMemUseTrackingEnabled); | |
1075 } | |
1076 | |
1077 /** | |
1078 * Creates a {@linkplain DebugMetric metric} that is enabled iff debugging is | |
1079 * {@linkplain #isEnabled() enabled} or the system property whose name is formed by adding to | |
1080 * {@value #ENABLE_METRIC_PROPERTY_NAME_PREFIX} to {@code name} is | |
1081 * {@linkplain Boolean#getBoolean(String) true}. If the latter condition is true, then the | |
1082 * returned metric is {@linkplain DebugMetric#isConditional() unconditional} otherwise it is | |
1083 * conditional. | |
1084 * <p> | |
1085 * A disabled metric has virtually no overhead. | |
1086 */ | |
1087 public static DebugMetric metric(CharSequence name) { | |
1088 if (!areUnconditionalMetricsEnabled() && !ENABLED) { | |
1089 return VOID_METRIC; | |
1090 } | |
1091 return createMetric("%s", name, null); | |
1092 } | |
1093 | |
1094 public static String applyFormattingFlagsAndWidth(String s, int flags, int width) { | |
1095 if (flags == 0 && width < 0) { | |
1096 return s; | |
1097 } | |
1098 StringBuilder sb = new StringBuilder(s); | |
1099 | |
1100 // apply width and justification | |
1101 int len = sb.length(); | |
1102 if (len < width) { | |
1103 for (int i = 0; i < width - len; i++) { | |
1104 if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) { | |
1105 sb.append(' '); | |
1106 } else { | |
1107 sb.insert(0, ' '); | |
1108 } | |
1109 } | |
1110 } | |
1111 | |
1112 String res = sb.toString(); | |
1113 if ((flags & UPPERCASE) == UPPERCASE) { | |
1114 res = res.toUpperCase(); | |
1115 } | |
1116 return res; | |
1117 } | |
1118 | |
1119 /** | |
1120 * Creates a debug metric. Invoking this method is equivalent to: | |
1121 * | |
1122 * <pre> | |
1123 * Debug.metric(format, arg, null) | |
1124 * </pre> | |
1125 * | |
1126 * except that the string formatting only happens if metering is enabled. | |
1127 * | |
1128 * @see #metric(String, Object, Object) | |
1129 */ | |
1130 public static DebugMetric metric(String format, Object arg) { | |
1131 if (!areUnconditionalMetricsEnabled() && !ENABLED) { | |
1132 return VOID_METRIC; | |
1133 } | |
1134 return createMetric(format, arg, null); | |
1135 } | |
1136 | |
1137 /** | |
1138 * Creates a debug metric. Invoking this method is equivalent to: | |
1139 * | |
1140 * <pre> | |
1141 * Debug.metric(String.format(format, arg1, arg2)) | |
1142 * </pre> | |
1143 * | |
1144 * except that the string formatting only happens if metering is enabled. In addition, each | |
1145 * argument is subject to the following type based conversion before being passed as an argument | |
1146 * to {@link String#format(String, Object...)}: | |
1147 * | |
1148 * <pre> | |
1149 * Type | Conversion | |
1150 * ------------------+----------------- | |
1151 * java.lang.Class | arg.getSimpleName() | |
1152 * | | |
1153 * </pre> | |
1154 * | |
1155 * @see #metric(CharSequence) | |
1156 */ | |
1157 public static DebugMetric metric(String format, Object arg1, Object arg2) { | |
1158 if (!areUnconditionalMetricsEnabled() && !ENABLED) { | |
1159 return VOID_METRIC; | |
1160 } | |
1161 return createMetric(format, arg1, arg2); | |
1162 } | |
1163 | |
1164 private static DebugMetric createMetric(String format, Object arg1, Object arg2) { | |
1165 String name = formatDebugName(format, arg1, arg2); | |
1166 boolean conditional = enabledMetrics == null || !findMatch(enabledMetrics, enabledMetricsSubstrings, name); | |
1167 if (!ENABLED && conditional) { | |
1168 return VOID_METRIC; | |
1169 } | |
1170 return new MetricImpl(name, conditional); | |
1171 } | |
1172 | |
1173 /** | |
1174 * Changes the debug configuration for the current thread. | |
1175 * | |
1176 * @param config new configuration to use for the current thread | |
1177 * @return an object that when {@linkplain DebugConfigScope#close() closed} will restore the | |
1178 * debug configuration for the current thread to what it was before this method was | |
1179 * called | |
1180 */ | |
1181 public static DebugConfigScope setConfig(DebugConfig config) { | |
1182 if (ENABLED) { | |
1183 return new DebugConfigScope(config); | |
1184 } else { | |
1185 return null; | |
1186 } | |
1187 } | |
1188 | |
1189 /** | |
1190 * Creates an object for counting value frequencies. | |
1191 */ | |
1192 public static DebugHistogram createHistogram(String name) { | |
1193 return new DebugHistogramImpl(name); | |
1194 } | |
1195 | |
1196 public static DebugConfig silentConfig() { | |
1197 return fixedConfig(0, 0, false, false, false, false, Collections.<DebugDumpHandler> emptyList(), Collections.<DebugVerifyHandler> emptyList(), null); | |
1198 } | |
1199 | |
1200 public static DebugConfig fixedConfig(final int logLevel, final int dumpLevel, final boolean isMeterEnabled, final boolean isMemUseTrackingEnabled, final boolean isTimerEnabled, | |
1201 final boolean isVerifyEnabled, final Collection<DebugDumpHandler> dumpHandlers, final Collection<DebugVerifyHandler> verifyHandlers, final PrintStream output) { | |
1202 return new DebugConfig() { | |
1203 | |
1204 @Override | |
1205 public int getLogLevel() { | |
1206 return logLevel; | |
1207 } | |
1208 | |
1209 public boolean isLogEnabledForMethod() { | |
1210 return logLevel > 0; | |
1211 } | |
1212 | |
1213 @Override | |
1214 public boolean isMeterEnabled() { | |
1215 return isMeterEnabled; | |
1216 } | |
1217 | |
1218 @Override | |
1219 public boolean isMemUseTrackingEnabled() { | |
1220 return isMemUseTrackingEnabled; | |
1221 } | |
1222 | |
1223 @Override | |
1224 public int getDumpLevel() { | |
1225 return dumpLevel; | |
1226 } | |
1227 | |
1228 public boolean isDumpEnabledForMethod() { | |
1229 return dumpLevel > 0; | |
1230 } | |
1231 | |
1232 @Override | |
1233 public boolean isVerifyEnabled() { | |
1234 return isVerifyEnabled; | |
1235 } | |
1236 | |
1237 public boolean isVerifyEnabledForMethod() { | |
1238 return isVerifyEnabled; | |
1239 } | |
1240 | |
1241 @Override | |
1242 public boolean isTimeEnabled() { | |
1243 return isTimerEnabled; | |
1244 } | |
1245 | |
1246 @Override | |
1247 public RuntimeException interceptException(Throwable e) { | |
1248 return null; | |
1249 } | |
1250 | |
1251 @Override | |
1252 public Collection<DebugDumpHandler> dumpHandlers() { | |
1253 return dumpHandlers; | |
1254 } | |
1255 | |
1256 @Override | |
1257 public Collection<DebugVerifyHandler> verifyHandlers() { | |
1258 return verifyHandlers; | |
1259 } | |
1260 | |
1261 @Override | |
1262 public PrintStream output() { | |
1263 return output; | |
1264 } | |
1265 | |
1266 @Override | |
1267 public void addToContext(Object o) { | |
1268 } | |
1269 | |
1270 @Override | |
1271 public void removeFromContext(Object o) { | |
1272 } | |
1273 }; | |
1274 } | |
1275 | |
1276 private static final DebugMetric VOID_METRIC = new DebugMetric() { | |
1277 | |
1278 public void increment() { | |
1279 } | |
1280 | |
1281 public void add(long value) { | |
1282 } | |
1283 | |
1284 public void setConditional(boolean flag) { | |
1285 throw new InternalError("Cannot make void metric conditional"); | |
1286 } | |
1287 | |
1288 public boolean isConditional() { | |
1289 return false; | |
1290 } | |
1291 | |
1292 public long getCurrentValue() { | |
1293 return 0L; | |
1294 } | |
1295 }; | |
1296 | |
1297 private static final DebugMemUseTracker VOID_MEM_USE_TRACKER = new DebugMemUseTracker() { | |
1298 | |
1299 public DebugCloseable start() { | |
1300 return DebugCloseable.VOID_CLOSEABLE; | |
1301 } | |
1302 | |
1303 public long getCurrentValue() { | |
1304 return 0; | |
1305 } | |
1306 }; | |
1307 | |
1308 public static final String ENABLE_UNSCOPED_TIMERS_PROPERTY_NAME = "graal.debug.unscopedTimers"; | |
1309 public static final String ENABLE_UNSCOPED_METRICS_PROPERTY_NAME = "graal.debug.unscopedMetrics"; | |
1310 public static final String ENABLE_UNSCOPED_MEM_USE_TRACKERS_PROPERTY_NAME = "graal.debug.unscopedMemUseTrackers"; | |
1311 | |
1312 /** | |
1313 * @see #timer(CharSequence) | |
1314 */ | |
1315 public static final String ENABLE_TIMER_PROPERTY_NAME_PREFIX = "graal.debug.timer."; | |
1316 | |
1317 /** | |
1318 * @see #metric(CharSequence) | |
1319 */ | |
1320 public static final String ENABLE_METRIC_PROPERTY_NAME_PREFIX = "graal.debug.metric."; | |
1321 | |
1322 /** | |
1323 * Set of unconditionally enabled metrics. Possible values and their meanings: | |
1324 * <ul> | |
1325 * <li>{@code null}: no unconditionally enabled metrics</li> | |
1326 * <li>{@code isEmpty()}: all metrics are unconditionally enabled</li> | |
1327 * <li>{@code !isEmpty()}: use {@link #findMatch(Set, Set, String)} on this set and | |
1328 * {@link #enabledMetricsSubstrings} to determine which metrics are unconditionally enabled</li> | |
1329 * </ul> | |
1330 */ | |
1331 private static final Set<String> enabledMetrics; | |
1332 | |
1333 /** | |
1334 * Set of unconditionally enabled timers. Same interpretation of values as for | |
1335 * {@link #enabledMetrics}. | |
1336 */ | |
1337 private static final Set<String> enabledTimers; | |
1338 | |
1339 private static final Set<String> enabledMetricsSubstrings = new HashSet<>(); | |
1340 private static final Set<String> enabledTimersSubstrings = new HashSet<>(); | |
1341 | |
1342 /** | |
1343 * Specifies if all mem use trackers are unconditionally enabled. | |
1344 */ | |
1345 private static final boolean isUnconditionalMemUseTrackingEnabled; | |
1346 | |
1347 static { | |
1348 Set<String> metrics = new HashSet<>(); | |
1349 Set<String> timers = new HashSet<>(); | |
1350 parseMetricAndTimerSystemProperties(metrics, timers, enabledMetricsSubstrings, enabledTimersSubstrings); | |
1351 metrics = metrics.isEmpty() && enabledMetricsSubstrings.isEmpty() ? null : metrics; | |
1352 timers = timers.isEmpty() && enabledTimersSubstrings.isEmpty() ? null : timers; | |
1353 if (metrics == null && Boolean.getBoolean(ENABLE_UNSCOPED_METRICS_PROPERTY_NAME)) { | |
1354 metrics = Collections.emptySet(); | |
1355 } | |
1356 if (timers == null && Boolean.getBoolean(ENABLE_UNSCOPED_TIMERS_PROPERTY_NAME)) { | |
1357 timers = Collections.emptySet(); | |
1358 } | |
1359 enabledMetrics = metrics; | |
1360 enabledTimers = timers; | |
1361 isUnconditionalMemUseTrackingEnabled = Boolean.getBoolean(ENABLE_UNSCOPED_MEM_USE_TRACKERS_PROPERTY_NAME); | |
1362 } | |
1363 | |
1364 private static boolean findMatch(Set<String> haystack, Set<String> haystackSubstrings, String needle) { | |
1365 if (haystack.isEmpty()) { | |
1366 // Empty haystack means match all | |
1367 return true; | |
1368 } | |
1369 if (haystack.contains(needle)) { | |
1370 return true; | |
1371 } | |
1372 if (!haystackSubstrings.isEmpty()) { | |
1373 for (String h : haystackSubstrings) { | |
1374 if (needle.startsWith(h)) { | |
1375 return true; | |
1376 } | |
1377 } | |
1378 } | |
1379 return false; | |
1380 } | |
1381 | |
1382 public static boolean areUnconditionalTimersEnabled() { | |
1383 return enabledTimers != null; | |
1384 } | |
1385 | |
1386 public static boolean areUnconditionalMetricsEnabled() { | |
1387 return enabledMetrics != null; | |
1388 } | |
1389 | |
1390 protected static void parseMetricAndTimerSystemProperties(Set<String> metrics, Set<String> timers, Set<String> metricsSubstrings, Set<String> timersSubstrings) { | |
1391 do { | |
1392 try { | |
1393 for (Map.Entry<Object, Object> e : System.getProperties().entrySet()) { | |
1394 String name = e.getKey().toString(); | |
1395 if (name.startsWith(ENABLE_METRIC_PROPERTY_NAME_PREFIX) && Boolean.parseBoolean(e.getValue().toString())) { | |
1396 if (name.endsWith("*")) { | |
1397 metricsSubstrings.add(name.substring(ENABLE_METRIC_PROPERTY_NAME_PREFIX.length(), name.length() - 1)); | |
1398 } else { | |
1399 metrics.add(name.substring(ENABLE_METRIC_PROPERTY_NAME_PREFIX.length())); | |
1400 } | |
1401 } | |
1402 if (name.startsWith(ENABLE_TIMER_PROPERTY_NAME_PREFIX) && Boolean.parseBoolean(e.getValue().toString())) { | |
1403 if (name.endsWith("*")) { | |
1404 timersSubstrings.add(name.substring(ENABLE_TIMER_PROPERTY_NAME_PREFIX.length(), name.length() - 1)); | |
1405 } else { | |
1406 timers.add(name.substring(ENABLE_TIMER_PROPERTY_NAME_PREFIX.length())); | |
1407 } | |
1408 } | |
1409 } | |
1410 return; | |
1411 } catch (ConcurrentModificationException e) { | |
1412 // Iterating over the system properties may race with another thread that is | |
1413 // updating the system properties. Simply try again in this case. | |
1414 } | |
1415 } while (true); | |
1416 } | |
1417 | |
1418 /** | |
1419 * Creates a {@linkplain DebugTimer timer} that is enabled iff debugging is | |
1420 * {@linkplain #isEnabled() enabled} or the system property whose name is formed by adding to | |
1421 * {@value #ENABLE_TIMER_PROPERTY_NAME_PREFIX} to {@code name} is | |
1422 * {@linkplain Boolean#getBoolean(String) true}. If the latter condition is true, then the | |
1423 * returned timer is {@linkplain DebugMetric#isConditional() unconditional} otherwise it is | |
1424 * conditional. | |
1425 * <p> | |
1426 * A disabled timer has virtually no overhead. | |
1427 */ | |
1428 public static DebugTimer timer(CharSequence name) { | |
1429 if (!areUnconditionalTimersEnabled() && !ENABLED) { | |
1430 return VOID_TIMER; | |
1431 } | |
1432 return createTimer("%s", name, null); | |
1433 } | |
1434 | |
1435 /** | |
1436 * Creates a debug timer. Invoking this method is equivalent to: | |
1437 * | |
1438 * <pre> | |
1439 * Debug.timer(format, arg, null) | |
1440 * </pre> | |
1441 * | |
1442 * except that the string formatting only happens if timing is enabled. | |
1443 * | |
1444 * @see #timer(String, Object, Object) | |
1445 */ | |
1446 public static DebugTimer timer(String format, Object arg) { | |
1447 if (!areUnconditionalTimersEnabled() && !ENABLED) { | |
1448 return VOID_TIMER; | |
1449 } | |
1450 return createTimer(format, arg, null); | |
1451 } | |
1452 | |
1453 /** | |
1454 * Creates a debug timer. Invoking this method is equivalent to: | |
1455 * | |
1456 * <pre> | |
1457 * Debug.timer(String.format(format, arg1, arg2)) | |
1458 * </pre> | |
1459 * | |
1460 * except that the string formatting only happens if timing is enabled. In addition, each | |
1461 * argument is subject to the following type based conversion before being passed as an argument | |
1462 * to {@link String#format(String, Object...)}: | |
1463 * | |
1464 * <pre> | |
1465 * Type | Conversion | |
1466 * ------------------+----------------- | |
1467 * java.lang.Class | arg.getSimpleName() | |
1468 * | | |
1469 * </pre> | |
1470 * | |
1471 * @see #timer(CharSequence) | |
1472 */ | |
1473 public static DebugTimer timer(String format, Object arg1, Object arg2) { | |
1474 if (!areUnconditionalTimersEnabled() && !ENABLED) { | |
1475 return VOID_TIMER; | |
1476 } | |
1477 return createTimer(format, arg1, arg2); | |
1478 } | |
1479 | |
1480 /** | |
1481 * There are paths where construction of formatted class names are common and the code below is | |
1482 * surprisingly expensive, so compute it once and cache it. | |
1483 */ | |
1484 private static final ClassValue<String> formattedClassName = new ClassValue<String>() { | |
1485 @Override | |
1486 protected String computeValue(Class<?> c) { | |
1487 final String simpleName = c.getSimpleName(); | |
1488 Class<?> enclosingClass = c.getEnclosingClass(); | |
1489 if (enclosingClass != null) { | |
1490 String prefix = ""; | |
1491 while (enclosingClass != null) { | |
1492 prefix = enclosingClass.getSimpleName() + "_" + prefix; | |
1493 enclosingClass = enclosingClass.getEnclosingClass(); | |
1494 } | |
1495 return prefix + simpleName; | |
1496 } else { | |
1497 return simpleName; | |
1498 } | |
1499 } | |
1500 }; | |
1501 | |
1502 public static Object convertFormatArg(Object arg) { | |
1503 if (arg instanceof Class) { | |
1504 return formattedClassName.get((Class<?>) arg); | |
1505 } | |
1506 return arg; | |
1507 } | |
1508 | |
1509 private static String formatDebugName(String format, Object arg1, Object arg2) { | |
1510 return String.format(format, convertFormatArg(arg1), convertFormatArg(arg2)); | |
1511 } | |
1512 | |
1513 private static DebugTimer createTimer(String format, Object arg1, Object arg2) { | |
1514 String name = formatDebugName(format, arg1, arg2); | |
1515 boolean conditional = enabledTimers == null || !findMatch(enabledTimers, enabledTimersSubstrings, name); | |
1516 if (!ENABLED && conditional) { | |
1517 return VOID_TIMER; | |
1518 } | |
1519 return new TimerImpl(name, conditional); | |
1520 } | |
1521 | |
1522 private static final DebugTimer VOID_TIMER = new DebugTimer() { | |
1523 | |
1524 public DebugCloseable start() { | |
1525 return DebugCloseable.VOID_CLOSEABLE; | |
1526 } | |
1527 | |
1528 public void setConditional(boolean flag) { | |
1529 throw new InternalError("Cannot make void timer conditional"); | |
1530 } | |
1531 | |
1532 public boolean isConditional() { | |
1533 return false; | |
1534 } | |
1535 | |
1536 public long getCurrentValue() { | |
1537 return 0L; | |
1538 } | |
1539 | |
1540 public TimeUnit getTimeUnit() { | |
1541 return null; | |
1542 } | |
1543 }; | |
1544 } |