DebugOperations.java
/*
* Copyright (c) 2014 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 org.jruby.truffle.runtime;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeUtil;
import org.jruby.truffle.runtime.backtrace.Backtrace;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.methods.RubyMethod;
import java.util.ArrayList;
import java.util.List;
public abstract class DebugOperations {
public static String inspect(RubyContext context, Object object) {
CompilerAsserts.neverPartOfCompilation();
final Object inspected = send(context, object, "inspect", null);
if (inspected == null) {
return String.format("%s@%x", object.getClass().getSimpleName(), object.hashCode());
}
return inspected.toString();
}
public static Object send(RubyContext context, Object object, String methodName, RubyProc block, Object... arguments) {
CompilerAsserts.neverPartOfCompilation();
final RubyMethod method = ModuleOperations.lookupMethod(context.getCoreLibrary().getMetaClass(object), methodName);
if (method == null) {
return null;
}
return method.getCallTarget().call(
RubyArguments.pack(method, method.getDeclarationFrame(), object, block, arguments));
}
public static void panic(RubyContext context, Node currentNode, String message) {
CompilerDirectives.transferToInterpreter();
System.err.println("=========================== JRuby+Truffle Debug Report ========================");
if (message != null) {
System.err.println();
System.err.println("Stopped because: " + message);
}
System.err.println();
System.err.println(" =========================== Ruby Bracktrace =========================== ");
System.err.println();
try {
for (String line : Backtrace.PANIC_FORMATTER.format(context, null, RubyCallStack.getBacktrace(currentNode))) {
System.err.println(line);
}
} catch (Throwable e) {
e.printStackTrace();
}
System.err.println();
System.err.println(" ========================== AST Backtrace ========================== ");
System.err.println();
try {
printASTBacktrace(currentNode);
} catch (Throwable e) {
e.printStackTrace();
}
System.err.println();
System.err.println(" =========================== Java Backtrace ============================ ");
System.err.println();
new Exception().printStackTrace();
System.err.println();
System.err.println("===============================================================================");
System.exit(1);
}
public static void printASTBacktrace(final Node currentNode) {
if (currentNode != null) {
printMethodASTBacktrace(currentNode);
}
Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<Object>() {
@Override
public Object visitFrame(FrameInstance frameInstance) {
printMethodASTBacktrace(frameInstance.getCallNode());
return null;
}
});
}
private static void printMethodASTBacktrace(Node currentNode) {
final List<Node> activeNodes = new ArrayList<>();
activeNodes.addAll(NodeUtil.findAllParents(currentNode, Node.class));
activeNodes.add(currentNode);
printASTForBacktrace(currentNode.getRootNode(), activeNodes, 0);
}
private static void printASTForBacktrace(Node node, List<Node> activeNodes, int indentation) {
for (int n = 0; n < indentation; n++) {
System.err.print(" ");
}
if (activeNodes.contains(node)) {
System.err.print("-> ");
} else {
System.err.print(" ");
}
System.err.println(node);
for (Node child : node.getChildren()) {
if (child != null) {
printASTForBacktrace(child, activeNodes, indentation + 1);
}
}
}
}