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(&quot;InliningGraph&quot;, 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(&quot;CompilingStub&quot;, 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 }