Mark Shannon avatar Mark Shannon committed 6a7634a Draft

Avoid stack overflow when materialising tuples. Improve reporting of exits

Comments (0)

Files changed (5)

Include/optimiser.h

 #endif
     unsigned long failed_trace_recordings;
     unsigned long tracing_frame_stack_overflows;
+    unsigned long return_exits;
+    unsigned long rare_exits;
 } HotPyStatistics;
 
 typedef struct _hotpy_options {

Python/register_interpreter.c

         if (exit_trace->status == TRACE_VALID) {
             TRANSFER_TO(exit_trace, exit->exit_context);
         } else {
-            _HotPy_Stats.invalid_exits++;
+            if (exit_trace->execution_count < 0)
+                _HotPy_Stats.invalid_exits++;
+            else
+                _HotPy_Stats.cold_exits++;
             Py_DECREF(trace);
             return _HotPy_TraceExcecuteCold(tstate, exit_trace, "trace transfer");
         }

Python/trace_D_O_C.c

 static void
 materialise(HotPyOptimiser *x, PyObject *obj)
 {
-    int i;
+    int i, size;
     PyObject *f, *s;
     assert(Py_TYPE(obj) == &DeferredObject_Type);
     switch (KIND(obj)) {
             x->next->load_register(x->next, INDEX(obj));
         break;
     case DK_TUPLE:
-        for (i = 0; i < Py_SIZE(VALUE(obj)); i++) {
-            PyObject *item = PyTuple_GET_ITEM(VALUE(obj), i);
-            Py_INCREF(item);
-            materialise(x, item);
+        /* Need to be careful not to overflow the stack here */
+        size = Py_SIZE(VALUE(obj));
+        if (size <= HOTPY_STACK_OVERHEAD) {
+            for (i = 0; i < size; i++) {
+                PyObject *item = PyTuple_GET_ITEM(VALUE(obj), i);
+                Py_INCREF(item);
+                materialise(x, item);
+            }
+            x->next->opcode_with_arg(x->next, BUILD_TUPLE, size);
         }
-        x->next->opcode_with_arg(x->next, BUILD_TUPLE, Py_SIZE(VALUE(obj)));
+        else {
+            int partial_size = HOTPY_STACK_OVERHEAD;
+            for (i = 0; i < HOTPY_STACK_OVERHEAD; i++) {
+                PyObject *item = PyTuple_GET_ITEM(VALUE(obj), i);
+                Py_INCREF(item);
+                materialise(x, item);
+            }
+            x->next->opcode_with_arg(x->next, BUILD_TUPLE, HOTPY_STACK_OVERHEAD);
+            while (size - partial_size >= HOTPY_STACK_OVERHEAD) {
+                for (i = 0; i < HOTPY_STACK_OVERHEAD-1; i++) {
+                    PyObject *item = PyTuple_GET_ITEM(VALUE(obj), partial_size+i);
+                    Py_INCREF(item);
+                    materialise(x, item);
+                }
+                x->next->opcode_with_arg(x->next, BUILD_TUPLE, HOTPY_STACK_OVERHEAD-1);
+                x->next->tuple_concat(x->next);
+                partial_size += HOTPY_STACK_OVERHEAD-1;
+            }
+            if (partial_size < size) {
+                for (i = partial_size; i < size; i++) {
+                    PyObject *item = PyTuple_GET_ITEM(VALUE(obj), i);
+                    Py_INCREF(item);
+                    materialise(x, item);
+                }
+                x->next->opcode_with_arg(x->next, BUILD_TUPLE, size - partial_size);
+                x->next->tuple_concat(x->next);
+            }
+        }
         break;
     case DK_MAP:
         {
     materialise(x, v);
     context = x->next->from_object_dict_fast(x->next, dict_offset, keys, key);
     if (context) {
+        PUSH(get_constant(opt, key));
         PUSH(v);
-        PUSH(get_constant(opt, key));
         save_state_to_context(x, context);
         v = POP();
         Py_DECREF(v);
         v = POP();
         Py_DECREF(v);
     }
-    else
+    else {
+        Py_DECREF(v);
         PUSH(real_value());
+    }
     return context;
 }
 

Python/trace_interpreter.c

             int i;
             PyObject *builtins = POP();
             PyObject *globals = POP();
-            PyObject *co = POP();
+            PyObject *code = POP();
             PyFrameObject *frame;
-            assert(PyCode_Check(co));
-            frame = HotPyFrame_New(tstate, (PyCodeObject *)co,
+            assert(PyCode_Check(code));
+            frame = HotPyFrame_New(tstate, (PyCodeObject *)code,
                                    globals, builtins, NULL);
-            Py_DECREF(co);
+            Py_DECREF(code);
             Py_DECREF(globals);
             Py_DECREF(builtins);
             if (frame == NULL)
         TARGET(RETURN_VALUE)
             PyObject *retval = POP();
             Py_DECREF(trace);
+            _HotPy_Stats.return_exits;
             return (HotPyReturnValue) { retval, WHY_RETURN};
 
         TARGET_WITH_ARG(BINARY_OP)
                 offset != (unsigned short)gen->gi_frame->f_lasti) {
                 Py_DECREF(gen);
                 exit = (HotPyExitObject *)GETITEM(trace->trace_exits, oparg);
+                _HotPy_Stats.rare_exits++;
                 goto rare_exit;
             }
             Py_DECREF(gen);
             Py_DECREF(v);
             if (x == NULL) {
                 exit = (HotPyExitObject *)GETITEM(trace->trace_exits, oparg);
+                _HotPy_Stats.rare_exits++;
                 goto rare_exit;
             }
             PUSH(x);
                 next_instr = HotPyIP_ToAddr(exit->exit_context->cf_instrs[0]);
                 PUSH_TO_REAL(x);
                 Py_DECREF(trace);
+                _HotPy_Stats.rare_exits++;
                 return (HotPyReturnValue)
                     { next_instr, WHY_NOT};
             }
             TRANSFER_TO(exit_trace, exit->exit_context);
         }
         else {
-            _HotPy_Stats.invalid_exits++;
+            if (exit_trace->execution_count < 0)
+                _HotPy_Stats.invalid_exits++;
+            else
+                _HotPy_Stats.cold_exits++;
             Py_DECREF(trace);
             return _HotPy_TraceExcecuteCold(tstate, exit_trace, "trace transfer");
         }

Python/trace_manager.c

     printf("%ld Polymorphic cold exits\n", _HotPy_Stats.polymorphic_cold_exits);
     printf("%ld Polymorphic overflow exits\n", _HotPy_Stats.polymorphic_overflow_exits);
     printf("%ld Invalid trace exits\n", _HotPy_Stats.invalid_exits);
+    printf("%ld Return to top-level exits\n", _HotPy_Stats.return_exits);
+    printf("%ld Rare exits\n", _HotPy_Stats.rare_exits);
     printf("%ld Cold exits\n", _HotPy_Stats.cold_exits);
     printf("%ld Non-bool/int exits\n", _HotPy_Stats.not_bool_exits);
     printf("%ld Exception exits\n", _HotPy_Stats.exception_exits);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.