--- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java 2017-07-07 09:32:21.000000000 -0700 +++ /dev/null 2017-07-07 09:32:21.000000000 -0700 @@ -1,579 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.debug.internal; - -import java.io.PrintStream; -import java.util.Iterator; -import java.util.concurrent.Callable; -import java.util.concurrent.atomic.AtomicLong; - -import org.graalvm.compiler.debug.Debug; -import org.graalvm.compiler.debug.DebugConfig; -import org.graalvm.compiler.debug.DebugDumpHandler; -import org.graalvm.compiler.debug.DebugVerifyHandler; -import org.graalvm.compiler.debug.DelegatingDebugConfig; -import org.graalvm.compiler.debug.Indent; -import org.graalvm.compiler.debug.JavaMethodContext; -import org.graalvm.compiler.debug.TTY; -import org.graalvm.compiler.debug.TopLevelDebugConfig; - -import jdk.vm.ci.meta.JavaMethod; - -public final class DebugScope implements Debug.Scope { - - private final class IndentImpl implements Indent { - - private static final String INDENTATION_INCREMENT = " "; - - final String indent; - final IndentImpl parentIndent; - - IndentImpl(IndentImpl parentIndent) { - this.parentIndent = parentIndent; - this.indent = (parentIndent == null ? "" : parentIndent.indent + INDENTATION_INCREMENT); - } - - private boolean logScopeName() { - return logScopeName; - } - - private void printScopeName(StringBuilder str, boolean isCurrent) { - if (logScopeName) { - boolean parentPrinted = false; - if (parentIndent != null) { - parentPrinted = parentIndent.logScopeName(); - parentIndent.printScopeName(str, false); - } - /* - * Always print the current scope, scopes with context and the any scope whose - * parent didn't print. This ensure the first new scope always shows up. - */ - if (isCurrent || printContext(null) != 0 || !parentPrinted) { - str.append(indent).append("[thread:").append(Thread.currentThread().getId()).append("] scope: ").append(getQualifiedName()).append(System.lineSeparator()); - } - printContext(str); - logScopeName = false; - } - } - - /** - * Print or count the context objects for the current scope. - */ - private int printContext(StringBuilder str) { - int count = 0; - if (context != null && context.length > 0) { - // Include some context in the scope output - for (Object contextObj : context) { - if (contextObj instanceof JavaMethodContext || contextObj instanceof JavaMethod) { - if (str != null) { - str.append(indent).append("Context: ").append(contextObj).append(System.lineSeparator()); - } - count++; - } - } - } - return count; - } - - public void log(int logLevel, String msg, Object... args) { - if (isLogEnabled(logLevel)) { - StringBuilder str = new StringBuilder(); - printScopeName(str, true); - str.append(indent); - String result = args.length == 0 ? msg : String.format(msg, args); - String lineSep = System.lineSeparator(); - str.append(result.replace(lineSep, lineSep.concat(indent))); - str.append(lineSep); - output.append(str); - lastUsedIndent = this; - } - } - - IndentImpl indent() { - lastUsedIndent = new IndentImpl(this); - return lastUsedIndent; - } - - @Override - public void close() { - if (parentIndent != null) { - lastUsedIndent = parentIndent; - } - } - } - - /** - * Interface for an additional information object per scope. The information object will be - * given to child scopes, but can be explicitly set with - * {@link DebugScope#enhanceWithExtraInfo(CharSequence, ExtraInfo, boolean, Object...)} - */ - public interface ExtraInfo { - - } - - private static final ThreadLocal instanceTL = new ThreadLocal<>(); - private static final ThreadLocal lastClosedTL = new ThreadLocal<>(); - private static final ThreadLocal configTL = new ThreadLocal<>(); - private static final ThreadLocal lastExceptionThrownTL = new ThreadLocal<>(); - - private final DebugScope parent; - private final DebugConfig parentConfig; - private final boolean sandbox; - private IndentImpl lastUsedIndent; - private boolean logScopeName; - - private final Object[] context; - - private DebugValueMap valueMap; - - private String qualifiedName; - private final String unqualifiedName; - - private final ExtraInfo extraInfo; - - private static final AtomicLong uniqueScopeId = new AtomicLong(); - private final long scopeId; - - private static final char SCOPE_SEP = '.'; - - private boolean countEnabled; - private boolean timeEnabled; - private boolean memUseTrackingEnabled; - private boolean verifyEnabled; - private boolean methodMetricsEnabled; - - private int currentDumpLevel; - private int currentLogLevel; - - private PrintStream output; - - public static long getCurrentGlobalScopeId() { - return uniqueScopeId.get(); - } - - public static DebugScope getInstance() { - DebugScope result = instanceTL.get(); - if (result == null) { - DebugScope topLevelDebugScope = new DebugScope(Thread.currentThread()); - instanceTL.set(topLevelDebugScope); - return topLevelDebugScope; - } else { - return result; - } - } - - public static DebugConfig getConfig() { - return configTL.get(); - } - - static final Object[] EMPTY_CONTEXT = new Object[0]; - - private DebugScope(Thread thread) { - this(thread.getName(), null, uniqueScopeId.incrementAndGet(), null, false); - computeValueMap(thread.getName()); - DebugValueMap.registerTopLevel(getValueMap()); - } - - private DebugScope(String unqualifiedName, DebugScope parent, long scopeId, ExtraInfo metaInfo, boolean sandbox, Object... context) { - this.parent = parent; - this.sandbox = sandbox; - this.parentConfig = getConfig(); - this.context = context; - this.scopeId = scopeId; - this.unqualifiedName = unqualifiedName; - this.extraInfo = metaInfo; - if (parent != null) { - logScopeName = !unqualifiedName.equals(""); - } else { - logScopeName = true; - } - - this.output = TTY.out; - assert context != null; - } - - private void computeValueMap(String name) { - if (parent != null) { - for (DebugValueMap child : parent.getValueMap().getChildren()) { - if (child.getName().equals(name)) { - this.valueMap = child; - return; - } - } - this.valueMap = new DebugValueMap(name); - parent.getValueMap().addChild(this.valueMap); - } else { - this.valueMap = new DebugValueMap(name); - } - } - - @Override - public void close() { - instanceTL.set(parent); - configTL.set(parentConfig); - lastClosedTL.set(this); - } - - public boolean isDumpEnabled(int dumpLevel) { - assert dumpLevel >= 0; - return currentDumpLevel >= dumpLevel; - } - - /** - * Enable dumping at the new {@code dumpLevel} for the remainder of enclosing scopes. This only - * works if a {@link TopLevelDebugConfig} was installed at a higher scope. - * - * @param dumpLevel - */ - public static void setDumpLevel(int dumpLevel) { - TopLevelDebugConfig config = fetchTopLevelDebugConfig("setDebugLevel"); - if (config != null) { - config.override(DelegatingDebugConfig.Level.DUMP, dumpLevel); - recursiveUpdateFlags(); - } - } - - /** - * Enable logging at the new {@code logLevel} for the remainder of enclosing scopes. This only - * works if a {@link TopLevelDebugConfig} was installed at a higher scope. - * - * @param logLevel - */ - public static void setLogLevel(int logLevel) { - TopLevelDebugConfig config = fetchTopLevelDebugConfig("setLogLevel"); - if (config != null) { - config.override(DelegatingDebugConfig.Level.LOG, logLevel); - config.delegate(DelegatingDebugConfig.Feature.LOG_METHOD); - recursiveUpdateFlags(); - } - } - - private static void recursiveUpdateFlags() { - DebugScope c = DebugScope.getInstance(); - while (c != null) { - c.updateFlags(); - c = c.parent; - } - } - - private static TopLevelDebugConfig fetchTopLevelDebugConfig(String msg) { - DebugConfig config = getConfig(); - if (config instanceof TopLevelDebugConfig) { - return (TopLevelDebugConfig) config; - } else { - if (config == null) { - TTY.println("DebugScope.%s ignored because debugging is disabled", msg); - } else { - TTY.println("DebugScope.%s ignored because top level delegate config missing", msg); - } - return null; - } - } - - public boolean isVerifyEnabled() { - return verifyEnabled; - } - - public boolean isLogEnabled(int logLevel) { - assert logLevel > 0; - return currentLogLevel >= logLevel; - } - - public boolean isCountEnabled() { - return countEnabled; - } - - public boolean isTimeEnabled() { - return timeEnabled; - } - - public boolean isMethodMeterEnabled() { - return methodMetricsEnabled; - } - - public boolean isMemUseTrackingEnabled() { - return memUseTrackingEnabled; - } - - public void log(int logLevel, String msg, Object... args) { - if (isLogEnabled(logLevel)) { - getLastUsedIndent().log(logLevel, msg, args); - } - } - - public ExtraInfo getExtraInfo() { - return extraInfo; - } - - public long scopeId() { - return scopeId; - } - - public void dump(int dumpLevel, Object object, String formatString, Object... args) { - if (isDumpEnabled(dumpLevel)) { - DebugConfig config = getConfig(); - if (config != null) { - for (DebugDumpHandler dumpHandler : config.dumpHandlers()) { - dumpHandler.dump(object, formatString, args); - } - } - } - } - - /** - * This method exists mainly to allow a debugger (e.g., Eclipse) to force dump a graph. - */ - public static void forceDump(Object object, String format, Object... args) { - DebugConfig config = getConfig(); - if (config != null) { - for (DebugDumpHandler dumpHandler : config.dumpHandlers()) { - dumpHandler.dump(object, format, args); - } - } else { - TTY.println("Forced dump ignored because debugging is disabled - use -Dgraal.ForceDebugEnable=true"); - } - } - - /** - * @see Debug#verify(Object, String) - */ - public void verify(Object object, String formatString, Object... args) { - if (isVerifyEnabled()) { - DebugConfig config = getConfig(); - if (config != null) { - for (DebugVerifyHandler handler : config.verifyHandlers()) { - handler.verify(object, formatString, args); - } - } - } - } - - /** - * Creates and enters a new debug scope which is either a child of the current scope or a - * disjoint top level scope. - * - * @param name the name of the new scope - * @param sandboxConfig the configuration to use for a new top level scope, or null if the new - * scope should be a child scope - * @param newContextObjects objects to be appended to the debug context - * @return the new scope which will be exited when its {@link #close()} method is called - */ - public DebugScope scope(CharSequence name, DebugConfig sandboxConfig, Object... newContextObjects) { - DebugScope newScope = null; - if (sandboxConfig != null) { - newScope = new DebugScope(name.toString(), this, uniqueScopeId.incrementAndGet(), null, true, newContextObjects); - configTL.set(sandboxConfig); - } else { - newScope = this.createChild(name.toString(), this.extraInfo, newContextObjects); - } - instanceTL.set(newScope); - newScope.updateFlags(); - return newScope; - } - - public DebugScope enhanceWithExtraInfo(CharSequence name, ExtraInfo newInfo, boolean newId, Object... newContext) { - DebugScope newScope = createChild(name.toString(), newInfo, newId ? uniqueScopeId.incrementAndGet() : this.scopeId, newContext); - instanceTL.set(newScope); - newScope.updateFlags(); - return newScope; - } - - public RuntimeException handle(Throwable e) { - DebugScope lastClosed = lastClosedTL.get(); - try { - assert lastClosed.parent == this : "Debug.handle() used with no matching Debug.scope(...) or Debug.sandbox(...) " + - "or an exception occurred while opening a scope"; - if (e != lastExceptionThrownTL.get()) { - RuntimeException newException = null; - instanceTL.set(lastClosed); - try (DebugScope s = lastClosed) { - newException = s.interceptException(e); - } - assert instanceTL.get() == this; - assert lastClosed == lastClosedTL.get(); - if (newException == null) { - lastExceptionThrownTL.set(e); - } else { - lastExceptionThrownTL.set(newException); - throw newException; - } - } - } catch (Throwable t) { - t.initCause(e); - throw t; - } - if (e instanceof Error) { - throw (Error) e; - } - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } - throw new RuntimeException(e); - } - - private void updateFlags() { - DebugConfig config = getConfig(); - if (config == null) { - countEnabled = false; - memUseTrackingEnabled = false; - timeEnabled = false; - verifyEnabled = false; - currentDumpLevel = -1; - methodMetricsEnabled = false; - // Be pragmatic: provide a default log stream to prevent a crash if the stream is not - // set while logging - output = TTY.out; - } else { - countEnabled = config.isCountEnabled(); - memUseTrackingEnabled = config.isMemUseTrackingEnabled(); - timeEnabled = config.isTimeEnabled(); - verifyEnabled = config.isVerifyEnabled(); - output = config.output(); - currentDumpLevel = config.getDumpLevel(); - currentLogLevel = config.getLogLevel(); - methodMetricsEnabled = config.isMethodMeterEnabled(); - } - } - - @SuppressWarnings("try") - private RuntimeException interceptException(final Throwable e) { - final DebugConfig config = getConfig(); - if (config != null) { - try (DebugScope s = scope("InterceptException", null, e)) { - return config.interceptException(e); - } catch (Throwable t) { - return new RuntimeException("Exception while intercepting exception", t); - } - } - return null; - } - - private DebugValueMap getValueMap() { - if (valueMap == null) { - computeValueMap(unqualifiedName); - } - return valueMap; - } - - long getCurrentValue(int index) { - return getValueMap().getCurrentValue(index); - } - - void setCurrentValue(int index, long l) { - getValueMap().setCurrentValue(index, l); - } - - private DebugScope createChild(String newName, ExtraInfo newInfo, Object[] newContext) { - return new DebugScope(newName, this, this.scopeId, newInfo, false, newContext); - } - - private DebugScope createChild(String newName, ExtraInfo newInfo, long newId, Object[] newContext) { - return new DebugScope(newName, this, newId, newInfo, false, newContext); - } - - public Iterable getCurrentContext() { - final DebugScope scope = this; - return new Iterable() { - - @Override - public Iterator iterator() { - return new Iterator() { - - DebugScope currentScope = scope; - int objectIndex; - - @Override - public boolean hasNext() { - selectScope(); - return currentScope != null; - } - - private void selectScope() { - while (currentScope != null && currentScope.context.length <= objectIndex) { - currentScope = currentScope.sandbox ? null : currentScope.parent; - objectIndex = 0; - } - } - - @Override - public Object next() { - selectScope(); - if (currentScope != null) { - return currentScope.context[objectIndex++]; - } - throw new IllegalStateException("May only be called if there is a next element."); - } - - @Override - public void remove() { - throw new UnsupportedOperationException("This iterator is read only."); - } - }; - } - }; - } - - public static T call(Callable callable) { - try { - return callable.call(); - } catch (Exception e) { - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } else { - throw new RuntimeException(e); - } - } - } - - public void setConfig(DebugConfig newConfig) { - configTL.set(newConfig); - updateFlags(); - } - - public String getQualifiedName() { - if (qualifiedName == null) { - if (parent == null) { - qualifiedName = unqualifiedName; - } else { - qualifiedName = parent.getQualifiedName() + SCOPE_SEP + unqualifiedName; - } - } - return qualifiedName; - } - - public Indent pushIndentLogger() { - lastUsedIndent = getLastUsedIndent().indent(); - return lastUsedIndent; - } - - public IndentImpl getLastUsedIndent() { - if (lastUsedIndent == null) { - if (parent != null) { - lastUsedIndent = new IndentImpl(parent.getLastUsedIndent()); - } else { - lastUsedIndent = new IndentImpl(null); - } - } - return lastUsedIndent; - } -}