All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.truffle.api.debug.SteppingStrategy Maven / Gradle / Ivy

Go to download

Truffle is a multi-language framework for executing dynamic languages that achieves high performance when combined with Graal.

There is a newer version: 1.0.0-rc7
Show newest version
/*
 * Copyright (c) 2015, 2016, 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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.truffle.api.debug;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.debug.DebuggerSession.SteppingLocation;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.instrumentation.EventContext;

/**
 * Implementation of a strategy for a debugger action that allows execution to continue
 * until it reaches another location e.g "step in" vs. "step over".
 */
abstract class SteppingStrategy {

    /*
     * Indicates that a stepping strategy was consumed by an suspended event.
     */
    private boolean consumed;
    private SteppingStrategy next;

    void consume() {
        consumed = true;
    }

    boolean isConsumed() {
        return consumed;
    }

    abstract boolean step(DebuggerSession steppingSession, EventContext context, SteppingLocation location);

    abstract void initialize();

    boolean isDone() {
        return false;
    }

    boolean isKill() {
        return false;
    }

    boolean isComposable() {
        return false;
    }

    @SuppressWarnings("unused")
    void add(SteppingStrategy nextStrategy) {
        throw new UnsupportedOperationException("Not composable.");
    }

    static SteppingStrategy createKill() {
        return new Kill();
    }

    static SteppingStrategy createAlwaysHalt() {
        return new AlwaysHalt();
    }

    static SteppingStrategy createContinue() {
        return new Continue();
    }

    static SteppingStrategy createStepInto(int stepCount) {
        return new StepInto(stepCount);
    }

    static SteppingStrategy createStepOut(int stepCount) {
        return new StepOut(stepCount);
    }

    static SteppingStrategy createStepOver(int stepCount) {
        return new StepOver(stepCount);
    }

    static SteppingStrategy createComposed(SteppingStrategy strategy1, SteppingStrategy strategy2) {
        return new ComposedStrategy(strategy1, strategy2);
    }

    // TODO (mlvdv) wish there were fast-path access to stack depth
    // TODO (chumer) wish so too
    @TruffleBoundary
    private static int computeStackDepth() {
        FrameInstanceCounter counter = new FrameInstanceCounter();
        Truffle.getRuntime().iterateFrames(counter);
        return counter.getCount() + 1;
    }

    private static class FrameInstanceCounter implements FrameInstanceVisitor {

        private int count;

        public Void visitFrame(FrameInstance frameInstance) {
            count++;
            return null;
        }

        public int getCount() {
            return count;
        }
    }

    private static final class Kill extends SteppingStrategy {

        @Override
        boolean step(DebuggerSession steppingSession, EventContext context, SteppingLocation location) {
            return true;
        }

        @Override
        void initialize() {

        }

        @Override
        public boolean isDone() {
            return true;
        }

        @Override
        public boolean isKill() {
            return true;
        }

        @Override
        public String toString() {
            return "KILL";
        }

    }

    private static final class AlwaysHalt extends SteppingStrategy {

        @Override
        boolean step(DebuggerSession steppingSession, EventContext context, SteppingLocation location) {
            return true;
        }

        @Override
        void initialize() {
        }

        @Override
        public String toString() {
            return "HALT";
        }

    }

