Skip to content

[mypyc] feat: __mypyc_empty_tuple__ constant #19654

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
14 changes: 11 additions & 3 deletions mypyc/irbuild/ll_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,12 @@
str_ssize_t_size_op,
unicode_compare,
)
from mypyc.primitives.tuple_ops import list_tuple_op, new_tuple_op, new_tuple_with_length_op
from mypyc.primitives.tuple_ops import (
list_tuple_op,
load_empty_tuple_constant_op,
new_tuple_op,
new_tuple_with_length_op,
)
from mypyc.rt_subtype import is_runtime_subtype
from mypyc.sametype import is_same_type
from mypyc.subtype import is_subtype
Expand Down Expand Up @@ -2322,8 +2327,11 @@ def builtin_len(self, val: Value, line: int, use_pyssize_t: bool = False) -> Val
return self.call_c(generic_len_op, [val], line)

def new_tuple(self, items: list[Value], line: int) -> Value:
size: Value = Integer(len(items), c_pyssize_t_rprimitive)
return self.call_c(new_tuple_op, [size] + items, line)
if items:
size: Value = Integer(len(items), c_pyssize_t_rprimitive)
return self.call_c(new_tuple_op, [size] + items, line)
else:
return self.call_c(load_empty_tuple_constant_op, [], line)

def new_tuple_with_length(self, length: Value, line: int) -> Value:
"""This function returns an uninitialized tuple.
Expand Down
8 changes: 8 additions & 0 deletions mypyc/lib-rt/CPy.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ typedef struct tuple_T4CIOO {
} tuple_T4CIOO;
#endif

// System-wide empty tuple constant
extern PyObject * __mypyc_empty_tuple__;

static inline PyObject *_CPyTuple_LoadEmptyTupleConstant() {
// do tests still pass if I comment this out? empty tuple singleton is not tracked by gc
// Py_INCREF(__mypyc_empty_tuple__);
return __mypyc_empty_tuple__;
}

// Native object operations

Expand Down
13 changes: 13 additions & 0 deletions mypyc/lib-rt/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,23 @@
struct ExcDummyStruct _CPy_ExcDummyStruct = { PyObject_HEAD_INIT(NULL) };
PyObject *_CPy_ExcDummy = (PyObject *)&_CPy_ExcDummyStruct;

// System-wide empty tuple constant
PyObject * __mypyc_empty_tuple__ = NULL;

// Because its dynamic linker is more restricted than linux/OS X,
// Windows doesn't allow initializing globals with values from
// other dynamic libraries. This means we need to initialize
// things at load time.
void CPy_Init(void) {
_CPy_ExcDummyStruct.ob_base.ob_type = &PyBaseObject_Type;

// Initialize system-wide empty tuple constant
if (__mypyc_empty_tuple__ == NULL) {
__mypyc_empty_tuple__ = PyTuple_New(0);
if (!__mypyc_empty_tuple__) {
PyErr_SetString(PyExc_RuntimeError, "Failed to initialize __mypyc_empty_tuple__");
return;
}
Py_INCREF(__mypyc_empty_tuple__);
}
}
7 changes: 7 additions & 0 deletions mypyc/primitives/tuple_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@
error_kind=ERR_MAGIC,
)

load_empty_tuple_constant_op = custom_op(
arg_types=[],
return_type=tuple_rprimitive,
c_function_name="_CPyTuple_LoadEmptyTupleConstant",
error_kind=ERR_NEVER,
)

# PyTuple_SET_ITEM does no error checking,
# and should only be used to fill in brand new tuples.
new_tuple_set_item_op = custom_op(
Expand Down
2 changes: 1 addition & 1 deletion mypyc/test-data/irbuild-basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,7 @@ L0:
r10 = PyDict_New()
r11 = CPyDict_UpdateInDisplay(r10, r6)
r12 = r11 >= 0 :: signed
r13 = PyTuple_Pack(0)
r13 = _CPyTuple_LoadEmptyTupleConstant()
r14 = PyObject_Call(r9, r13, r10)
r15 = unbox(tuple[int, int, int], r14)
return r15
Expand Down
4 changes: 2 additions & 2 deletions mypyc/test-data/irbuild-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ L2:
r27 = CPyType_FromTemplate(r26, r24, r25)
r28 = C_trait_vtable_setup()
r29 = '__mypyc_attrs__'
r30 = PyTuple_Pack(0)
r30 = _CPyTuple_LoadEmptyTupleConstant()
r31 = PyObject_SetAttr(r27, r29, r30)
r32 = r31 >= 0 :: signed
__main__.C = r27 :: type
Expand All @@ -310,7 +310,7 @@ L2:
r39 = __main__.S_template :: type
r40 = CPyType_FromTemplate(r39, r37, r38)
r41 = '__mypyc_attrs__'
r42 = PyTuple_Pack(0)
r42 = _CPyTuple_LoadEmptyTupleConstant()
r43 = PyObject_SetAttr(r40, r41, r42)
r44 = r43 >= 0 :: signed
__main__.S = r40 :: type
Expand Down
Loading