Attached is a patch that makes it possible to include interpreted Ruby
method information in the Java stack trace of a raised exception. This
mechanism would help users of Ruby from Java produce a stack trace that
shows exactly where an error happened, including both Ruby and Java
stack trace information. But it's a little hacky at the moment. If
anyone wants to play with it and clean it up, making sure it doesn't
break anything, I'd appreciate it. It was my 30-minute experiment for
the day.
Here's what the trace looks like: http://pastie.org/185586
- Charlie
diff --git a/src/org/jruby/Main.java b/src/org/jruby/Main.java
index cba95ab..32fd791 100644
--- a/src/org/jruby/Main.java
+++ b/src/org/jruby/Main.java
@@ -154,6 +154,7 @@ public class Main {
}
}
} catch (RaiseException rj) {
+ rj.printStackTrace();
RubyException raisedException = rj.getException();
if
(runtime.fastGetClass("SystemExit").isInstance(raisedException)) {
IRubyObject status =
raisedException.callMethod(runtime.getCurrentContext(), "status");
diff --git a/src/org/jruby/exceptions/RaiseException.java
b/src/org/jruby/exceptions/RaiseException.java
index 398b800..1a8b837 100644
--- a/src/org/jruby/exceptions/RaiseException.java
+++ b/src/org/jruby/exceptions/RaiseException.java
@@ -140,37 +140,41 @@ public class RaiseException extends JumpException {
runtime.setStackTraces(runtime.getStackTraces() - 1);
}
-
- public void printStackTrace() {
- printStackTrace(System.err);
- }
-
- public void printStackTrace(PrintStream ps) {
- StackTraceElement[] trace = getStackTrace();
- int externalIndex = 0;
- for (int i = trace.length - 1; i > 0; i--) {
- if (trace[i].getClassName().indexOf("org.jruby.evaluator") >= 0) {
- break;
- }
- externalIndex = i;
- }
- IRubyObject backtrace = exception.backtrace();
- Ruby runtime = backtrace.getRuntime();
- if (runtime.getNil() != backtrace) {
- String firstLine =
backtrace.callMethod(runtime.getCurrentContext(),
"first").callMethod(runtime.getCurrentContext(), MethodIndex.TO_S,
"to_s").toString();
- ps.print(firstLine + ": ");
- }
- ps.println(exception.message + " (" +
exception.getMetaClass().toString() + ")");
- exception.printBacktrace(ps);
- ps.println("\t...internal jruby stack elided...");
- for (int i = externalIndex; i < trace.length; i++) {
- ps.println("\tfrom " + trace[i].toString());
- }
- }
- public void printStackTrace(PrintWriter pw) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- printStackTrace(new PrintStream(baos));
- pw.print(baos.toString());
+ public Throwable fillInStackTrace() {
+ return originalFillInStackTrace();
}
+
+// public void printStackTrace() {
+// printStackTrace(System.err);
+// }
+//
+// public void printStackTrace(PrintStream ps) {
+// StackTraceElement[] trace = getStackTrace();
+// int externalIndex = 0;
+// for (int i = trace.length - 1; i > 0; i--) {
+// if (trace[i].getClassName().indexOf("org.jruby.evaluator") >= 0)
{
+// break;
+// }
+// externalIndex = i;
+// }
+// IRubyObject backtrace = exception.backtrace();
+// Ruby runtime = backtrace.getRuntime();
+// if (runtime.getNil() != backtrace) {
+// String firstLine =
backtrace.callMethod(runtime.getCurrentContext(),
"first").callMethod(runtime.getCurrentContext(), MethodIndex.TO_S,
"to_s").toString();
+// ps.print(firstLine + ": ");
+// }
+// ps.println(exception.message + " (" +
exception.getMetaClass().toString() + ")");
+// exception.printBacktrace(ps);
+// ps.println("\t...internal jruby stack elided...");
+// for (int i = externalIndex; i < trace.length; i++) {
+// ps.println("\tfrom " + trace[i].toString());
+// }
+// }
+//
+// public void printStackTrace(PrintWriter pw) {
+// ByteArrayOutputStream baos = new ByteArrayOutputStream();
+// printStackTrace(new PrintStream(baos));
+// pw.print(baos.toString());
+// }
}
diff --git a/src/org/jruby/internal/runtime/methods/DefaultMethod.java
b/src/org/jruby/internal/runtime/methods/DefaultMethod.java
index ee83140..7d23a07 100644
--- a/src/org/jruby/internal/runtime/methods/DefaultMethod.java
+++ b/src/org/jruby/internal/runtime/methods/DefaultMethod.java
@@ -141,6 +141,31 @@ public final class DefaultMethod extends DynamicMethod
implements JumpTarget {
return handleReturn(rj);
} catch (JumpException.RedoJump rj) {
return handleRedo(runtime);
+ } catch (RaiseException e) {
+ e.fillInStackTrace();
+ StackTraceElement[] trace = e.getStackTrace();
+ int interpreterFrames = 0;
+ for (StackTraceElement element : trace) {
+ if
(element.getClassName().equals("org.jruby.evaluator.ASTInterpreter")) {
+ interpreterFrames++;
+ } else if
(element.getClassName().equals("org.jruby.internal.runtime.methods.DefaultMethod"))
{
+ interpreterFrames++;
+ break;
+ } else {
+ interpreterFrames++;
+ }
+ }
+
+ StackTraceElement[] newTrace = new
StackTraceElement[trace.length - interpreterFrames + 1];
+ System.arraycopy(trace, interpreterFrames, newTrace, 0,
trace.length - interpreterFrames);
+
+ newTrace[0] = new
StackTraceElement(implementationClass.getBaseName(), name, position.getFile(),
-1);
+
+ e.setStackTrace(newTrace);
+
+ e.printStackTrace();
+
+ throw e;
} finally {
jitPost(runtime, context, name);
}
@@ -174,6 +199,19 @@ public final class DefaultMethod extends DynamicMethod
implements JumpTarget {
return handleReturn(rj);
} catch (JumpException.RedoJump rj) {
return handleRedo(runtime);
+ } catch (RaiseException e) {
+ //e.fillInStackTrace();
+ StackTraceElement[] trace = e.getStackTrace();
+ int i;
+ for (i = 0; i < trace.length; i++) {
+ if
(trace[i].getClassName().equals("org.jruby.evaluator.ASTInterpreter") &&
trace[i].getMethodName().equals("eval")) break;
+ }
+
+ trace[i] = new
StackTraceElement(implementationClass.getBaseName(), name, position.getFile(),
context.getLine() + 1);
+
+ e.setStackTrace(trace);
+
+ throw e;
} finally {
if (runtime.hasEventHooks()) {
traceReturn(context, runtime, name);
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email