|
33 | 33 | /* Cap per-batch RLE samples to bound the timestamp list (gh-151378) */ |
34 | 34 | #define MAX_RLE_BATCH_SAMPLES 8192 |
35 | 35 |
|
| 36 | +#define FRAME_INFO_CACHE_SIZE 1024 |
| 37 | + |
36 | 38 | /* ============================================================================ |
37 | 39 | * BINARY READER IMPLEMENTATION |
38 | 40 | * ============================================================================ */ |
@@ -699,71 +701,99 @@ reader_get_or_create_thread_state(BinaryReader *reader, uint64_t thread_id, |
699 | 701 | return ts; |
700 | 702 | } |
701 | 703 |
|
702 | | -/* Build a Python list of FrameInfo objects from frame indices */ |
703 | 704 | static PyObject * |
704 | | -build_frame_list(RemoteDebuggingState *state, BinaryReader *reader, |
705 | | - const uint32_t *frame_indices, size_t stack_depth) |
| 705 | +reader_get_frame_info(RemoteDebuggingState *state, BinaryReader *reader, |
| 706 | + uint32_t frame_index) |
706 | 707 | { |
707 | | - PyObject *frame_list = PyList_New(stack_depth); |
708 | | - if (!frame_list) { |
| 708 | + if (frame_index >= reader->frames_count) { |
| 709 | + PyErr_Format(PyExc_ValueError, "Invalid frame index: %u", frame_index); |
709 | 710 | return NULL; |
710 | 711 | } |
711 | | - |
712 | | - for (size_t k = 0; k < stack_depth; k++) { |
713 | | - uint32_t frame_idx = frame_indices[k]; |
714 | | - if (frame_idx >= reader->frames_count) { |
715 | | - PyErr_Format(PyExc_ValueError, "Invalid frame index: %u", frame_idx); |
716 | | - goto error; |
| 712 | + if (reader->frame_info_cache == NULL) { |
| 713 | + size_t cache_size = Py_MIN(reader->frames_count, |
| 714 | + FRAME_INFO_CACHE_SIZE); |
| 715 | + reader->frame_info_cache = PyMem_Calloc( |
| 716 | + cache_size, sizeof(*reader->frame_info_cache)); |
| 717 | + if (reader->frame_info_cache == NULL) { |
| 718 | + PyErr_NoMemory(); |
| 719 | + return NULL; |
717 | 720 | } |
| 721 | + reader->frame_info_cache_size = cache_size; |
| 722 | + } |
| 723 | + ReaderFrameCacheEntry *entry = &reader->frame_info_cache[ |
| 724 | + frame_index % reader->frame_info_cache_size]; |
| 725 | + if (entry->frame_info != NULL && entry->frame_index == frame_index) { |
| 726 | + return Py_NewRef(entry->frame_info); |
| 727 | + } |
718 | 728 |
|
719 | | - FrameEntry *frame = &reader->frames[frame_idx]; |
| 729 | + FrameEntry *frame = &reader->frames[frame_index]; |
| 730 | + if (frame->filename_idx >= reader->strings_count || |
| 731 | + frame->funcname_idx >= reader->strings_count) { |
| 732 | + PyErr_SetString(PyExc_ValueError, "Invalid string index in frame"); |
| 733 | + return NULL; |
| 734 | + } |
720 | 735 |
|
721 | | - if (frame->filename_idx >= reader->strings_count || |
722 | | - frame->funcname_idx >= reader->strings_count) { |
723 | | - PyErr_SetString(PyExc_ValueError, "Invalid string index in frame"); |
724 | | - goto error; |
725 | | - } |
| 736 | + PyObject *frame_info = PyStructSequence_New(state->FrameInfo_Type); |
| 737 | + if (!frame_info) { |
| 738 | + return NULL; |
| 739 | + } |
726 | 740 |
|
727 | | - PyObject *frame_info = PyStructSequence_New(state->FrameInfo_Type); |
728 | | - if (!frame_info) { |
729 | | - goto error; |
| 741 | + /* Build location tuple with full position info */ |
| 742 | + PyObject *location; |
| 743 | + if (frame->lineno != LOCATION_NOT_AVAILABLE) { |
| 744 | + location = Py_BuildValue("(iiii)", |
| 745 | + frame->lineno, |
| 746 | + frame->end_lineno, |
| 747 | + frame->column, |
| 748 | + frame->end_column); |
| 749 | + if (!location) { |
| 750 | + Py_DECREF(frame_info); |
| 751 | + return NULL; |
730 | 752 | } |
| 753 | + } |
| 754 | + else { |
| 755 | + location = Py_NewRef(Py_None); |
| 756 | + } |
731 | 757 |
|
732 | | - /* Build location tuple with full position info */ |
733 | | - PyObject *location; |
734 | | - if (frame->lineno != LOCATION_NOT_AVAILABLE) { |
735 | | - location = Py_BuildValue("(iiii)", |
736 | | - frame->lineno, |
737 | | - frame->end_lineno, |
738 | | - frame->column, |
739 | | - frame->end_column); |
740 | | - if (!location) { |
741 | | - Py_DECREF(frame_info); |
742 | | - goto error; |
743 | | - } |
744 | | - } |
745 | | - else { |
746 | | - location = Py_NewRef(Py_None); |
| 758 | + /* Build opcode object */ |
| 759 | + PyObject *opcode_obj; |
| 760 | + if (frame->opcode != OPCODE_NONE) { |
| 761 | + opcode_obj = PyLong_FromLong(frame->opcode); |
| 762 | + if (!opcode_obj) { |
| 763 | + Py_DECREF(location); |
| 764 | + Py_DECREF(frame_info); |
| 765 | + return NULL; |
747 | 766 | } |
| 767 | + } |
| 768 | + else { |
| 769 | + opcode_obj = Py_NewRef(Py_None); |
| 770 | + } |
748 | 771 |
|
749 | | - /* Build opcode object */ |
750 | | - PyObject *opcode_obj; |
751 | | - if (frame->opcode != OPCODE_NONE) { |
752 | | - opcode_obj = PyLong_FromLong(frame->opcode); |
753 | | - if (!opcode_obj) { |
754 | | - Py_DECREF(location); |
755 | | - Py_DECREF(frame_info); |
756 | | - goto error; |
757 | | - } |
758 | | - } |
759 | | - else { |
760 | | - opcode_obj = Py_NewRef(Py_None); |
761 | | - } |
| 772 | + PyStructSequence_SetItem(frame_info, 0, Py_NewRef(reader->strings[frame->filename_idx])); |
| 773 | + PyStructSequence_SetItem(frame_info, 1, location); |
| 774 | + PyStructSequence_SetItem(frame_info, 2, Py_NewRef(reader->strings[frame->funcname_idx])); |
| 775 | + PyStructSequence_SetItem(frame_info, 3, opcode_obj); |
| 776 | + Py_XSETREF(entry->frame_info, Py_NewRef(frame_info)); |
| 777 | + entry->frame_index = frame_index; |
| 778 | + return frame_info; |
| 779 | +} |
| 780 | + |
| 781 | +/* Build a Python list of FrameInfo objects from frame indices */ |
| 782 | +static PyObject * |
| 783 | +build_frame_list(RemoteDebuggingState *state, BinaryReader *reader, |
| 784 | + const uint32_t *frame_indices, size_t stack_depth) |
| 785 | +{ |
| 786 | + PyObject *frame_list = PyList_New(stack_depth); |
| 787 | + if (!frame_list) { |
| 788 | + return NULL; |
| 789 | + } |
762 | 790 |
|
763 | | - PyStructSequence_SetItem(frame_info, 0, Py_NewRef(reader->strings[frame->filename_idx])); |
764 | | - PyStructSequence_SetItem(frame_info, 1, location); |
765 | | - PyStructSequence_SetItem(frame_info, 2, Py_NewRef(reader->strings[frame->funcname_idx])); |
766 | | - PyStructSequence_SetItem(frame_info, 3, opcode_obj); |
| 791 | + for (size_t k = 0; k < stack_depth; k++) { |
| 792 | + PyObject *frame_info = reader_get_frame_info( |
| 793 | + state, reader, frame_indices[k]); |
| 794 | + if (frame_info == NULL) { |
| 795 | + goto error; |
| 796 | + } |
767 | 797 | PyList_SET_ITEM(frame_list, k, frame_info); |
768 | 798 | } |
769 | 799 |
|
@@ -1789,6 +1819,13 @@ binary_reader_close(BinaryReader *reader) |
1789 | 1819 | PyMem_Free(reader->block_streams); |
1790 | 1820 | PyMem_Free(reader->block_stacks); |
1791 | 1821 |
|
| 1822 | + if (reader->frame_info_cache != NULL) { |
| 1823 | + for (size_t i = 0; i < reader->frame_info_cache_size; i++) { |
| 1824 | + Py_XDECREF(reader->frame_info_cache[i].frame_info); |
| 1825 | + } |
| 1826 | + PyMem_Free(reader->frame_info_cache); |
| 1827 | + } |
| 1828 | + |
1792 | 1829 | if (reader->strings) { |
1793 | 1830 | for (uint32_t i = 0; i < reader->strings_count; i++) { |
1794 | 1831 | Py_XDECREF(reader->strings[i]); |
|
0 commit comments