changeset 16463:f1d839174e71

Support for specifying log and dump levels.
author Roland Schatz <roland.schatz@oracle.com>
date Thu, 10 Jul 2014 18:29:58 +0200
parents 1a6989c482f6
children 76081918079d aee02665e505
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/DebugFilter.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java
diffstat 9 files changed, 363 insertions(+), 206 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Thu Jul 10 18:29:58 2014 +0200
@@ -384,7 +384,7 @@
 
     public StructuredGraph visualize(StructuredGraph graph, String title) {
         DebugConfig debugConfig = DebugScope.getConfig();
-        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output());
+        DebugConfig fixedConfig = Debug.fixedConfig(0, Debug.DEFAULT_LOG_LEVEL, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output());
         try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
             Debug.dump(graph, title);
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/DebugFilter.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/DebugFilter.java	Thu Jul 10 18:29:58 2014 +0200
@@ -35,52 +35,52 @@
  * <p>
  * These options enable the associated debug facility if their filter matches the
  * {@linkplain DebugScope#getQualifiedName() name} of the {@linkplain Debug#currentScope() current
- * scope}.
+ * scope}. For the {@link GraalDebugConfig#Dump} and {@link GraalDebugConfig#Log} options, the log
+ * or dump level is set. The {@link GraalDebugConfig#Meter} and {@link GraalDebugConfig#Time}
+ * options don't have a level, for them {@code level = 0} means disabled and a {@code level > 0}
+ * means enabled.
  * <p>
- * A filter is a list of comma-separated terms. Each term is interpreted as a glob pattern if it
- * contains a "*" or "?" character. Otherwise, it is interpreted as a substring. If a term starts
- * with "~", then it is an positive term. An input is matched by a filter if any of its positive
- * terms match the input (or it has no positive terms) AND none of its negative terms match the
- * input (or it has no negative terms).
+ * A filter is a list of comma-separated terms of the form {@code <pattern>[:<level>]}.
+ * {@code <pattern>} is interpreted as a glob pattern if it contains a "*" or "?" character.
+ * Otherwise, it is interpreted as a substring. If {@code <pattern>} is empty, it matches every
+ * scope. If {@code :<level>} is omitted, it defaults to {@link Debug#DEFAULT_LOG_LEVEL}. The term
+ * {@code ~<pattern>} is a shorthand for {@code <pattern>:0} to disable a debug facility for a
+ * pattern.
  * <p>
- * Examples of filters include:
- * <p>
+ * The resulting log level of a scope is determined by the <em>last</em> matching term. If no term
+ * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log
+ * level of {@link Debug#DEFAULT_LOG_LEVEL}.
+ *
+ * <h2>Examples of filters</h2>
+ *
  * <ul>
- * <li>
- * 
- * <pre>
- * &quot;&quot;
- * </pre>
- * 
- * Matches any scope.</li>
- * <li>
- * 
- * <pre>
- * &quot;*&quot;
- * </pre>
- * 
- * Matches any scope.</li>
- * <li>
- * 
- * <pre>
- * &quot;CodeGen,CodeInstall&quot;
- * </pre>
- * 
- * Matches a scope whose name contains "CodeGen" or "CodeInstall".</li>
- * <li>
- * 
- * <pre>
- * &quot;Code*&quot;
- * </pre>
- * 
- * Matches a scope whose name starts with "Code".</li>
- * <li>
- * 
- * <pre>
- * &quot;Code,&tilde;Dead&quot;
- * </pre>
- * 
- * Matches a scope whose name contains "Code" but does not contain "Dead".</li>
+ * <li>(empty string)<br>
+ * Matches any scope with log level {@link Debug#DEFAULT_LOG_LEVEL}.
+ *
+ * <li> {@code :1}<br>
+ * Matches any scope with log level 1.
+ *
+ * <li> {@code *}<br>
+ * Matches any scope with log level {@link Debug#DEFAULT_LOG_LEVEL}.
+ *
+ * <li> {@code CodeGen,CodeInstall}<br>
+ * Matches scopes containing "CodeGen" or "CodeInstall", both with log level
+ * {@link Debug#DEFAULT_LOG_LEVEL}.
+ *
+ * <li> {@code CodeGen:2,CodeInstall:1}<br>
+ * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1.
+ *
+ * <li> {@code :1,Dead:2}<br>
+ * Matches scopes containing "Dead" with log level 2, and all other scopes with log level 1.
+ *
+ * <li> {@code :1,Dead:0}<br>
+ * Matches all scopes with log level 1, except those containing "Dead".
+ *
+ * <li> {@code Code*}<br>
+ * Matches scopes starting with "Code" with log level {@link Debug#DEFAULT_LOG_LEVEL}.
+ *
+ * <li> {@code Code,~Dead}<br>
+ * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#DEFAULT_LOG_LEVEL}.
  * </ul>
  */
 class DebugFilter {
@@ -92,69 +92,76 @@
         return new DebugFilter(spec.split(","));
     }
 
-    final Term[] positive;
-    final Term[] negative;
+    private final Term[] terms;
+
+    private DebugFilter(String[] terms) {
+        if (terms.length == 0) {
+            this.terms = null;
+        } else {
+            this.terms = new Term[terms.length];
+            for (int i = 0; i < terms.length; i++) {
+                String t = terms[i];
+                int idx = t.indexOf(':');
 
-    DebugFilter(String[] terms) {
-        List<Term> pos = new ArrayList<>(terms.length);
-        List<Term> neg = new ArrayList<>(terms.length);
-        for (int i = 0; i < terms.length; i++) {
-            String t = terms[i];
-            if (t.startsWith("~")) {
-                neg.add(new Term(t.substring(1)));
-            } else {
-                pos.add(new Term(t));
+                String pattern;
+                int level;
+                if (idx < 0) {
+                    if (t.startsWith("~")) {
+                        pattern = t.substring(1);
+                        level = 0;
+                    } else {
+                        pattern = t;
+                        level = Debug.DEFAULT_LOG_LEVEL;
+                    }
+                } else {
+                    pattern = t.substring(0, idx);
+                    if (idx + 1 < t.length()) {
+                        level = Integer.parseInt(t.substring(idx + 1));
+                    } else {
+                        level = Debug.DEFAULT_LOG_LEVEL;
+                    }
+                }
+
+                this.terms[i] = new Term(pattern, level);
             }
         }
-        this.positive = pos.isEmpty() ? null : pos.toArray(new Term[pos.size()]);
-        this.negative = neg.isEmpty() ? null : neg.toArray(new Term[neg.size()]);
     }
 
     /**
-     * Determines if a given input is matched by this filter.
+     * Check whether a given input is matched by this filter, and determine the log level.
      */
-    public boolean matches(String input) {
-        boolean match = true;
-        if (positive != null) {
-            match = false;
-            for (Term t : positive) {
+    public int matchLevel(String input) {
+        if (terms == null) {
+            return Debug.DEFAULT_LOG_LEVEL;
+        } else {
+            int level = 0;
+            for (Term t : terms) {
                 if (t.matches(input)) {
-                    match = true;
-                    break;
+                    level = t.level;
                 }
             }
+            return level;
         }
-        if (match && negative != null) {
-            for (Term t : negative) {
-                if (t.matches(input)) {
-                    match = false;
-                    break;
-                }
-            }
-        }
-        return match;
     }
 
     @Override
     public String toString() {
-        StringBuilder buf = new StringBuilder("DebugFilter[");
-        String sep = "";
-        if (positive != null) {
-            buf.append(sep).append("pos=").append(Arrays.toString(positive));
-            sep = ", ";
+        StringBuilder buf = new StringBuilder("DebugFilter");
+        if (terms != null) {
+            buf.append(Arrays.toString(terms));
+        } else {
+            buf.append("[]");
         }
-        if (negative != null) {
-            buf.append(sep).append("neg=").append(Arrays.toString(negative));
-            sep = ", ";
-        }
-        return buf.append("]").toString();
+        return buf.toString();
     }
 
-    static class Term {
+    private static class Term {
 
-        final Pattern pattern;
+        private final Pattern pattern;
+        public final int level;
 
-        public Term(String filter) {
+        public Term(String filter, int level) {
+            this.level = level;
             if (filter.isEmpty()) {
                 this.pattern = null;
             } else if (filter.contains("*") || filter.contains("?")) {
@@ -173,7 +180,7 @@
 
         @Override
         public String toString() {
-            return pattern == null ? ".*" : pattern.toString();
+            return (pattern == null ? ".*" : pattern.toString()) + ":" + level;
         }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Thu Jul 10 18:29:58 2014 +0200
@@ -121,8 +121,8 @@
         this.output = output;
     }
 
-    public boolean isLogEnabled() {
-        return isEnabled(logFilter);
+    public int getLogLevel() {
+        return getLevel(logFilter);
     }
 
     public boolean isLogEnabledForMethod() {
@@ -137,8 +137,8 @@
         return isEnabled(trackMemUseFilter);
     }
 
-    public boolean isDumpEnabled() {
-        return isEnabled(dumpFilter);
+    public int getDumpLevel() {
+        return getLevel(dumpFilter);
     }
 
     public boolean isDumpEnabledForMethod() {
@@ -162,15 +162,27 @@
     }
 
     private boolean isEnabled(DebugFilter filter) {
-        return checkDebugFilter(Debug.currentScope(), filter) && checkMethodFilter();
+        return getLevel(filter) > 0;
+    }
+
+    private int getLevel(DebugFilter filter) {
+        int level = checkDebugFilter(Debug.currentScope(), filter);
+        if (level > 0 && !checkMethodFilter()) {
+            level = 0;
+        }
+        return level;
     }
 
     private boolean isEnabledForMethod(DebugFilter filter) {
         return filter != null && checkMethodFilter();
     }
 
-    private static boolean checkDebugFilter(String currentScope, DebugFilter filter) {
-        return filter != null && filter.matches(currentScope);
+    private static int checkDebugFilter(String currentScope, DebugFilter filter) {
+        if (filter == null) {
+            return 0;
+        } else {
+            return filter.matchLevel(currentScope);
+        }
     }
 
     /**
@@ -241,7 +253,7 @@
         if (e instanceof BailoutException) {
             return null;
         }
-        Debug.setConfig(Debug.fixedConfig(true, true, false, false, false, false, dumpHandlers, verifyHandlers, output));
+        Debug.setConfig(Debug.fixedConfig(Debug.DEFAULT_LOG_LEVEL, Debug.DEFAULT_LOG_LEVEL, false, false, false, false, dumpHandlers, verifyHandlers, output));
         Debug.log(String.format("Exception occurred in scope: %s", Debug.currentScope()));
         for (Object o : Debug.context()) {
             if (o instanceof Graph) {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Thu Jul 10 18:29:58 2014 +0200
@@ -82,8 +82,14 @@
         return config.isDumpEnabledForMethod();
     }
 
+    public static final int DEFAULT_LOG_LEVEL = 2;
+
     public static boolean isDumpEnabled() {
-        return ENABLED && DebugScope.getInstance().isDumpEnabled();
+        return isDumpEnabled(DEFAULT_LOG_LEVEL);
+    }
+
+    public static boolean isDumpEnabled(int dumpLevel) {
+        return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel);
     }
 
     /**
@@ -137,7 +143,11 @@
     }
 
     public static boolean isLogEnabled() {
-        return ENABLED && DebugScope.getInstance().isLogEnabled();
+        return isLogEnabled(DEFAULT_LOG_LEVEL);
+    }
+
+    public static boolean isLogEnabled(int logLevel) {
+        return ENABLED && DebugScope.getInstance().isLogEnabled(logLevel);
     }
 
     @SuppressWarnings("unused")
@@ -352,74 +362,106 @@
         }
     }
 
+    public static void log(String msg) {
+        log(DEFAULT_LOG_LEVEL, msg);
+    }
+
     /**
      * Prints a message to the current debug scope's logging stream if logging is enabled.
      *
      * @param msg the message to log
      */
-    public static void log(String msg) {
+    public static void log(int logLevel, String msg) {
         if (ENABLED) {
-            DebugScope.getInstance().log(msg);
+            DebugScope.getInstance().log(logLevel, msg);
         }
     }
 
+    public static void log(String format, Object arg) {
+        log(DEFAULT_LOG_LEVEL, format, arg);
+    }
+
     /**
      * Prints a message to the current debug scope's logging stream if logging is enabled.
      *
      * @param format a format string
      * @param arg the argument referenced by the format specifiers in {@code format}
      */
-    public static void log(String format, Object arg) {
+    public static void log(int logLevel, String format, Object arg) {
         if (ENABLED) {
-            DebugScope.getInstance().log(format, arg);
+            DebugScope.getInstance().log(logLevel, format, arg);
         }
     }
 
+    public static void log(String format, Object arg1, Object arg2) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2);
+    }
+
     /**
-     * @see #log(String, Object)
+     * @see #log(int, String, Object)
      */
-    public static void log(String format, Object arg1, Object arg2) {
+    public static void log(int logLevel, String format, Object arg1, Object arg2) {
         if (ENABLED) {
-            DebugScope.getInstance().log(format, arg1, arg2);
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2);
         }
     }
 
+    public static void log(String format, Object arg1, Object arg2, Object arg3) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
     /**
-     * @see #log(String, Object)
+     * @see #log(int, String, Object)
      */
-    public static void log(String format, Object arg1, Object arg2, Object arg3) {
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3) {
         if (ENABLED) {
-            DebugScope.getInstance().log(format, arg1, arg2, arg3);
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3);
         }
     }
 
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4);
+    }
+
     /**
-     * @see #log(String, Object)
+     * @see #log(int, String, Object)
      */
-    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4) {
         if (ENABLED) {
-            DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4);
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4);
         }
     }
 
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5);
+    }
+
     /**
-     * @see #log(String, Object)
+     * @see #log(int, String, Object)
      */
-    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
         if (ENABLED) {
-            DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4, arg5);
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5);
         }
     }
 
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+
     /**
-     * @see #log(String, Object)
+     * @see #log(int, String, Object)
      */
-    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
         if (ENABLED) {
-            DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4, arg5, arg6);
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6);
         }
     }
 
+    public static void logv(String format, Object... args) {
+        logv(DEFAULT_LOG_LEVEL, format, args);
+    }
+
     /**
      * Prints a message to the current debug scope's logging stream. This method must only be called
      * if debugging is {@linkplain Debug#isEnabled() enabled} as it incurs allocation at the call
@@ -429,11 +471,11 @@
      * @param format a format string
      * @param args the arguments referenced by the format specifiers in {@code format}
      */
-    public static void logv(String format, Object... args) {
+    public static void logv(int logLevel, String format, Object... args) {
         if (!ENABLED) {
             throw new InternalError("Use of Debug.logv() must be guarded by a test of Debug.isEnabled()");
         }
-        DebugScope.getInstance().log(format, args);
+        DebugScope.getInstance().log(logLevel, format, args);
     }
 
     /**
@@ -445,30 +487,58 @@
     @Deprecated
     public static void log(String format, Object[] args) {
         assert false : "shouldn't use this";
-        logv(format, args);
+        log(DEFAULT_LOG_LEVEL, format, args);
+    }
+
+    /**
+     * This override exists to catch cases when {@link #log(int, String, Object)} is called with one
+     * argument bound to a varargs method parameter. It will bind to this method instead of the
+     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void log(int logLevel, String format, Object[] args) {
+        assert false : "shouldn't use this";
+        logv(logLevel, format, args);
     }
 
     public static void dump(Object object, String msg) {
-        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
-            DebugScope.getInstance().dump(object, msg);
+        dump(DEFAULT_LOG_LEVEL, object, msg);
+    }
+
+    public static void dump(int dumpLevel, Object object, String msg) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, msg);
         }
     }
 
     public static void dump(Object object, String format, Object arg) {
-        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
-            DebugScope.getInstance().dump(object, format, arg);
+        dump(DEFAULT_LOG_LEVEL, object, format, arg);
+    }
+
+    public static void dump(int dumpLevel, Object object, String format, Object arg) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, format, arg);
         }
     }
 
     public static void dump(Object object, String format, Object arg1, Object arg2) {
-        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
-            DebugScope.getInstance().dump(object, format, arg1, arg2);
+        dump(DEFAULT_LOG_LEVEL, object, format, arg1, arg2);
+    }
+
+    public static void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, format, arg1, arg2);
         }
     }
 
     public static void dump(Object object, String format, Object arg1, Object arg2, Object arg3) {
-        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
-            DebugScope.getInstance().dump(object, format, arg1, arg2, arg3);
+        dump(DEFAULT_LOG_LEVEL, object, format, arg1, arg2, arg3);
+    }
+
+    public static void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2, Object arg3) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, format, arg1, arg2, arg3);
         }
     }
 
@@ -481,8 +551,20 @@
     @Deprecated
     public static void dump(Object object, String format, Object[] args) {
         assert false : "shouldn't use this";
-        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
-            DebugScope.getInstance().dump(object, format, args);
+        dump(DEFAULT_LOG_LEVEL, object, format, args);
+    }
+
+    /**
+     * This override exists to catch cases when {@link #dump(int, Object, String, Object)} is called
+     * with one argument bound to a varargs method parameter. It will bind to this method instead of
+     * the single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void dump(int dumpLevel, Object object, String format, Object[] args) {
+        assert false : "shouldn't use this";
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, format, args);
         }
     }
 
@@ -537,8 +619,8 @@
      *
      * @return an object that reverts to the current indentation level when
      *         {@linkplain Indent#close() closed} or null if debugging is disabled
-     * @see #logAndIndent(String)
-     * @see #logAndIndent(String, Object)
+     * @see #logAndIndent(int, String)
+     * @see #logAndIndent(int, String, Object)
      */
     public static Indent indent() {
         if (ENABLED) {
@@ -548,6 +630,10 @@
         return null;
     }
 
+    public static Indent logAndIndent(String msg) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, msg);
+    }
+
     /**
      * A convenience function which combines {@link #log(String)} and {@link #indent()}.
      *
@@ -555,13 +641,17 @@
      * @return an object that reverts to the current indentation level when
      *         {@linkplain Indent#close() closed} or null if debugging is disabled
      */
-    public static Indent logAndIndent(String msg) {
+    public static Indent logAndIndent(int logLevel, String msg) {
         if (ENABLED) {
-            return logvAndIndent(msg);
+            return logvAndIndent(logLevel, msg);
         }
         return null;
     }
 
+    public static Indent logAndIndent(String format, Object arg) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg);
+    }
+
     /**
      * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}.
      *
@@ -570,45 +660,54 @@
      * @return an object that reverts to the current indentation level when
      *         {@linkplain Indent#close() closed} or null if debugging is disabled
      */
-    public static Indent logAndIndent(String format, Object arg) {
+    public static Indent logAndIndent(int logLevel, String format, Object arg) {
+        if (ENABLED) {
+            return logvAndIndent(logLevel, format, arg);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, Object arg2) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2) {
         if (ENABLED) {
-            return logvAndIndent(format, arg);
+            return logvAndIndent(logLevel, format, arg1, arg2);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3) {
+        if (ENABLED) {
+            return logvAndIndent(logLevel, format, arg1, arg2, arg3);
         }
         return null;
     }
 
     /**
-     * @see #logAndIndent(String, Object)
-     */
-    public static Indent logAndIndent(String format, Object arg1, Object arg2) {
-        if (ENABLED) {
-            return logvAndIndent(format, arg1, arg2);
-        }
-        return null;
-    }
-
-    /**
-     * @see #logAndIndent(String, Object)
-     */
-    public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) {
-        if (ENABLED) {
-            return logvAndIndent(format, arg1, arg2, arg3);
-        }
-        return null;
-    }
-
-    /**
-     * A convenience function which combines {@link #logv(String, Object...)} and {@link #indent()}.
+     * A convenience function which combines {@link #logv(int, String, Object...)} and
+     * {@link #indent()}.
      *
      * @param format a format string
      * @param args the arguments referenced by the format specifiers in {@code format}
      * @return an object that reverts to the current indentation level when
      *         {@linkplain Indent#close() closed} or null if debugging is disabled
      */
-    public static Indent logvAndIndent(String format, Object... args) {
+    public static Indent logvAndIndent(int logLevel, String format, Object... args) {
         if (ENABLED) {
             DebugScope scope = DebugScope.getInstance();
-            scope.log(format, args);
+            scope.log(logLevel, format, args);
             return scope.pushIndentLogger();
         }
         throw new InternalError("Use of Debug.logvAndIndent() must be guarded by a test of Debug.isEnabled()");
@@ -623,7 +722,19 @@
     @Deprecated
     public static void logAndIndent(String format, Object[] args) {
         assert false : "shouldn't use this";
-        logvAndIndent(format, args);
+        logAndIndent(DEFAULT_LOG_LEVEL, format, args);
+    }
+
+    /**
+     * This override exists to catch cases when {@link #logAndIndent(int, String, Object)} is called
+     * with one argument bound to a varargs method parameter. It will bind to this method instead of
+     * the single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void logAndIndent(int logLevel, String format, Object[] args) {
+        assert false : "shouldn't use this";
+        logvAndIndent(logLevel, format, args);
     }
 
     public static Iterable<Object> context() {
@@ -845,20 +956,20 @@
     }
 
     public static DebugConfig silentConfig() {
-        return fixedConfig(false, false, false, false, false, false, Collections.<DebugDumpHandler> emptyList(), Collections.<DebugVerifyHandler> emptyList(), null);
+        return fixedConfig(0, 0, false, false, false, false, Collections.<DebugDumpHandler> emptyList(), Collections.<DebugVerifyHandler> emptyList(), null);
     }
 
-    public static DebugConfig fixedConfig(final boolean isLogEnabled, final boolean isDumpEnabled, final boolean isMeterEnabled, final boolean isMemUseTrackingEnabled, final boolean isTimerEnabled,
+    public static DebugConfig fixedConfig(final int logLevel, final int dumpLevel, final boolean isMeterEnabled, final boolean isMemUseTrackingEnabled, final boolean isTimerEnabled,
                     final boolean isVerifyEnabled, final Collection<DebugDumpHandler> dumpHandlers, final Collection<DebugVerifyHandler> verifyHandlers, final PrintStream output) {
         return new DebugConfig() {
 
             @Override
-            public boolean isLogEnabled() {
-                return isLogEnabled;
+            public int getLogLevel() {
+                return logLevel;
             }
 
             public boolean isLogEnabledForMethod() {
-                return isLogEnabled;
+                return logLevel > 0;
             }
 
             @Override
@@ -872,12 +983,12 @@
             }
 
             @Override
-            public boolean isDumpEnabled() {
-                return isDumpEnabled;
+            public int getDumpLevel() {
+                return dumpLevel;
             }
 
             public boolean isDumpEnabledForMethod() {
-                return isDumpEnabled;
+                return dumpLevel > 0;
             }
 
             @Override
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Thu Jul 10 18:29:58 2014 +0200
@@ -28,9 +28,16 @@
 public interface DebugConfig {
 
     /**
-     * Determines if logging is on in the {@linkplain Debug#currentScope() current debug scope} .
+     * Determines the current log level in the {@linkplain Debug#currentScope() current debug scope}
+     * .
      */
-    boolean isLogEnabled();
+    int getLogLevel();
+
+    /**
+     * Determines the current dump level in the {@linkplain Debug#currentScope() current debug
+     * scope}.
+     */
+    int getDumpLevel();
 
     /**
      * Determines if logging can be enabled in the current method, regardless of the
@@ -55,14 +62,6 @@
     boolean isMemUseTrackingEnabled();
 
     /**
-     * Determines if dumping is enabled in the {@linkplain Debug#currentScope() current debug scope}
-     * .
-     *
-     * @see Debug#dump(Object, String)
-     */
-    boolean isDumpEnabled();
-
-    /**
      * Determines if dumping can be enabled in the current method, regardless of the
      * {@linkplain Debug#currentScope() current debug scope}.
      */
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Thu Jul 10 18:29:58 2014 +0200
@@ -83,6 +83,18 @@
     private final Map<Feature, Boolean> featureState = new EnumMap<>(Feature.class);
 
     /**
+     * The debug levels of a {@link DelegatingDebugConfig} than can be
+     * {@linkplain DelegatingDebugConfig#override(Level, int) overridden} or
+     * {@linkplain DelegatingDebugConfig#delegate(Level) delegated}.
+     */
+    public enum Level {
+        LOG,
+        DUMP
+    }
+
+    private final Map<Level, Integer> levelState = new EnumMap<>(Level.class);
+
+    /**
      * Creates a config that delegates to the {@link DebugScope#getConfig() current config}.
      */
     public DelegatingDebugConfig() {
@@ -106,18 +118,28 @@
         return this;
     }
 
+    public DelegatingDebugConfig override(Level level, int newLevel) {
+        levelState.put(level, newLevel);
+        return this;
+    }
+
     public DelegatingDebugConfig delegate(Feature feature) {
         featureState.put(feature, null);
         return this;
     }
 
+    public DelegatingDebugConfig delegate(Level level) {
+        levelState.put(level, null);
+        return this;
+    }
+
     @Override
-    public boolean isLogEnabled() {
-        Boolean fs = featureState.get(Feature.LOG);
-        if (fs == null) {
-            return delegate.isLogEnabled();
+    public int getLogLevel() {
+        Integer ls = levelState.get(Level.LOG);
+        if (ls == null) {
+            return delegate.getLogLevel();
         }
-        return fs.booleanValue();
+        return ls.intValue();
     }
 
     public boolean isLogEnabledForMethod() {
@@ -146,12 +168,12 @@
     }
 
     @Override
-    public boolean isDumpEnabled() {
-        Boolean fs = featureState.get(Feature.DUMP);
-        if (fs == null) {
-            return delegate.isDumpEnabled();
+    public int getDumpLevel() {
+        Integer ls = levelState.get(Level.DUMP);
+        if (ls == null) {
+            return delegate.getDumpLevel();
         }
-        return fs.booleanValue();
+        return ls.intValue();
     }
 
     public boolean isDumpEnabledForMethod() {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Thu Jul 10 18:29:58 2014 +0200
@@ -52,8 +52,8 @@
             }
         }
 
-        public void log(String msg, Object... args) {
-            if (isLogEnabled()) {
+        public void log(int logLevel, String msg, Object... args) {
+            if (isLogEnabled(logLevel)) {
                 StringBuilder str = new StringBuilder();
                 printScopeName(str);
                 str.append(indent);
@@ -102,9 +102,10 @@
     private boolean meterEnabled;
     private boolean timeEnabled;
     private boolean memUseTrackingEnabled;
-    private boolean dumpEnabled;
     private boolean verifyEnabled;
-    private boolean logEnabled;
+
+    private int currentDumpLevel;
+    private int currentLogLevel;
 
     private PrintStream output;
 
@@ -163,16 +164,18 @@
         lastClosedTL.set(this);
     }
 
-    public boolean isDumpEnabled() {
-        return dumpEnabled;
+    public boolean isDumpEnabled(int dumpLevel) {
+        assert dumpLevel > 0;
+        return currentDumpLevel >= dumpLevel;
     }
 
     public boolean isVerifyEnabled() {
         return verifyEnabled;
     }
 
-    public boolean isLogEnabled() {
-        return logEnabled;
+    public boolean isLogEnabled(int logLevel) {
+        assert logLevel > 0;
+        return currentLogLevel >= logLevel;
     }
 
     public boolean isMeterEnabled() {
@@ -187,12 +190,12 @@
         return memUseTrackingEnabled;
     }
 
-    public void log(String msg, Object... args) {
-        lastUsedIndent.log(msg, args);
+    public void log(int logLevel, String msg, Object... args) {
+        lastUsedIndent.log(logLevel, msg, args);
     }
 
-    public void dump(Object object, String formatString, Object... args) {
-        if (isDumpEnabled()) {
+    public void dump(int dumpLevel, Object object, String formatString, Object... args) {
+        if (isDumpEnabled(dumpLevel)) {
             DebugConfig config = getConfig();
             if (config != null) {
                 String message = String.format(formatString, args);
@@ -289,9 +292,10 @@
             meterEnabled = false;
             memUseTrackingEnabled = false;
             timeEnabled = false;
-            dumpEnabled = false;
             verifyEnabled = false;
 
+            currentDumpLevel = 0;
+
             // Be pragmatic: provide a default log stream to prevent a crash if the stream is not
             // set while logging
             output = TTY.cachedOut;
@@ -299,10 +303,10 @@
             meterEnabled = config.isMeterEnabled();
             memUseTrackingEnabled = config.isMemUseTrackingEnabled();
             timeEnabled = config.isTimeEnabled();
-            dumpEnabled = config.isDumpEnabled();
             verifyEnabled = config.isVerifyEnabled();
-            logEnabled = config.isLogEnabled();
             output = config.output();
+            currentDumpLevel = config.getDumpLevel();
+            currentLogLevel = config.getLogLevel();
         }
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Thu Jul 10 18:29:58 2014 +0200
@@ -692,7 +692,7 @@
             };
 
             DebugConfig debugConfig = DebugScope.getConfig();
-            DebugConfig fixedConfig = Debug.fixedConfig(false, false, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output());
+            DebugConfig fixedConfig = Debug.fixedConfig(0, 0, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output());
             try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
                 ReentrantNodeIterator.apply(closure, graph.start(), false);
                 new WriteBarrierVerificationPhase().apply(graph);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Thu Jul 10 17:17:17 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Thu Jul 10 18:29:58 2014 +0200
@@ -38,6 +38,8 @@
  */
 public abstract class BasePhase<C> {
 
+    public static final int PHASE_DUMP_LEVEL = 1;
+
     private CharSequence name;
 
     /**
@@ -97,8 +99,8 @@
             this.run(graph, context);
             executionCount.increment();
             inputNodesCount.add(graph.getNodeCount());
-            if (dumpGraph && Debug.isDumpEnabled()) {
-                Debug.dump(graph, "After phase %s", getName());
+            if (dumpGraph && Debug.isDumpEnabled(PHASE_DUMP_LEVEL)) {
+                Debug.dump(PHASE_DUMP_LEVEL, graph, "After phase %s", getName());
             }
             if (Debug.isVerifyEnabled()) {
                 Debug.verify(graph, "After phase %s", getName());