view graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/TraceManager.java @ 14094:3f27e57439ed

Truffle/Instrumentation: significant rearrangement (including moved class) and extension of the Truffle Instrumentation Framework. New interfaces include DebugContext (which can be attached to the ExecutionContext), through which access is provided to possibly language-specific (a) node instrumentation, (b) debug services manager, (c) notification when programs halt, (d) display of language values, and (e) display of variable identifiers.
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Mon, 03 Feb 2014 20:58:23 -0800
parents 0fbee3eb71f0
children
line wrap: on
line source

/*
 * 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();
    }
}