changeset 6451:c9f45d2d96cf

fixed bug in monitor snippets; they are now used for general lowering of monitor operations added support for runtime checking balanced monitors in compiled code expanded debug tracing for monitor snippets
author Doug Simon <doug.simon@oracle.com>
date Wed, 26 Sep 2012 21:47:42 +0200
parents 9214d9ff2fb9
children a89a18a57617
files graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java
diffstat 3 files changed, 272 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java	Wed Sep 26 21:45:20 2012 +0200
+++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java	Wed Sep 26 21:47:42 2012 +0200
@@ -267,7 +267,7 @@
     public static String HIRLowerInstanceOf = "";
     public static String HIRLowerNewInstance = "";
     public static String HIRLowerNewArray = "";
-    public static String HIRLowerMonitors = "MonitorTest";
+    public static String HIRLowerMonitors = "";
     public static String HIRLowerNewMultiArray = "";
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Wed Sep 26 21:47:42 2012 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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 com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.*;
+
+/**
+ * Node that is used to maintain a stack based counter of how many locks
+ * are currently held.
+ */
+public final class MonitorCounterNode extends FloatingNode implements LIRGenLowerable {
+
+    public MonitorCounterNode(Kind wordKind) {
+        super(StampFactory.forWord(wordKind, true));
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
+        StackSlot counter = gen.frameMap().allocateStackBlock(gen.target().wordSize, false);
+        Value result = gen.emitLea(counter);
+        gen.setResult(this, result);
+    }
+
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static Word counter(@ConstantNodeParameter Kind wordKind) {
+        throw new UnsupportedOperationException();
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Wed Sep 26 21:45:20 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Wed Sep 26 21:47:42 2012 +0200
@@ -26,18 +26,21 @@
 import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*;
 import static com.oracle.graal.hotspot.nodes.EndLockScopeNode.*;
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
-import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
 import static com.oracle.graal.snippets.nodes.DirectObjectStoreNode.*;
 
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.util.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.snippets.*;
 import com.oracle.graal.snippets.Snippet.ConstantParameter;
@@ -45,6 +48,7 @@
 import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.snippets.SnippetTemplate.Arguments;
 import com.oracle.graal.snippets.SnippetTemplate.Key;
+import com.oracle.graal.snippets.nodes.*;
 
 /**
  * Snippets used for implementing the monitorenter and monitorexit instructions.
@@ -56,32 +60,19 @@
 public class MonitorSnippets implements SnippetsInterface {
 
     /**
-     * Monitor operations on objects whose type contains this substring will be logged.
+     * Monitor operations on objects whose type contains this substring will be traced.
      */
-    private static final String LOG_TYPE = System.getProperty("graal.monitorsnippets.log");
-
-    private static void log(boolean enabled, String action, Object object) {
-        if (enabled) {
-            Log.print(action);
-            Log.print(' ');
-            Log.printlnObject(object);
-        }
-    }
+    private static final String TRACE_TYPE_FILTER = System.getProperty("graal.monitors.trace.typeFilter");
 
     /**
-     * Leaving the breakpoint code in provides a good example of how to use
-     * {@link BreakpointNode} as an intrinsic.
+     * Monitor operations in methods whose fully qualified name contains this substring will be traced.
      */
-    private static final boolean ENABLE_BREAKPOINT = false;
+    private static final String TRACE_METHOD_FILTER = System.getProperty("graal.monitors.trace.methodFilter");
 
-    @SuppressWarnings("unused")
-    @NodeIntrinsic(BreakpointNode.class)
-    static void bkpt(Object object, Word mark, Word tmp, Word value) {
-        throw new GraalInternalError("");
-    }
+    public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalance");
 
     @Snippet
-    public static void monitorenter(@Parameter("object") Object object, @ConstantParameter("logEnabled") boolean logEnabled) {
+    public static void monitorenter(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) {
         verifyOop(object);
 
         // Load the mark word - this includes a null-check on object
@@ -89,6 +80,12 @@
 
         final Word lock = beginLockScope(false, wordKind());
 
+        trace(trace, "           object: 0x%016lx\n", Word.fromObject(object).toLong());
+        trace(trace, "             lock: 0x%016lx\n", lock.toLong());
+        trace(trace, "             mark: 0x%016lx\n", mark.toLong());
+
+        incCounter();
+
         if (useBiasedLocking()) {
             // See whether the lock is currently biased toward our thread and
             // whether the epoch is still valid.
@@ -106,9 +103,12 @@
                 final Word prototypeMarkWord = loadWordFromObject(hub, prototypeMarkWordOffset());
                 final Word thread = thread();
                 final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace());
+                trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord.toLong());
+                trace(trace, "           thread: 0x%016lx\n", thread.toLong());
+                trace(trace, "              tmp: 0x%016lx\n", tmp.toLong());
                 if (tmp == Word.zero()) {
                     // Object is already biased to current thread -> done
-                    log(logEnabled, "+lock{bias}", object);
+                    trace(trace, "+lock{bias:existing}", object);
                     return;
                 }
 
@@ -117,6 +117,10 @@
                 // figure out more details about the state of the mark word in order to
                 // know what operations can be legally performed on the object's
                 // mark word.
+
+                // If the low three bits in the xor result aren't clear, that means
+                // the prototype header is no longer biasable and we have to revoke
+                // the bias on this object.
                 if (tmp.and(biasedLockMaskInPlace()) == Word.zero()) {
                     // Biasing is still enabled for object's type. See whether the
                     // epoch of the current bias is still valid, meaning that the epoch
@@ -127,7 +131,7 @@
                     // that the current epoch is invalid in order to do this because
                     // otherwise the manipulations it performs on the mark word are
                     // illegal.
-                    if (tmp.and(epochMaskInPlace()) != Word.zero()) {
+                    if (tmp.and(epochMaskInPlace()) == Word.zero()) {
                         // The epoch of the current bias is still valid but we know nothing
                         // about the owner; it might be set or it might be clear. Try to
                         // acquire the bias of the object using an atomic operation. If this
@@ -136,35 +140,37 @@
                         // don't accidentally blow away another thread's valid bias.
                         Word unbiasedMark = mark.and(biasedLockMaskInPlace() | ageMaskInPlace() | epochMaskInPlace());
                         Word biasedMark = unbiasedMark.or(thread);
+                        trace(trace, "     unbiasedMark: 0x%016lx\n", unbiasedMark.toLong());
+                        trace(trace, "       biasedMark: 0x%016lx\n", biasedMark.toLong());
                         if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark) == unbiasedMark) {
                             // Object is now biased to current thread -> done
-                            log(logEnabled, "+lock{bias}", object);
+                            trace(trace, "+lock{bias:acquired}", object);
                             return;
                         }
-                        // If the biasing toward our thread failed, this means that
-                        // another thread succeeded in biasing it toward itself and we
-                        // need to revoke that bias. The revocation will occur in the
-                        // interpreter runtime in the slow case.
-                        log(logEnabled, "+lock{stub:revoke}", object);
+                        // If the biasing toward our thread failed, this means that another thread
+                        // owns the bias and we need to revoke that bias. The revocation will occur
+                        // in the interpreter runtime.
+                        trace(trace, "+lock{stub:revoke}", object);
                         MonitorEnterStubCall.call(object, lock);
                         return;
                     } else {
                         // At this point we know the epoch has expired, meaning that the
-                        // current "bias owner", if any, is actually invalid. Under these
-                        // circumstances _only_, we are allowed to use the current mark word
+                        // current bias owner, if any, is actually invalid. Under these
+                        // circumstances _only_, are we allowed to use the current mark word
                         // value as the comparison value when doing the CAS to acquire the
                         // bias in the current epoch. In other words, we allow transfer of
                         // the bias from one thread to another directly in this situation.
                         Word biasedMark = prototypeMarkWord.or(thread);
+                        trace(trace, "       biasedMark: 0x%016lx\n", biasedMark.toLong());
                         if (compareAndSwap(object, markOffset(), mark, biasedMark) == mark) {
                             // Object is now biased to current thread -> done
-                            log(logEnabled, "+lock{bias}", object);
+                            trace(trace, "+lock{bias:transfer}", object);
                             return;
                         }
                         // If the biasing toward our thread failed, then another thread
                         // succeeded in biasing it toward itself and we need to revoke that
                         // bias. The revocation will occur in the runtime in the slow case.
-                        log(logEnabled, "+lock{stub:epoch-expired}", object);
+                        trace(trace, "+lock{stub:epoch-expired}", object);
                         MonitorEnterStubCall.call(object, lock);
                         return;
                     }
@@ -192,6 +198,7 @@
 
         // Create the unlocked mark word pattern
         Word unlockedMark = mark.or(unlockedMask());
+        trace(trace, "     unlockedMark: 0x%016lx\n", unlockedMark.toLong());
 
         // Copy this unlocked mark word into the lock slot on the stack
         storeWord(lock, lockDisplacedMarkOffset(), 0, unlockedMark);
@@ -200,6 +207,7 @@
         // (address of) the lock slot into the object's mark word.
         Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock);
         if (currentMark != unlockedMark) {
+            trace(trace, "      currentMark: 0x%016lx\n", currentMark.toLong());
             // The mark word in the object header was not the same.
             // Either the object is locked by another thread or is already locked
             // by the current thread. The latter is true if the mark word
@@ -219,21 +227,22 @@
             final Word stackPointer = stackPointer();
             if (currentMark.minus(stackPointer).and(alignedMask.minus(pageSize())) != Word.zero()) {
                 // Most likely not a recursive lock, go into a slow runtime call
-                log(logEnabled, "+lock{stub:failed-cas}", object);
+                trace(trace, "+lock{stub:failed-cas}", object);
                 MonitorEnterStubCall.call(object, lock);
                 return;
             } else {
                 // Recursively locked => write 0 to the lock slot
                 storeWord(lock, lockDisplacedMarkOffset(), 0, Word.zero());
-                log(logEnabled, "+lock{recursive}", object);
+                trace(trace, "+lock{recursive}", object);
             }
         } else {
-            log(logEnabled, "+lock{cas}", object);
+            trace(trace, "+lock{cas}", object);
         }
     }
 
     @Snippet
     public static void monitorenterEliminated() {
+        incCounter();
         beginLockScope(true, wordKind());
     }
 
@@ -241,20 +250,22 @@
      * Calls straight out to the monitorenter stub.
      */
     @Snippet
-    public static void monitorenterStub(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("logEnabled") boolean logEnabled) {
+    public static void monitorenterStub(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("trace") boolean trace) {
         verifyOop(object);
+        incCounter();
         if (checkNull && object == null) {
             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
         }
         // BeginLockScope nodes do not read from object so a use of object
         // cannot float about the null check above
         final Word lock = beginLockScope(false, wordKind());
-        log(logEnabled, "+lock{stub}", object);
+        trace(trace, "+lock{stub}", object);
         MonitorEnterStubCall.call(object, lock);
     }
 
     @Snippet
-    public static void monitorexit(@Parameter("object") Object object, @ConstantParameter("logEnabled") boolean logEnabled) {
+    public static void monitorexit(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) {
+        trace(trace, "           object: 0x%016lx\n", Word.fromObject(object).toLong());
         if (useBiasedLocking()) {
             // Check for biased locking unlock case, which is a no-op
             // Note: we do not have to check the thread ID for two reasons.
@@ -263,9 +274,11 @@
             // lock, the object could not be rebiased toward another thread, so
             // the bias bit would be clear.
             final Word mark = loadWordFromObject(object, markOffset());
+            trace(trace, "             mark: 0x%016lx\n", mark.toLong());
             if (mark.and(biasedLockMaskInPlace()).toLong() == biasedLockPattern()) {
                 endLockScope();
-                log(logEnabled, "-lock{bias}", object);
+                decCounter();
+                trace(trace, "-lock{bias}", object);
                 return;
             }
         }
@@ -274,10 +287,11 @@
 
         // Load displaced mark
         final Word displacedMark = loadWordFromWord(lock, lockDisplacedMarkOffset());
+        trace(trace, "    displacedMark: 0x%016lx\n", displacedMark.toLong());
 
         if (displacedMark == Word.zero()) {
             // Recursive locking => done
-            log(logEnabled, "-lock{recursive}", object);
+            trace(trace, "-lock{recursive}", object);
         } else {
             verifyOop(object);
             // Test if object's mark word is pointing to the displaced mark word, and if so, restore
@@ -286,29 +300,90 @@
             if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark) != lock) {
               // The object's mark word was not pointing to the displaced header,
               // we do unlocking via runtime call.
-                log(logEnabled, "-lock{stub}", object);
+                trace(trace, "-lock{stub}", object);
                 MonitorExitStubCall.call(object);
             } else {
-                log(logEnabled, "-lock{cas}", object);
+                trace(trace, "-lock{cas}", object);
             }
         }
         endLockScope();
+        decCounter();
     }
 
     /**
      * Calls straight out to the monitorexit stub.
      */
     @Snippet
-    public static void monitorexitStub(@Parameter("object") Object object, @ConstantParameter("logEnabled") boolean logEnabled) {
+    public static void monitorexitStub(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) {
         verifyOop(object);
-        log(logEnabled, "-lock{stub}", object);
+        trace(trace, "-lock{stub}", object);
         MonitorExitStubCall.call(object);
         endLockScope();
+        decCounter();
     }
 
     @Snippet
     public static void monitorexitEliminated() {
         endLockScope();
+        decCounter();
+    }
+
+    private static void trace(boolean enabled, String action, Object object) {
+        if (enabled) {
+            Log.print(action);
+            Log.print(' ');
+            Log.printlnObject(object);
+        }
+    }
+
+    private static void trace(boolean enabled, String format, long value) {
+        if (enabled) {
+            Log.printf(format, value);
+        }
+    }
+
+    /**
+     * Leaving the breakpoint code in to provide an example of how to use the {@link BreakpointNode} intrinsic.
+     */
+    private static final boolean ENABLE_BREAKPOINT = false;
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic(BreakpointNode.class)
+    static void bkpt(Object object, Word mark, Word tmp, Word value) {
+        throw new GraalInternalError("");
+    }
+
+    private static void incCounter() {
+        if (CHECK_BALANCED_MONITORS) {
+            final Word counter = MonitorCounterNode.counter(wordKind());
+            final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int);
+            DirectObjectStoreNode.storeInt(counter, 0, 0, count + 1);
+        }
+    }
+
+    private static void decCounter() {
+        if (CHECK_BALANCED_MONITORS) {
+            final Word counter = MonitorCounterNode.counter(wordKind());
+            final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int);
+            DirectObjectStoreNode.storeInt(counter, 0, 0, count - 1);
+        }
+    }
+
+    @Snippet
+    private static void initCounter() {
+        final Word counter = MonitorCounterNode.counter(wordKind());
+        DirectObjectStoreNode.storeInt(counter, 0, 0, 0);
+    }
+
+    @Snippet
+    private static void checkCounter(String errMsg) {
+        final Word counter = MonitorCounterNode.counter(wordKind());
+        final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int);
+        if (count != 0) {
+            Log.print(errMsg);
+            Log.println(count);
+            DirectObjectStoreNode.storeInt(Word.zero(), 0, 0, count + 1);
+        }
     }
 
     public static class Templates extends AbstractTemplates<MonitorSnippets> {
@@ -319,6 +394,8 @@
         private final ResolvedJavaMethod monitorexitStub;
         private final ResolvedJavaMethod monitorenterEliminated;
         private final ResolvedJavaMethod monitorexitEliminated;
+        private final ResolvedJavaMethod initCounter;
+        private final ResolvedJavaMethod checkCounter;
         private final boolean useFastLocking;
 
         public Templates(CodeCacheProvider runtime, boolean useFastLocking) {
@@ -329,36 +406,34 @@
             monitorexitStub = snippet("monitorexitStub", Object.class, boolean.class);
             monitorenterEliminated = snippet("monitorenterEliminated");
             monitorexitEliminated = snippet("monitorexitEliminated");
+            initCounter = snippet("initCounter");
+            checkCounter = snippet("checkCounter", String.class);
             this.useFastLocking = useFastLocking;
         }
 
-        static boolean isLoggingEnabledFor(ValueNode object) {
-            ResolvedJavaType type = object.objectStamp().type();
-            if (LOG_TYPE == null) {
-                return false;
-            } else {
-                if (LOG_TYPE.length() == 0) {
-                    return true;
-                }
-                if (type == null) {
-                    return false;
-                }
-                return (type.name().contains(LOG_TYPE));
-            }
-        }
+        public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) {
+            StructuredGraph graph = (StructuredGraph) monitorenterNode.graph();
 
-        public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) {
+            checkBalancedMonitors(graph);
+
             FrameState stateAfter = monitorenterNode.stateAfter();
-            ResolvedJavaMethod method = monitorenterNode.eliminated() ? monitorenterEliminated : useFastLocking ? monitorenter : monitorenterStub;
+            boolean eliminated = monitorenterNode.eliminated();
+            ResolvedJavaMethod method = eliminated ? monitorenterEliminated : useFastLocking ? monitorenter : monitorenterStub;
             boolean checkNull = !monitorenterNode.object().stamp().nonNull();
             Key key = new Key(method);
             if (method == monitorenterStub) {
                 key.add("checkNull", checkNull);
             }
-            if (!monitorenterNode.eliminated()) {
-                key.add("logEnabled", isLoggingEnabledFor(monitorenterNode.object()));
+            if (!eliminated) {
+                key.add("trace", isTracingEnabledForType(monitorenterNode.object()) ||
+                                 isTracingEnabledForMethod(stateAfter.method()) ||
+                                 isTracingEnabledForMethod(graph.method()));
             }
-            Arguments arguments = arguments("object", monitorenterNode.object());
+
+            Arguments arguments = new Arguments();
+            if (!eliminated) {
+                arguments.add("object", monitorenterNode.object());
+            }
             SnippetTemplate template = cache.get(key);
             Map<Node, Node> nodes = template.instantiate(runtime, monitorenterNode, arguments);
             for (Node n : nodes.values()) {
@@ -370,13 +445,20 @@
         }
 
         public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) {
+            StructuredGraph graph = (StructuredGraph) monitorexitNode.graph();
             FrameState stateAfter = monitorexitNode.stateAfter();
-            ResolvedJavaMethod method = monitorexitNode.eliminated() ? monitorexitEliminated : useFastLocking ? monitorexit : monitorexitStub;
+            boolean eliminated = monitorexitNode.eliminated();
+            ResolvedJavaMethod method = eliminated ? monitorexitEliminated : useFastLocking ? monitorexit : monitorexitStub;
             Key key = new Key(method);
-            if (!monitorexitNode.eliminated()) {
-                key.add("logEnabled", isLoggingEnabledFor(monitorexitNode.object()));
+            if (!eliminated) {
+                key.add("trace", isTracingEnabledForType(monitorexitNode.object()) ||
+                                 isTracingEnabledForMethod(stateAfter.method()) ||
+                                 isTracingEnabledForMethod(graph.method()));
             }
-            Arguments arguments = arguments("object", monitorexitNode.object());
+            Arguments arguments = new Arguments();
+            if (!eliminated) {
+                arguments.add("object", monitorexitNode.object());
+            }
             SnippetTemplate template = cache.get(key);
             Map<Node, Node> nodes = template.instantiate(runtime, monitorexitNode, arguments);
             for (Node n : nodes.values()) {
@@ -386,5 +468,69 @@
                 }
             }
         }
+
+        static boolean isTracingEnabledForType(ValueNode object) {
+            ResolvedJavaType type = object.objectStamp().type();
+            if (TRACE_TYPE_FILTER == null) {
+                return false;
+            } else {
+                if (TRACE_TYPE_FILTER.length() == 0) {
+                    return true;
+                }
+                if (type == null) {
+                    return false;
+                }
+                return (type.name().contains(TRACE_TYPE_FILTER));
+            }
+        }
+
+        static boolean isTracingEnabledForMethod(ResolvedJavaMethod method) {
+            if (TRACE_METHOD_FILTER == null) {
+                return false;
+            } else {
+                if (TRACE_METHOD_FILTER.length() == 0) {
+                    return true;
+                }
+                if (method == null) {
+                    return false;
+                }
+                return (MetaUtil.format("%H.%n", method).contains(TRACE_METHOD_FILTER));
+            }
+        }
+
+        /**
+         * If balanced monitor checking is enabled then nodes are inserted at the start and
+         * all return points of the graph to initialize and check the monitor counter
+         * respectively.
+         */
+        private void checkBalancedMonitors(StructuredGraph graph) {
+            if (CHECK_BALANCED_MONITORS) {
+                NodeIterable<MonitorCounterNode> nodes = graph.getNodes().filter(MonitorCounterNode.class);
+                if (nodes.isEmpty()) {
+                    // Only insert the nodes if this is the first monitorenter being lowered.
+                    JavaType returnType = initCounter.signature().returnType(initCounter.holder());
+                    MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, initCounter, new ValueNode[0], returnType));
+                    InvokeNode invoke = graph.add(new InvokeNode(callTarget, 0, -1));
+                    invoke.setStateAfter(graph.start().stateAfter());
+                    graph.addAfterFixed(graph.start(), invoke);
+                    StructuredGraph inlineeGraph = (StructuredGraph) initCounter.compilerStorage().get(Graph.class);
+                    InliningUtil.inline(invoke, inlineeGraph, false);
+
+                    List<ReturnNode> rets = graph.getNodes().filter(ReturnNode.class).snapshot();
+                    for (ReturnNode ret : rets) {
+                        returnType = checkCounter.signature().returnType(checkCounter.holder());
+                        ConstantNode errMsg = ConstantNode.forObject("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()), runtime, graph);
+                        callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter, new ValueNode[] {errMsg}, returnType));
+                        invoke = graph.add(new InvokeNode(callTarget, 0, -1));
+                        List<ValueNode> stack = Collections.emptyList();
+                        FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false, null);
+                        invoke.setStateAfter(graph.add(stateAfter));
+                        graph.addBeforeFixed(ret, invoke);
+                        inlineeGraph = (StructuredGraph) checkCounter.compilerStorage().get(Graph.class);
+                        InliningUtil.inline(invoke, inlineeGraph, false);
+                    }
+                }
+            }
+        }
     }
 }