Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
35 changes: 35 additions & 0 deletions Include/internal/pycore_c_array.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef Py_INTERNAL_C_ARRAY_H
#define Py_INTERNAL_C_ARRAY_H

#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif


/* Utility for a number of growing arrays */

typedef struct {
void **array; /* pointer to the array */
int *allocated_entries; /* pointer to the capacity of the array */
size_t item_size; /* size of each element */
int initial_num_entries; /* initial allocation size */
} _Py_c_array_t;

/* If idx is out of bouds:
* If arr->array is NULL, allocate arr->initial_num_entries slots.
* Otherwise, double its size.
*
* Return 0 if successful and -1 (with exception set) otherwise.
*/
int _Py_c_array_EnsureCapacity(_Py_c_array_t *c_array, int idx);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int _Py_c_array_EnsureCapacity(_Py_c_array_t *c_array, int idx);
int
_Py_c_array_EnsureCapacity(_Py_c_array_t *c_array, int idx);

Should we assume idx is n int or maybe a uint32_t or just a size_t? any possibility of unsafe downcasting?



#ifdef __cplusplus
}
#endif

#endif /* !Py_INTERNAL_C_ARRAY_H */
8 changes: 0 additions & 8 deletions Include/internal/pycore_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,6 @@ int _PyCodegen_Expression(struct _PyCompiler *c, expr_ty e);
int _PyCodegen_Body(struct _PyCompiler *c, _Py_SourceLocation loc, asdl_stmt_seq *stmts,
bool is_interactive);

/* Utility for a number of growing arrays used in the compiler */
int _PyCompile_EnsureArrayLargeEnough(
int idx,
void **array,
int *alloc,
int default_alloc,
size_t item_size);

int _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj);

PyCodeObject *_PyCompile_OptimizeAndAssemble(struct _PyCompiler *c, int addNone);
Expand Down
41 changes: 17 additions & 24 deletions Python/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define NEED_OPCODE_TABLES
#include "pycore_opcode_utils.h"
#undef NEED_OPCODE_TABLES
#include "pycore_c_array.h" // _Py_c_array_t
#include "pycore_compile.h"
#include "pycore_instruction_sequence.h" // _PyInstructionSequence_NewLabel()
#include "pycore_intrinsics.h"
Expand Down Expand Up @@ -109,40 +110,31 @@ static const int compare_masks[] = {
[Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS,
};

/*
* Resize the array if index is out of range.
*
* idx: the index we want to access
* arr: pointer to the array
* alloc: pointer to the capacity of the array
* default_alloc: initial number of items
* item_size: size of each item
*
*/

int
_PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc,
int default_alloc, size_t item_size)
_Py_c_array_EnsureCapacity(_Py_c_array_t *c_array, int idx)
{
void *arr = *array;
void *arr = *c_array->array;
int alloc = *c_array->allocated_entries;
if (arr == NULL) {
int new_alloc = default_alloc;
int new_alloc = c_array->initial_num_entries;
if (idx >= new_alloc) {
new_alloc = idx + default_alloc;
new_alloc = idx + c_array->initial_num_entries;
}
arr = PyMem_Calloc(new_alloc, item_size);
arr = PyMem_Calloc(new_alloc, c_array->item_size);
if (arr == NULL) {
PyErr_NoMemory();
return ERROR;
}
*alloc = new_alloc;
alloc = new_alloc;
}
else if (idx >= *alloc) {
size_t oldsize = *alloc * item_size;
int new_alloc = *alloc << 1;
else if (idx >= alloc) {
size_t oldsize = alloc * c_array->item_size;
int new_alloc = alloc << 1;
if (idx >= new_alloc) {
new_alloc = idx + default_alloc;
new_alloc = idx + c_array->initial_num_entries;
}
size_t newsize = new_alloc * item_size;
size_t newsize = new_alloc * c_array->item_size;

if (oldsize > (SIZE_MAX >> 1)) {
PyErr_NoMemory();
Expand All @@ -155,12 +147,13 @@ _PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc,
PyErr_NoMemory();
return ERROR;
}
*alloc = new_alloc;
alloc = new_alloc;
arr = tmp;
memset((char *)arr + oldsize, 0, newsize - oldsize);
}

*array = arr;
*c_array->array = arr;
*c_array->allocated_entries = alloc;
return SUCCESS;
}

Expand Down
16 changes: 9 additions & 7 deletions Python/flowgraph.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "Python.h"
#include "opcode.h"
#include "pycore_c_array.h" // _Py_c_array_EnsureCapacity
#include "pycore_flowgraph.h"
#include "pycore_compile.h"
#include "pycore_intrinsics.h"
Expand Down Expand Up @@ -141,13 +142,14 @@ static int
basicblock_next_instr(basicblock *b)
{
assert(b != NULL);
RETURN_IF_ERROR(
_PyCompile_EnsureArrayLargeEnough(
b->b_iused + 1,
(void**)&b->b_instr,
&b->b_ialloc,
DEFAULT_BLOCK_SIZE,
sizeof(cfg_instr)));
_Py_c_array_t array = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having to manually initialize a struct, just to pass it to a function seems clunky. The previous API was probably better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just to make the transition now. If we were defining basic block from scratch we would have put this struct field in it. But I think now that's a transformation for another PR.

.array = (void**)&b->b_instr,
.allocated_entries = &b->b_ialloc,
.item_size = sizeof(cfg_instr),
.initial_num_entries = DEFAULT_BLOCK_SIZE,
};

RETURN_IF_ERROR(_Py_c_array_EnsureCapacity(&array, b->b_iused + 1));
return b->b_iused++;
}

Expand Down
33 changes: 20 additions & 13 deletions Python/instruction_sequence.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

#include "Python.h"

#include "pycore_compile.h" // _PyCompile_EnsureArrayLargeEnough
#include "pycore_c_array.h" // _Py_c_array_EnsureCapacity
#include "pycore_compile.h" // _PyInstruction
#include "pycore_opcode_utils.h"
#include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc

Expand Down Expand Up @@ -36,12 +37,16 @@ static int
instr_sequence_next_inst(instr_sequence *seq) {
assert(seq->s_instrs != NULL || seq->s_used == 0);

RETURN_IF_ERROR(
_PyCompile_EnsureArrayLargeEnough(seq->s_used + 1,
(void**)&seq->s_instrs,
&seq->s_allocated,
INITIAL_INSTR_SEQUENCE_SIZE,
sizeof(instruction)));

_Py_c_array_t array = {
.array = (void**)&seq->s_instrs,
.allocated_entries = &seq->s_allocated,
.item_size = sizeof(instruction),
.initial_num_entries = INITIAL_INSTR_SEQUENCE_SIZE,
};

RETURN_IF_ERROR(_Py_c_array_EnsureCapacity(&array, seq->s_used + 1));

assert(seq->s_allocated >= 0);
assert(seq->s_used < seq->s_allocated);
return seq->s_used++;
Expand All @@ -58,12 +63,14 @@ int
_PyInstructionSequence_UseLabel(instr_sequence *seq, int lbl)
{
int old_size = seq->s_labelmap_size;
RETURN_IF_ERROR(
_PyCompile_EnsureArrayLargeEnough(lbl,
(void**)&seq->s_labelmap,
&seq->s_labelmap_size,
INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE,
sizeof(int)));
_Py_c_array_t array = {
.array = (void**)&seq->s_labelmap,
.allocated_entries = &seq->s_labelmap_size,
.item_size = sizeof(int),
.initial_num_entries = INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE,
};

RETURN_IF_ERROR(_Py_c_array_EnsureCapacity(&array, lbl));

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