Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Lib/test/test_sys_settrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ class TraceTestCase(unittest.TestCase):
# Disable gc collection when tracing, otherwise the
# deallocators may be traced as well.
def setUp(self):
if os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0':
self.skipTest("Line tracing behavior differs when JIT optimizer is disabled")
self.using_gc = gc.isenabled()
gc.disable()
self.addCleanup(sys.settrace, sys.gettrace())
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ def test_traced_func_linear(self):

self.assertEqual(self.tracer.results().counts, expected)

@unittest.skipIf(os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0',
"Line counts differ when JIT optimizer is disabled")
def test_traced_func_loop(self):
self.tracer.runfunc(traced_func_loop, 2, 3)

Expand All @@ -166,6 +168,8 @@ def test_traced_func_importing(self):

self.assertEqual(self.tracer.results().counts, expected)

@unittest.skipIf(os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0',
"Line counts differ when JIT optimizer is disabled")
def test_trace_func_generator(self):
self.tracer.runfunc(traced_func_calling_generator)

Expand Down Expand Up @@ -236,6 +240,8 @@ def setUp(self):
self.my_py_filename = fix_ext_py(__file__)
self.addCleanup(sys.settrace, sys.gettrace())

@unittest.skipIf(os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0',
"Line counts differ when JIT optimizer is disabled")
def test_exec_counts(self):
self.tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
code = r'''traced_func_loop(2, 5)'''
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix JIT trace buffer overrun by pre-reserving exit stub space. Patch By
Donghee Na.
22 changes: 8 additions & 14 deletions Python/optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,12 @@ translate_bytecode_to_trace(
_Py_BloomFilter_Add(dependencies, initial_code);
_Py_CODEUNIT *initial_instr = instr;
int trace_length = 0;
// Leave space for possible trailing _EXIT_TRACE
int max_length = buffer_size-2;
/*
* Assumption: 80% reserved for trace, 20% for exit stubs
* TODO: Compute the required number of exit stubs dynamically
*/
int max_exit_stubs = (buffer_size * 20) / 100; // 20% for exit stubs
int max_length = buffer_size - 2 - max_exit_stubs;
struct {
PyFunctionObject *func;
PyCodeObject *code;
Expand Down Expand Up @@ -647,16 +651,6 @@ translate_bytecode_to_trace(
assert(!OPCODE_HAS_DEOPT(opcode));
}

if (OPCODE_HAS_EXIT(opcode)) {
// Make space for side exit and final _EXIT_TRACE:
RESERVE_RAW(2, "_EXIT_TRACE");
max_length--;
}
if (OPCODE_HAS_ERROR(opcode)) {
// Make space for error stub and final _EXIT_TRACE:
RESERVE_RAW(2, "_ERROR_POP_N");
max_length--;
}
switch (opcode) {
case POP_JUMP_IF_NONE:
case POP_JUMP_IF_NOT_NONE:
Expand Down Expand Up @@ -731,9 +725,9 @@ translate_bytecode_to_trace(
{
const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode];
if (expansion->nuops > 0) {
// Reserve space for nuops (+ _SET_IP + _EXIT_TRACE)
// Reserve space for nuops (exit stub space already pre-reserved)
int nuops = expansion->nuops;
RESERVE(nuops + 1); /* One extra for exit */
RESERVE(nuops);
int16_t last_op = expansion->uops[nuops-1].uop;
if (last_op == _RETURN_VALUE || last_op == _RETURN_GENERATOR || last_op == _YIELD_VALUE) {
// Check for trace stack underflow now:
Expand Down
Loading