|
10 | 10 | #include "clinic/codeobject.c.h" |
11 | 11 |
|
12 | 12 | #include <stdbool.h> |
| 13 | +#include <sys/mman.h> |
13 | 14 |
|
14 | 15 | static PyObject* code_repr(PyCodeObject *co); |
15 | 16 |
|
@@ -543,6 +544,73 @@ remove_column_info(PyObject *locations) |
543 | 544 | return res; |
544 | 545 | } |
545 | 546 |
|
| 547 | +#define BUMP_CHUNK_SIZE (1024 * 1024 * 1024) // 1GiB, must be a power of 2 |
| 548 | + |
| 549 | +// Process-global state for the bump allocator |
| 550 | +static struct { |
| 551 | + char *current_ptr; // Current allocation position |
| 552 | + char *end_ptr; // End of current memory region |
| 553 | +} code_allocator_state = {NULL, NULL}; |
| 554 | + |
| 555 | +// Extend the bump allocator's memory region |
| 556 | +static int |
| 557 | +extend_code_bump_allocator(Py_ssize_t min_size) |
| 558 | +{ |
| 559 | + // Calculate how much to allocate (at least BUMP_CHUNK_SIZE, rounded up) |
| 560 | + Py_ssize_t size = (min_size + BUMP_CHUNK_SIZE - 1) & ~(BUMP_CHUNK_SIZE - 1); |
| 561 | + |
| 562 | + // Try to extend the existing region |
| 563 | + void *ptr = mmap(code_allocator_state.end_ptr, size, |
| 564 | + PROT_READ | PROT_WRITE, |
| 565 | + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); |
| 566 | + |
| 567 | + if (ptr == MAP_FAILED) { |
| 568 | + // If MAP_FIXED fails, try without it |
| 569 | + ptr = mmap(NULL, size, |
| 570 | + PROT_READ | PROT_WRITE, |
| 571 | + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 572 | + |
| 573 | + if (ptr == MAP_FAILED) { |
| 574 | + return -1; |
| 575 | + } |
| 576 | + |
| 577 | + // We got memory but not contiguous |
| 578 | + code_allocator_state.current_ptr = ptr; |
| 579 | + code_allocator_state.end_ptr = ptr + size; |
| 580 | + } else { |
| 581 | + if (code_allocator_state.current_ptr == NULL) { |
| 582 | + code_allocator_state.current_ptr = ptr; |
| 583 | + code_allocator_state.end_ptr = ptr + size; |
| 584 | + } else { |
| 585 | + code_allocator_state.end_ptr += size; |
| 586 | + } |
| 587 | + } |
| 588 | + |
| 589 | + return 0; |
| 590 | +} |
| 591 | + |
| 592 | +// Allocate memory from the bump allocator |
| 593 | +static void* |
| 594 | +code_bump_allocate(Py_ssize_t n_bytes) |
| 595 | +{ |
| 596 | + // Align the allocation to 8 bytes |
| 597 | + n_bytes = (n_bytes + 7) & ~7; |
| 598 | + |
| 599 | + // Check if we have enough space |
| 600 | + if (code_allocator_state.current_ptr + n_bytes > code_allocator_state.end_ptr) { |
| 601 | + // Need to extend |
| 602 | + if (extend_code_bump_allocator(n_bytes) < 0) { |
| 603 | + return NULL; |
| 604 | + } |
| 605 | + } |
| 606 | + |
| 607 | + // Allocate from the bump pointer |
| 608 | + void *result = code_allocator_state.current_ptr; |
| 609 | + code_allocator_state.current_ptr += n_bytes; |
| 610 | + |
| 611 | + return result; |
| 612 | +} |
| 613 | + |
546 | 614 | /* The caller is responsible for ensuring that the given data is valid. */ |
547 | 615 |
|
548 | 616 | PyCodeObject * |
@@ -580,13 +648,15 @@ _PyCode_New(struct _PyCodeConstructor *con) |
580 | 648 | con->linetable = replacement_locations; |
581 | 649 | } |
582 | 650 |
|
583 | | - Py_ssize_t size = PyBytes_GET_SIZE(con->code) / sizeof(_Py_CODEUNIT); |
584 | | - PyCodeObject *co = PyObject_NewVar(PyCodeObject, &PyCode_Type, size); |
| 651 | + Py_ssize_t nitems = PyBytes_GET_SIZE(con->code) / sizeof(_Py_CODEUNIT); |
| 652 | + Py_ssize_t size = _PyObject_VAR_SIZE(&PyCode_Type, nitems); |
| 653 | + PyCodeObject *co = (PyCodeObject *)code_bump_allocate(size); |
585 | 654 | if (co == NULL) { |
586 | 655 | Py_XDECREF(replacement_locations); |
587 | 656 | PyErr_NoMemory(); |
588 | 657 | return NULL; |
589 | 658 | } |
| 659 | + PyObject_InitVar(co, &PyCode_Type, nitems); |
590 | 660 | init_code(co, con); |
591 | 661 | Py_XDECREF(replacement_locations); |
592 | 662 | return co; |
@@ -1744,7 +1814,8 @@ code_dealloc(PyCodeObject *co) |
1744 | 1814 | PyObject_ClearWeakRefs((PyObject*)co); |
1745 | 1815 | } |
1746 | 1816 | free_monitoring_data(co->_co_monitoring); |
1747 | | - PyObject_Free(co); |
| 1817 | + |
| 1818 | + // Data not actually freed as it comes from the the bump allocator. |
1748 | 1819 | } |
1749 | 1820 |
|
1750 | 1821 | static PyObject * |
|
0 commit comments