Skip to content

Commit 4242c2b

Browse files
authored
gh-130080: move _Py_EnsureArrayLargeEnough to a separate header so it can be used outside of the compiler (#130930)
1 parent 9a63138 commit 4242c2b

File tree

5 files changed

+108
-52
lines changed

5 files changed

+108
-52
lines changed

Include/internal/pycore_c_array.h

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#ifndef Py_INTERNAL_C_ARRAY_H
2+
#define Py_INTERNAL_C_ARRAY_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
#ifndef Py_BUILD_CORE
9+
# error "this header requires Py_BUILD_CORE define"
10+
#endif
11+
12+
13+
/* Utility for a number of growing arrays */
14+
15+
typedef struct {
16+
void *array; /* pointer to the array */
17+
int allocated_entries; /* pointer to the capacity of the array */
18+
size_t item_size; /* size of each element */
19+
int initial_num_entries; /* initial allocation size */
20+
} _Py_c_array_t;
21+
22+
23+
int _Py_CArray_Init(_Py_c_array_t* array, int item_size, int initial_num_entries);
24+
void _Py_CArray_Fini(_Py_c_array_t* array);
25+
26+
/* If idx is out of bounds:
27+
* If arr->array is NULL, allocate arr->initial_num_entries slots.
28+
* Otherwise, double its size.
29+
*
30+
* Return 0 if successful and -1 (with exception set) otherwise.
31+
*/
32+
int _Py_CArray_EnsureCapacity(_Py_c_array_t *c_array, int idx);
33+
34+
35+
#ifdef __cplusplus
36+
}
37+
#endif
38+
39+
#endif /* !Py_INTERNAL_C_ARRAY_H */

Include/internal/pycore_compile.h

-8
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,6 @@ int _PyCodegen_Expression(struct _PyCompiler *c, expr_ty e);
183183
int _PyCodegen_Body(struct _PyCompiler *c, _Py_SourceLocation loc, asdl_stmt_seq *stmts,
184184
bool is_interactive);
185185

186-
/* Utility for a number of growing arrays used in the compiler */
187-
int _PyCompile_EnsureArrayLargeEnough(
188-
int idx,
189-
void **array,
190-
int *alloc,
191-
int default_alloc,
192-
size_t item_size);
193-
194186
int _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj);
195187

196188
PyCodeObject *_PyCompile_OptimizeAndAssemble(struct _PyCompiler *c, int addNone);

Python/codegen.c

+34-24
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define NEED_OPCODE_TABLES
1919
#include "pycore_opcode_utils.h"
2020
#undef NEED_OPCODE_TABLES
21+
#include "pycore_c_array.h" // _Py_c_array_t
2122
#include "pycore_compile.h"
2223
#include "pycore_instruction_sequence.h" // _PyInstructionSequence_NewLabel()
2324
#include "pycore_intrinsics.h"
@@ -100,40 +101,48 @@ static const int compare_masks[] = {
100101
[Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS,
101102
};
102103

103-
/*
104-
* Resize the array if index is out of range.
105-
*
106-
* idx: the index we want to access
107-
* arr: pointer to the array
108-
* alloc: pointer to the capacity of the array
109-
* default_alloc: initial number of items
110-
* item_size: size of each item
111-
*
112-
*/
104+
105+
int
106+
_Py_CArray_Init(_Py_c_array_t* array, int item_size, int initial_num_entries) {
107+
memset(array, 0, sizeof(_Py_c_array_t));
108+
array->item_size = item_size;
109+
array->initial_num_entries = initial_num_entries;
110+
return 0;
111+
}
112+
113+
void
114+
_Py_CArray_Fini(_Py_c_array_t* array)
115+
{
116+
if (array->array) {
117+
PyMem_Free(array->array);
118+
array->allocated_entries = 0;
119+
}
120+
}
121+
113122
int
114-
_PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc,
115-
int default_alloc, size_t item_size)
123+
_Py_CArray_EnsureCapacity(_Py_c_array_t *c_array, int idx)
116124
{
117-
void *arr = *array;
125+
void *arr = c_array->array;
126+
int alloc = c_array->allocated_entries;
118127
if (arr == NULL) {
119-
int new_alloc = default_alloc;
128+
int new_alloc = c_array->initial_num_entries;
120129
if (idx >= new_alloc) {
121-
new_alloc = idx + default_alloc;
130+
new_alloc = idx + c_array->initial_num_entries;
122131
}
123-
arr = PyMem_Calloc(new_alloc, item_size);
132+
arr = PyMem_Calloc(new_alloc, c_array->item_size);
124133
if (arr == NULL) {
125134
PyErr_NoMemory();
126135
return ERROR;
127136
}
128-
*alloc = new_alloc;
137+
alloc = new_alloc;
129138
}
130-
else if (idx >= *alloc) {
131-
size_t oldsize = *alloc * item_size;
132-
int new_alloc = *alloc << 1;
139+
else if (idx >= alloc) {
140+
size_t oldsize = alloc * c_array->item_size;
141+
int new_alloc = alloc << 1;
133142
if (idx >= new_alloc) {
134-
new_alloc = idx + default_alloc;
143+
new_alloc = idx + c_array->initial_num_entries;
135144
}
136-
size_t newsize = new_alloc * item_size;
145+
size_t newsize = new_alloc * c_array->item_size;
137146

138147
if (oldsize > (SIZE_MAX >> 1)) {
139148
PyErr_NoMemory();
@@ -146,12 +155,13 @@ _PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc,
146155
PyErr_NoMemory();
147156
return ERROR;
148157
}
149-
*alloc = new_alloc;
158+
alloc = new_alloc;
150159
arr = tmp;
151160
memset((char *)arr + oldsize, 0, newsize - oldsize);
152161
}
153162

154-
*array = arr;
163+
c_array->array = arr;
164+
c_array->allocated_entries = alloc;
155165
return SUCCESS;
156166
}
157167

Python/flowgraph.c

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "Python.h"
22
#include "opcode.h"
3+
#include "pycore_c_array.h" // _Py_CArray_EnsureCapacity
34
#include "pycore_flowgraph.h"
45
#include "pycore_compile.h"
56
#include "pycore_intrinsics.h"
@@ -141,13 +142,16 @@ static int
141142
basicblock_next_instr(basicblock *b)
142143
{
143144
assert(b != NULL);
144-
RETURN_IF_ERROR(
145-
_PyCompile_EnsureArrayLargeEnough(
146-
b->b_iused + 1,
147-
(void**)&b->b_instr,
148-
&b->b_ialloc,
149-
DEFAULT_BLOCK_SIZE,
150-
sizeof(cfg_instr)));
145+
_Py_c_array_t array = {
146+
.array = (void*)b->b_instr,
147+
.allocated_entries = b->b_ialloc,
148+
.item_size = sizeof(cfg_instr),
149+
.initial_num_entries = DEFAULT_BLOCK_SIZE,
150+
};
151+
152+
RETURN_IF_ERROR(_Py_CArray_EnsureCapacity(&array, b->b_iused + 1));
153+
b->b_instr = array.array;
154+
b->b_ialloc = array.allocated_entries;
151155
return b->b_iused++;
152156
}
153157

Python/instruction_sequence.c

+24-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
#include "Python.h"
99

10-
#include "pycore_compile.h" // _PyCompile_EnsureArrayLargeEnough
10+
#include "pycore_c_array.h" // _Py_CArray_EnsureCapacity
11+
#include "pycore_compile.h" // _PyInstruction
1112
#include "pycore_opcode_utils.h"
1213
#include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc
1314

@@ -36,12 +37,18 @@ static int
3637
instr_sequence_next_inst(instr_sequence *seq) {
3738
assert(seq->s_instrs != NULL || seq->s_used == 0);
3839

39-
RETURN_IF_ERROR(
40-
_PyCompile_EnsureArrayLargeEnough(seq->s_used + 1,
41-
(void**)&seq->s_instrs,
42-
&seq->s_allocated,
43-
INITIAL_INSTR_SEQUENCE_SIZE,
44-
sizeof(instruction)));
40+
41+
_Py_c_array_t array = {
42+
.array = (void*)seq->s_instrs,
43+
.allocated_entries = seq->s_allocated,
44+
.item_size = sizeof(instruction),
45+
.initial_num_entries = INITIAL_INSTR_SEQUENCE_SIZE,
46+
};
47+
48+
RETURN_IF_ERROR(_Py_CArray_EnsureCapacity(&array, seq->s_used + 1));
49+
seq->s_instrs = array.array;
50+
seq->s_allocated = array.allocated_entries;
51+
4552
assert(seq->s_allocated >= 0);
4653
assert(seq->s_used < seq->s_allocated);
4754
return seq->s_used++;
@@ -58,12 +65,16 @@ int
5865
_PyInstructionSequence_UseLabel(instr_sequence *seq, int lbl)
5966
{
6067
int old_size = seq->s_labelmap_size;
61-
RETURN_IF_ERROR(
62-
_PyCompile_EnsureArrayLargeEnough(lbl,
63-
(void**)&seq->s_labelmap,
64-
&seq->s_labelmap_size,
65-
INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE,
66-
sizeof(int)));
68+
_Py_c_array_t array = {
69+
.array = (void*)seq->s_labelmap,
70+
.allocated_entries = seq->s_labelmap_size,
71+
.item_size = sizeof(int),
72+
.initial_num_entries = INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE,
73+
};
74+
75+
RETURN_IF_ERROR(_Py_CArray_EnsureCapacity(&array, lbl));
76+
seq->s_labelmap = array.array;
77+
seq->s_labelmap_size = array.allocated_entries;
6778

6879
for(int i = old_size; i < seq->s_labelmap_size; i++) {
6980
seq->s_labelmap[i] = -111; /* something weird, for debugging */

0 commit comments

Comments
 (0)