DebugConfigImpl.java revision 13264:48566d838608
1/*
2 * Copyright (c) 2012, 2015, 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 */
23package org.graalvm.compiler.debug;
24
25import static org.graalvm.compiler.debug.DebugContext.BASIC_LEVEL;
26
27import java.io.ByteArrayOutputStream;
28import java.io.PrintStream;
29import java.util.Arrays;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.IdentityHashMap;
33import java.util.List;
34import java.util.Map;
35
36import org.graalvm.compiler.options.OptionValues;
37
38import jdk.vm.ci.code.BailoutException;
39import jdk.vm.ci.meta.JavaMethod;
40
41final class DebugConfigImpl implements DebugConfig {
42
43    private final OptionValues options;
44
45    private final DebugFilter countFilter;
46    private final DebugFilter logFilter;
47    private final DebugFilter trackMemUseFilter;
48    private final DebugFilter timerFilter;
49    private final DebugFilter dumpFilter;
50    private final DebugFilter verifyFilter;
51    private final MethodFilter[] methodFilter;
52    private final List<DebugDumpHandler> dumpHandlers;
53    private final List<DebugVerifyHandler> verifyHandlers;
54    private final PrintStream output;
55
56    DebugConfigImpl(OptionValues options) {
57        this(options, TTY.out, Collections.emptyList(), Collections.emptyList());
58    }
59
60    DebugConfigImpl(OptionValues options, PrintStream output,
61                    List<DebugDumpHandler> dumpHandlers,
62                    List<DebugVerifyHandler> verifyHandlers) {
63        this(options, DebugOptions.Log.getValue(options),
64                        DebugOptions.Count.getValue(options),
65                        DebugOptions.TrackMemUse.getValue(options),
66                        DebugOptions.Time.getValue(options),
67                        DebugOptions.Dump.getValue(options),
68                        DebugOptions.Verify.getValue(options),
69                        DebugOptions.MethodFilter.getValue(options),
70                        output, dumpHandlers, verifyHandlers);
71    }
72
73    DebugConfigImpl(OptionValues options,
74                    String logFilter,
75                    String countFilter,
76                    String trackMemUseFilter,
77                    String timerFilter,
78                    String dumpFilter,
79                    String verifyFilter,
80                    String methodFilter,
81                    PrintStream output,
82                    List<DebugDumpHandler> dumpHandlers,
83                    List<DebugVerifyHandler> verifyHandlers) {
84        this.options = options;
85        this.logFilter = DebugFilter.parse(logFilter);
86        this.countFilter = DebugFilter.parse(countFilter);
87        this.trackMemUseFilter = DebugFilter.parse(trackMemUseFilter);
88        this.timerFilter = DebugFilter.parse(timerFilter);
89        this.dumpFilter = DebugFilter.parse(dumpFilter);
90        this.verifyFilter = DebugFilter.parse(verifyFilter);
91        if (methodFilter == null || methodFilter.isEmpty()) {
92            this.methodFilter = null;
93        } else {
94            this.methodFilter = org.graalvm.compiler.debug.MethodFilter.parse(methodFilter);
95        }
96
97        this.dumpHandlers = Collections.unmodifiableList(dumpHandlers);
98        this.verifyHandlers = Collections.unmodifiableList(verifyHandlers);
99        this.output = output;
100    }
101
102    @Override
103    public OptionValues getOptions() {
104        return options;
105    }
106
107    @Override
108    public int getLogLevel(DebugContext.Scope scope) {
109        return getLevel(scope, logFilter);
110    }
111
112    @Override
113    public boolean isLogEnabledForMethod(DebugContext.Scope scope) {
114        return isEnabledForMethod(scope, logFilter);
115    }
116
117    @Override
118    public boolean isCountEnabled(DebugContext.Scope scope) {
119        return isEnabled(scope, countFilter);
120    }
121
122    @Override
123    public boolean isMemUseTrackingEnabled(DebugContext.Scope scope) {
124        return isEnabled(scope, trackMemUseFilter);
125    }
126
127    @Override
128    public int getDumpLevel(DebugContext.Scope scope) {
129        return getLevel(scope, dumpFilter);
130    }
131
132    @Override
133    public boolean isDumpEnabledForMethod(DebugContext.Scope scope) {
134        return isEnabledForMethod(scope, dumpFilter);
135    }
136
137    @Override
138    public boolean isVerifyEnabled(DebugContext.Scope scope) {
139        return isEnabled(scope, verifyFilter);
140    }
141
142    @Override
143    public boolean isVerifyEnabledForMethod(DebugContext.Scope scope) {
144        return isEnabledForMethod(scope, verifyFilter);
145    }
146
147    @Override
148    public boolean isTimeEnabled(DebugContext.Scope scope) {
149        return isEnabled(scope, timerFilter);
150    }
151
152    @Override
153    public PrintStream output() {
154        return output;
155    }
156
157    private boolean isEnabled(DebugContext.Scope scope, DebugFilter filter) {
158        return getLevel(scope, filter) > 0;
159    }
160
161    private int getLevel(DebugContext.Scope scope, DebugFilter filter) {
162        int level;
163        if (filter == null) {
164            level = 0;
165        } else {
166            String currentScope = scope.getQualifiedName();
167            level = filter.matchLevel(currentScope);
168        }
169        if (level >= 0 && !checkMethodFilter(scope)) {
170            level = -1;
171        }
172        return level;
173    }
174
175    private boolean isEnabledForMethod(DebugContext.Scope scope, DebugFilter filter) {
176        return filter != null && checkMethodFilter(scope);
177    }
178
179    private boolean checkMethodFilter(DebugContext.Scope scope) {
180        if (methodFilter == null) {
181            return true;
182        } else {
183            JavaMethod lastMethod = null;
184            Iterable<Object> context = scope.getCurrentContext();
185            for (Object o : context) {
186                if (methodFilter != null) {
187                    JavaMethod method = DebugConfig.asJavaMethod(o);
188                    if (method != null) {
189                        if (!DebugOptions.MethodFilterRootOnly.getValue(options)) {
190                            if (org.graalvm.compiler.debug.MethodFilter.matches(methodFilter, method)) {
191                                return true;
192                            }
193                        } else {
194                            /*
195                             * The context values operate as a stack so if we want MethodFilter to
196                             * only apply to the root method we have to check only the last method
197                             * seen.
198                             */
199                            lastMethod = method;
200                        }
201                    }
202                }
203            }
204            if (lastMethod != null && org.graalvm.compiler.debug.MethodFilter.matches(methodFilter, lastMethod)) {
205                return true;
206            }
207            return false;
208        }
209    }
210
211    @Override
212    public String toString() {
213        StringBuilder sb = new StringBuilder();
214        sb.append("Debug config:");
215        add(sb, "Log", logFilter);
216        add(sb, "Count", countFilter);
217        add(sb, "Time", timerFilter);
218        add(sb, "Dump", dumpFilter);
219        add(sb, "MethodFilter", methodFilter);
220        return sb.toString();
221    }
222
223    private static void add(StringBuilder sb, String name, Object filter) {
224        if (filter != null) {
225            sb.append(' ');
226            sb.append(name);
227            sb.append('=');
228            if (filter instanceof Object[]) {
229                sb.append(Arrays.toString((Object[]) filter));
230            } else {
231                sb.append(String.valueOf(filter));
232            }
233        }
234    }
235
236    @Override
237    public RuntimeException interceptException(DebugContext debug, Throwable e) {
238        if (e instanceof BailoutException && !DebugOptions.InterceptBailout.getValue(options)) {
239            return null;
240        }
241
242        OptionValues interceptOptions = new OptionValues(options,
243                        DebugOptions.Count, null,
244                        DebugOptions.Time, null,
245                        DebugOptions.TrackMemUse, null,
246                        DebugOptions.Verify, null,
247                        DebugOptions.Dump, ":" + BASIC_LEVEL,
248                        DebugOptions.Log, ":" + BASIC_LEVEL);
249        DebugConfigImpl config = new DebugConfigImpl(interceptOptions, output, dumpHandlers, verifyHandlers);
250        ScopeImpl scope = debug.currentScope;
251        scope.updateFlags(config);
252        try {
253            ByteArrayOutputStream baos = new ByteArrayOutputStream();
254            e.printStackTrace(new PrintStream(baos));
255            debug.log("Exception raised in scope %s: %s", debug.getCurrentScopeName(), baos);
256            Map<Object, Object> firstSeen = new IdentityHashMap<>();
257            for (Object o : debug.context()) {
258                // Only dump a context object once.
259                if (!firstSeen.containsKey(o)) {
260                    firstSeen.put(o, o);
261                    if (DebugOptions.DumpOnError.getValue(options) || DebugOptions.Dump.getValue(options) != null) {
262                        debug.dump(DebugContext.BASIC_LEVEL, o, "Exception: %s", e);
263                    } else {
264                        debug.log("Context obj %s", o);
265                    }
266                }
267            }
268        } finally {
269            scope.updateFlags(this);
270        }
271        return null;
272    }
273
274    @Override
275    public Collection<DebugDumpHandler> dumpHandlers() {
276        return dumpHandlers;
277    }
278
279    @Override
280    public Collection<DebugVerifyHandler> verifyHandlers() {
281        return verifyHandlers;
282    }
283}
284