diff -r 0d8f139a6e19 Doc/library/debug.rst --- a/Doc/library/debug.rst Sat Jul 16 07:17:46 2016 +0000 +++ b/Doc/library/debug.rst Wed Aug 03 18:57:46 2016 +0200 @@ -16,3 +16,4 @@ timeit.rst trace.rst tracemalloc.rst + ltrace.rst diff -r 0d8f139a6e19 Doc/library/ltrace.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Doc/library/ltrace.rst Wed Aug 03 18:57:46 2016 +0200 @@ -0,0 +1,44 @@ +ltrace --- ByteCode execution +============================= + +ltrace is a feature of Python where you can see the executed bytecode by your +python interpreter. + +Usage +----- + +In the Python interpreter, you have to define a variable `__ltrace__` and set up +any value :: + + >>> __ltrace__ = True + >>> print("hello") + 0: LOAD_NAME, 0 + push + 2: LOAD_CONST, 0 + push 'hello' + 4: CALL_FUNCTION, 1 + ext_pop 'hello' + hello + ext_pop + push None + 6: PRINT_EXPR + pop None + 8: LOAD_CONST, 1 + push None + 10: RETURN_VALUE + pop None + >>> + + +Once you have finished to trace the byte codes, you can disable this feature in removing +the __ltrace__ variable from the globals dictionary:: + + >>> del __ltrace__ + 0: DELETE_NAME, 0 + 2: LOAD_CONST, 0 + push None + 4: RETURN_VALUE + pop None + >>> print("hello") + hello + >>> diff -r 0d8f139a6e19 Lib/test/test_ltrace.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/test/test_ltrace.py Wed Aug 03 18:57:46 2016 +0200 @@ -0,0 +1,43 @@ +import sys +import unittest +import test.support +from test.support.script_helper import (assert_python_ok, make_script) + +LTRACE_SCRIPT = """ +def func(): + return 1 + +__ltrace__ = True + +func() +""" + +REGEXP = b'0: LOAD_CONST, 1\n2: RETURN_VALUE\n16: POP_TOP\n18: LOAD_CONST, 3\n' \ + b'20: RETURN_VALUE\npush 1\npop 1\next_pop \n' \ + b'push 1\npop 1\npush None\npop None\n' + +Py_DEBUG = hasattr(sys, 'gettotalrefcount') + + +@unittest.skipUnless(Py_DEBUG, 'need Py_DEBUG') +class TestLTrace(unittest.TestCase): + + def setUp(self): + self.orig_stdout = sys.stdout + self.orig_stderr = sys.stderr + self.orig_displayhook = sys.displayhook + + def tearDown(self): + sys.stdout = self.orig_stdout + sys.stderr = self.orig_stderr + sys.displayhook = self.orig_displayhook + + def test_ltrace_result(self): + with test.support.temp_dir() as d: + script_file = make_script(d, 'test_ltrace_code.py', LTRACE_SCRIPT) + + response = assert_python_ok(script_file) + self.assertEqual(response.rc, 0) + self.assertRegex(response.out, REGEXP) + self.assertEqual(response.err, b'') + diff -r 0d8f139a6e19 Makefile.pre.in --- a/Makefile.pre.in Sat Jul 16 07:17:46 2016 +0000 +++ b/Makefile.pre.in Wed Aug 03 18:57:46 2016 +0200 @@ -367,6 +367,12 @@ OPCODETARGETGEN_FILES= \ $(OPCODETARGETGEN) $(srcdir)/Lib/opcode.py +OPCODETRANSLATIONGEN= \ + $(srcdir)/Python/makeopcodetranslations.py + +OPCODETRANSLATIONGEN_FILES= \ + $(OPCODETRANSLATIONGEN) $(srcdir)/Lib/opcode.py + PYTHON_OBJS= \ Python/_warnings.o \ Python/Python-ast.o \ @@ -884,7 +890,10 @@ $(OPCODETARGETS_H): $(OPCODETARGETGEN_FILES) $(OPCODETARGETGEN) $(OPCODETARGETS_H) -Python/ceval.o: $(OPCODETARGETS_H) $(srcdir)/Python/ceval_gil.h +$(OPCODETRANSLATIONS_H): $(OPCODETARGETGEN_FILES) + $(OPCODETRANSLATIONGEN) $(OPCODETARGETS_H) + +Python/ceval.o: $(OPCODETARGETS_H) $(OPCODETRANSLATIONS_H) $(srcdir)/Python/ceval_gil.h Python/frozen.o: Python/importlib.h Python/importlib_external.h diff -r 0d8f139a6e19 Python/ceval.c --- a/Python/ceval.c Sat Jul 16 07:17:46 2016 +0000 +++ b/Python/ceval.c Wed Aug 03 18:57:46 2016 +0200 @@ -20,6 +20,10 @@ #include +#ifdef Py_DEBUG +#include "opcode_translations.h" +#endif + #ifndef WITH_TSC #define READ_TIMESTAMP(var) @@ -1339,15 +1343,15 @@ #ifdef LLTRACE /* Instruction tracing */ - if (lltrace) { + const char *opcode_label = opcode_translations[opcode]; if (HAS_ARG(opcode)) { - printf("%d: %d, %d\n", - f->f_lasti, opcode, oparg); + PySys_WriteStdout("%d: %s, %d\n", + f->f_lasti, opcode_label, oparg); } else { - printf("%d: %d\n", - f->f_lasti, opcode); + PySys_WriteStdout("%d: %s\n", + f->f_lasti, opcode_label); } } #endif diff -r 0d8f139a6e19 Python/makeopcodetranslations.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Python/makeopcodetranslations.py Wed Aug 03 18:57:46 2016 +0200 @@ -0,0 +1,52 @@ +#!/usr/bin/env python +"""Generate C code for the jump table of the threaded code interpreter +(for compilers supporting computed gotos or "labels-as-values", such as gcc). +""" + +import os +import sys + + +try: + from importlib.machinery import SourceFileLoader +except ImportError: + import imp + + def find_module(modname): + """Finds and returns a module in the local dist/checkout.""" + modpath = os.path.join( + os.path.dirname(os.path.dirname(__file__)), "Lib") + return imp.load_module(modname, *imp.find_module(modname, [modpath])) +else: + def find_module(modname): + """Finds and returns a module in the local dist/checkout.""" + modpath = os.path.join( + os.path.dirname(os.path.dirname(__file__)), "Lib", modname + ".py") + return SourceFileLoader(modname, modpath).load_module() + + +def write_contents(f): + """Write C code contents to the target file object.""" + opcode = find_module("opcode") + targets = ['NULL'] * 256 + for opname, op in opcode.opmap.items(): + targets[op] = '"%s"' % opname + f.write("static void *opcode_translations[256] = {\n") + f.write(",\n".join([" %s" % s for s in targets])) + f.write("\n};\n") + + +def main(): + if len(sys.argv) >= 3: + sys.exit("Too many arguments") + if len(sys.argv) == 2: + target = sys.argv[1] + else: + target = "Python/opcode_translations.h" + with open(target, "w") as f: + write_contents(f) + print("Jump table written into %s" % target) + + +if __name__ == "__main__": + main() diff -r 0d8f139a6e19 Python/opcode_translations.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Python/opcode_translations.h Wed Aug 03 18:57:46 2016 +0200 @@ -0,0 +1,258 @@ +static void *opcode_translations[256] = { + NULL, + "POP_TOP", + "ROT_TWO", + "ROT_THREE", + "DUP_TOP", + "DUP_TOP_TWO", + NULL, + NULL, + NULL, + "NOP", + "UNARY_POSITIVE", + "UNARY_NEGATIVE", + "UNARY_NOT", + NULL, + NULL, + "UNARY_INVERT", + "BINARY_MATRIX_MULTIPLY", + "INPLACE_MATRIX_MULTIPLY", + NULL, + "BINARY_POWER", + "BINARY_MULTIPLY", + NULL, + "BINARY_MODULO", + "BINARY_ADD", + "BINARY_SUBTRACT", + "BINARY_SUBSCR", + "BINARY_FLOOR_DIVIDE", + "BINARY_TRUE_DIVIDE", + "INPLACE_FLOOR_DIVIDE", + "INPLACE_TRUE_DIVIDE", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "GET_AITER", + "GET_ANEXT", + "BEFORE_ASYNC_WITH", + NULL, + NULL, + "INPLACE_ADD", + "INPLACE_SUBTRACT", + "INPLACE_MULTIPLY", + NULL, + "INPLACE_MODULO", + "STORE_SUBSCR", + "DELETE_SUBSCR", + "BINARY_LSHIFT", + "BINARY_RSHIFT", + "BINARY_AND", + "BINARY_XOR", + "BINARY_OR", + "INPLACE_POWER", + "GET_ITER", + "GET_YIELD_FROM_ITER", + "PRINT_EXPR", + "LOAD_BUILD_CLASS", + "YIELD_FROM", + "GET_AWAITABLE", + NULL, + "INPLACE_LSHIFT", + "INPLACE_RSHIFT", + "INPLACE_AND", + "INPLACE_XOR", + "INPLACE_OR", + "BREAK_LOOP", + "WITH_CLEANUP_START", + "WITH_CLEANUP_FINISH", + "RETURN_VALUE", + "IMPORT_STAR", + NULL, + "YIELD_VALUE", + "POP_BLOCK", + "END_FINALLY", + "POP_EXCEPT", + "STORE_NAME", + "DELETE_NAME", + "UNPACK_SEQUENCE", + "FOR_ITER", + "UNPACK_EX", + "STORE_ATTR", + "DELETE_ATTR", + "STORE_GLOBAL", + "DELETE_GLOBAL", + NULL, + "LOAD_CONST", + "LOAD_NAME", + "BUILD_TUPLE", + "BUILD_LIST", + "BUILD_SET", + "BUILD_MAP", + "LOAD_ATTR", + "COMPARE_OP", + "IMPORT_NAME", + "IMPORT_FROM", + "JUMP_FORWARD", + "JUMP_IF_FALSE_OR_POP", + "JUMP_IF_TRUE_OR_POP", + "JUMP_ABSOLUTE", + "POP_JUMP_IF_FALSE", + "POP_JUMP_IF_TRUE", + "LOAD_GLOBAL", + NULL, + NULL, + "CONTINUE_LOOP", + "SETUP_LOOP", + "SETUP_EXCEPT", + "SETUP_FINALLY", + NULL, + "LOAD_FAST", + "STORE_FAST", + "DELETE_FAST", + NULL, + NULL, + NULL, + "RAISE_VARARGS", + "CALL_FUNCTION", + "MAKE_FUNCTION", + "BUILD_SLICE", + NULL, + "LOAD_CLOSURE", + "LOAD_DEREF", + "STORE_DEREF", + "DELETE_DEREF", + NULL, + "CALL_FUNCTION_VAR", + "CALL_FUNCTION_KW", + "CALL_FUNCTION_VAR_KW", + "SETUP_WITH", + "EXTENDED_ARG", + "LIST_APPEND", + "SET_ADD", + "MAP_ADD", + "LOAD_CLASSDEREF", + "BUILD_LIST_UNPACK", + "BUILD_MAP_UNPACK", + "BUILD_MAP_UNPACK_WITH_CALL", + "BUILD_TUPLE_UNPACK", + "BUILD_SET_UNPACK", + "SETUP_ASYNC_WITH", + "FORMAT_VALUE", + "BUILD_CONST_KEY_MAP", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +};