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

Reply via email to