    /**
     * Strategy: the null stepping strategy.
     * 
    *
  • User breakpoints are enabled.
  • *
  • Execution continues until either: *
      *
    1. execution arrives at a node with attached user breakpoint, or:
    2. *
    3. execution completes.
    4. *
    *
*/ private static final class Continue extends SteppingStrategy { @Override boolean step(DebuggerSession steppingSession, EventContext context, SteppingLocation location) { return false; } @Override void initialize() { } @Override public boolean isDone() { return true; } @Override public String toString() { return "CONTINUE"; } } /** * Strategy: per-{@link #HALT_TAG} stepping. *
    *
  • User breakpoints are enabled.
  • *
  • Execution continues until either: *
      *
    1. execution arrives at a {@link #HALT_TAG} node, or:
    2. *
    3. execution returns to a {@link #CALL_TAG} node and the call stack is smaller then * when execution started, or:
    4. *
    5. execution completes.
    6. *
    *
* * @see Debugger#prepareStepInto(int) */ private static final class StepInto extends SteppingStrategy { private int startStackDepth; private int unfinishedStepCount; StepInto(int stepCount) { this.unfinishedStepCount = stepCount; } @Override void initialize() { this.startStackDepth = computeStackDepth(); } @Override boolean step(DebuggerSession steppingSession, EventContext context, SteppingLocation location) { if (location == SteppingLocation.BEFORE_STATEMENT) { if (--unfinishedStepCount <= 0) { return true; } } else if (location == SteppingLocation.AFTER_CALL) { if (computeStackDepth() < startStackDepth) { if (--unfinishedStepCount <= 0) { return true; } } } return false; } @Override public String toString() { return String.format("STEP_INTO(startStackDepth=%s, stepCount=%s)", startStackDepth, unfinishedStepCount); } } /** * Strategy: execution to nearest enclosing call site. *
    *
  • User breakpoints are enabled.
  • *
  • Execution continues until either: *
      *
    1. execution arrives at a node with attached user breakpoint, or:
    2. *
    3. execution returns to a CALL node and the call stack is smaller than when * execution started, or:
    4. *
    5. execution completes.
    6. *
    *
* * @see Debugger#prepareStepOut() */ private static final class StepOut extends SteppingStrategy { private int unfinishedStepCount; private int startStackDepth; StepOut(int stepCount) { this.unfinishedStepCount = stepCount; } @Override void initialize() { this.startStackDepth = computeStackDepth(); } @Override boolean step(DebuggerSession steppingSession, EventContext context, SteppingLocation location) { if (location == SteppingLocation.AFTER_CALL) { if (computeStackDepth() < startStackDepth) { if (--unfinishedStepCount <= 0) { return true; } } } return false; } @Override public String toString() { return String.format("STEP_OUT(startStackDepth=%s, stepCount=%s)", startStackDepth, unfinishedStepCount); } } /** * Strategy: per-{@link #HALT_TAG} stepping, so long as not nested in method calls (i.e. at * original stack depth). *
    *
  • User breakpoints are enabled.
  • *
  • Execution continues until either: *
      *
    1. execution arrives at a node holding {@link #HALT_TAG}, with stack depth no more than when * started or:
    2. *
    3. the program completes.
    4. *
    *
*/ private static final class StepOver extends SteppingStrategy { private int startStackDepth; private int unfinishedStepCount; StepOver(int stepCount) { this.unfinishedStepCount = stepCount; } @Override void initialize() { this.startStackDepth = computeStackDepth(); } @Override boolean step(DebuggerSession steppingSession, EventContext context, SteppingLocation location) { if (location == SteppingLocation.BEFORE_STATEMENT) { if (computeStackDepth() <= startStackDepth) { if (--unfinishedStepCount <= 0) { return true; } } } else if (location == SteppingLocation.AFTER_CALL) { if (computeStackDepth() < startStackDepth) { if (--unfinishedStepCount <= 0) { return true; } } } return false; } @Override public String toString() { return String.format("STEP_OVER(startStackDepth=%s, stepCount=%s)", startStackDepth, unfinishedStepCount); } } static final class ComposedStrategy extends SteppingStrategy { private final SteppingStrategy first; private SteppingStrategy last; private SteppingStrategy current; private ComposedStrategy(SteppingStrategy strategy1, SteppingStrategy strategy2) { strategy1.next = strategy2; first = strategy1; current = first; last = strategy2; } @Override void initialize() { assert current == first; current.initialize(); } @Override boolean step(DebuggerSession steppingSession, EventContext context, SteppingLocation location) { boolean hit = current.step(steppingSession, context, location); if (hit) { if (current == last) { return true; } else { current = current.next; current.initialize(); } } return false; } @Override void consume() { assert current == last; last.consume(); } @Override boolean isConsumed() { assert current == last; return last.isConsumed(); } @Override boolean isDone() { if (current == last) { return last.isDone(); } return false; } @Override boolean isKill() { if (current == last) { return last.isKill(); } return false; } @Override boolean isComposable() { return true; } @Override synchronized void add(SteppingStrategy nextStrategy) { last.next = nextStrategy; last = nextStrategy; } @Override public String toString() { StringBuilder all = new StringBuilder(); for (SteppingStrategy s = first; s.next != null; s = s.next) { if (all.length() > 0) { all.append(", "); } all.append(s.toString()); } return "COMPOSED(" + all + ")"; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy