diff graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/TraceManager.java @ 13514:0fbee3eb71f0

Ruby: import project.
author Chris Seaton <chris.seaton@oracle.com>
date Mon, 06 Jan 2014 17:12:09 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/TraceManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.subsystems;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Manages trace events and calls the user's trace method if one is set.
+ * <p>
+ * Once tracing has been enabled via {@link #setTraceProc(RubyProc)}, the underlying instrumentation
+ * remains in effect, along with performance impact.
+ */
+public final class TraceManager {
+
+    private RubyContext context;
+
+    private final AssumedValue<RubyProc> traceProc = new AssumedValue<>("trace-proc", null);
+    private boolean suspended;
+
+    private String lastFile;
+    private int lastLine;
+
+    private final Assumption notTracingAssumption = Truffle.getRuntime().createAssumption("tracing-disabled");
+
+    public TraceManager(RubyContext context) {
+        this.context = context;
+    }
+
+    /**
+     * Produce a trace; it is a runtime error if {@link #hasTraceProc()}{@code == false}.
+     */
+    @CompilerDirectives.SlowPath
+    public void trace(String event, String file, int line, long objectId, RubyBinding binding, String className) {
+        // If tracing is suspended, stop here
+
+        if (suspended) {
+            return;
+        }
+
+        // If the file and line haven't changed since the last trace, stop here
+
+        if (file.equals(lastFile) && line == lastLine) {
+            return;
+        }
+
+        final RubyClass stringClass = context.getCoreLibrary().getStringClass();
+
+        // Suspend tracing while we run the trace proc
+
+        suspended = true;
+
+        try {
+            // Exceptions from within the proc propagate normally
+
+            traceProc.get().call(null, new RubyString(stringClass, event), //
+                            new RubyString(stringClass, file), //
+                            line, //
+                            GeneralConversions.fixnumOrBignum(objectId), //
+                            GeneralConversions.instanceOrNil(binding), //
+                            GeneralConversions.instanceOrNil(className));
+        } finally {
+            // Resume tracing
+
+            suspended = false;
+        }
+
+        // Remember the last trace event file and line
+
+        lastFile = file;
+        lastLine = line;
+    }
+
+    /**
+     * Is there a "trace proc" in effect?
+     */
+    public boolean hasTraceProc() {
+        return traceProc.get() != null;
+    }
+
+    /**
+     * Gets the assumption that there has never yet been tracing enabled. Once the assumption is
+     * invalidated, tracing is presumed permanently enabled even if {@link #hasTraceProc()} returns
+     * {@code false}.
+     */
+    public Assumption getNotTracingAssumption() {
+        return notTracingAssumption;
+    }
+
+    public void setTraceProc(RubyProc newTraceProc) {
+        if (!context.getConfiguration().getTrace()) {
+            throw new RuntimeException("You need the --trace option to use tracing");
+        }
+
+        traceProc.set(newTraceProc);
+        lastFile = null;
+        lastLine = -1;
+
+        notTracingAssumption.invalidate();
+    }
+}