Index: C:/work/thirdparty/jython_2_2_1/src/org/python/core/PyFrame.java =================================================================== --- C:/work/thirdparty/jython_2_2_1/src/org/python/core/PyFrame.java (revision 3741) +++ C:/work/thirdparty/jython_2_2_1/src/org/python/core/PyFrame.java (working copy) @@ -146,6 +146,13 @@ return f_locals; } + // + // Track the current line number. Called by generated code. + // + // This is not to be confused with the CPython method + // frame_setlineno() which causes the interpreter to jump to + // the given line. + // public void setline(int line) { f_lineno = line; if (tracefunc != null) Index: C:/work/thirdparty/jython_2_2_1/src/org/python/core/PythonTraceFunction.java =================================================================== --- C:/work/thirdparty/jython_2_2_1/src/org/python/core/PythonTraceFunction.java (revision 3741) +++ C:/work/thirdparty/jython_2_2_1/src/org/python/core/PythonTraceFunction.java (working copy) @@ -24,8 +24,8 @@ ret = tracefunc.__call__(frame, new PyString(label), arg); } catch(PyException exc) { frame.tracefunc = null; - ts.systemState.tracefunc = null; - ts.systemState.profilefunc = null; + ts.tracefunc = null; + ts.profilefunc = null; throw exc; } finally { ts.tracing = false; Index: C:/work/thirdparty/jython_2_2_1/src/org/python/core/PyTableCode.java =================================================================== --- C:/work/thirdparty/jython_2_2_1/src/org/python/core/PyTableCode.java (revision 3741) +++ C:/work/thirdparty/jython_2_2_1/src/org/python/core/PyTableCode.java (working copy) @@ -167,49 +167,14 @@ ts.frame = frame; // Handle trace function for debugging - PySystemState ss = ts.systemState; - if (ss.tracefunc != null) { - // Jython and CPython differ here. CPython actually lays down - // an extra SET_LINENO bytecode for function definition line. - // This is ostensibly so that a tuple unpacking failure in - // argument passing gets the right line number in the - // traceback. It also means that when tracing a function, - // you'll see two 'line' events, one for the def line and then - // immediately after, one for the first line of the function. - // - // Jython on the other hand only lays down a call in the - // generated Java function to set the line number for the first - // line of the function (i.e. not the def line). This - // difference in behavior doesn't seem to affect arg tuple - // unpacking tracebacks, but it does mean that function tracing - // gives slightly different behavior. Is this bad? Until - // someone complains... no. - // - // The second commented out line fixes this but it is probably - // not the right solution. Better would be to fix the code - // generator to lay down two calls to setline() in the - // classfile. This would allow that call to be optimized out - // when using the -O option. I suppose on the other hand we - // could test that flag here and not call the setline below. - // In either case, it probably doesn't make sense to slow down - // function calling even by this miniscule amount until it's - // shown to have a detrimental effect. - // - // Note also that if you were to print out frame.f_lineno in - // the `call' event handler of your trace function, you'd see - // zero instead of the line of the def. That's what the first - // commented line fixes. - // - // 9-Sep-1999 baw - // -// frame.f_lineno = co_firstlineno; - frame.tracefunc = ss.tracefunc.traceCall(frame); - frame.setline(co_firstlineno); + if (ts.tracefunc != null) { + frame.f_lineno = co_firstlineno; + frame.tracefunc = ts.tracefunc.traceCall(frame); } // Handle trace function for profiling - if (ss.profilefunc != null) { - ss.profilefunc.traceCall(frame); + if (ts.profilefunc != null) { + ts.profilefunc.traceCall(frame); } PyObject ret; @@ -239,8 +204,8 @@ if (frame.tracefunc != null) { frame.tracefunc.traceException(frame, e); } - if (ss.profilefunc != null) { - ss.profilefunc.traceException(frame, e); + if (ts.profilefunc != null) { + ts.profilefunc.traceException(frame, e); } //Rethrow the exception to the next stack frame @@ -253,8 +218,8 @@ frame.tracefunc.traceReturn(frame, ret); } // Handle trace function for profiling - if (ss.profilefunc != null) { - ss.profilefunc.traceReturn(frame, ret); + if (ts.profilefunc != null) { + ts.profilefunc.traceReturn(frame, ret); } // Restore previously defined exception Index: C:/work/thirdparty/jython_2_2_1/src/org/python/core/PySystemState.java =================================================================== --- C:/work/thirdparty/jython_2_2_1/src/org/python/core/PySystemState.java (revision 3741) +++ C:/work/thirdparty/jython_2_2_1/src/org/python/core/PySystemState.java (working copy) @@ -769,25 +769,22 @@ packageManager.addJarDir(directoryPath, cache); } - public TraceFunction tracefunc = null; - public TraceFunction profilefunc = null; public void settrace(PyObject tracefunc) { - //InterpreterState interp = Py.getThreadState().interp; + ThreadState ts = Py.getThreadState(); if (tracefunc == Py.None) { - this.tracefunc = null; + ts.tracefunc = null; } else { - this.tracefunc = new PythonTraceFunction(tracefunc); + ts.tracefunc = new PythonTraceFunction(tracefunc); } } public void setprofile(PyObject profilefunc) { - //InterpreterState interp = Py.getThreadState().interp; - + ThreadState ts = Py.getThreadState(); if (profilefunc == Py.None) { - this.profilefunc = null; + ts.profilefunc = null; } else { - this.profilefunc = new PythonTraceFunction(profilefunc); + ts.profilefunc = new PythonTraceFunction(profilefunc); } } Index: C:/work/thirdparty/jython_2_2_1/src/org/python/core/ThreadState.java =================================================================== --- C:/work/thirdparty/jython_2_2_1/src/org/python/core/ThreadState.java (revision 3741) +++ C:/work/thirdparty/jython_2_2_1/src/org/python/core/ThreadState.java (working copy) @@ -28,6 +28,11 @@ public int recursion_depth = 0; + // Trace callout hook. + public TraceFunction tracefunc = null; + // Profiling callout hook. + public TraceFunction profilefunc = null; + public PyInstance getInitializingProxy() { if (this.initializingProxies == null || this.initializingProxies.empty()) { Index: C:/work/thirdparty/jython_2_2_1/src/org/python/util/InteractiveInterpreter.java =================================================================== --- C:/work/thirdparty/jython_2_2_1/src/org/python/util/InteractiveInterpreter.java (revision 3741) +++ C:/work/thirdparty/jython_2_2_1/src/org/python/util/InteractiveInterpreter.java (working copy) @@ -118,11 +118,11 @@ **/ public void interrupt(ThreadState ts) { TraceFunction breaker = new BreakTraceFunction(); - TraceFunction oldTrace = ts.systemState.tracefunc; - ts.systemState.tracefunc = breaker; + TraceFunction oldTrace = ts.tracefunc; + ts.tracefunc = breaker; if (ts.frame != null) ts.frame.tracefunc = breaker; - ts.systemState.tracefunc = oldTrace; + ts.tracefunc = oldTrace; //ts.thread.join(); } } Index: C:/work/thirdparty/jython_2_2_1/CPythonLib/threading.py =================================================================== --- C:/work/thirdparty/jython_2_2_1/CPythonLib/threading.py (revision 59227) +++ C:/work/thirdparty/jython_2_2_1/CPythonLib/threading.py (working copy) @@ -56,7 +56,19 @@ def _note(self, *args): pass +# Support for profile and trace hooks +_profile_hook = None +_trace_hook = None + +def setprofile(func): + global _profile_hook + _profile_hook = func + +def settrace(func): + global _trace_hook + _trace_hook = func + # Synchronization classes Lock = _allocate_lock @@ -410,6 +422,14 @@ _active_limbo_lock.release() if __debug__: self._note("%s.__bootstrap(): thread started", self) + + if _trace_hook: + self._note("%s.__bootstrap(): registering trace hook", self) + _sys.settrace(_trace_hook) + if _profile_hook: + self._note("%s.__bootstrap(): registering profile hook", self) + _sys.setprofile(_profile_hook) + try: self.run() except SystemExit: