Skip to content

Commit acf264f

Browse files
yoneymeta-codesync[bot]
authored andcommitted
Fix CinderX 3.15 build for upstream Python API changes
Summary: Upstream Python main (3.15) made several API changes that broke the CinderX build: 1. gc_collection_stats → gc_generation_stats: The GC stats struct was renamed. Updated the CinderX GC hooks patch (pycore_gc.h, gc.c), ParallelGC/parallel_gc.c, and the patch file to use the new name for 3.15 while preserving the old name for 3.14. 2. _PyDict_MergeEx → _PyDict_MergeUniq: The dict merge API changed to return a duplicate key. Updated Jit/jit_rt.cpp with a version guard to use the new API on 3.15. 3. _PyEval_FormatKwargsError gained a 4th dupkey parameter: Updated the call in Jit/jit_rt.cpp alongside the dict merge change. 4. Interpreter bytecode changes: Regenerated Interpreter/3.15/Includes/generated_cases.c.h via regen-cases-315.sh. 5. Missing upstream borrow dependencies: Added borrow directives for setitem_take2_lock_held_known_hash (from dictobject.c) and _pymalloc_virtual_alloc_size (from obmalloc.c) to the 3.15 borrow template. Reviewed By: DinoV Differential Revision: D99680559 fbshipit-source-id: a2a087f5594d0ddcccf7f7263ddabb4d8427b947
1 parent aca5c60 commit acf264f

4 files changed

Lines changed: 69 additions & 43 deletions

File tree

cinderx/Interpreter/3.15/Includes/generated_cases.c.h

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3835,9 +3835,10 @@
38353835
assert(self != NULL);
38363836
STAT_INC(CALL, hit);
38373837
_PyFrame_SetStackPointer(frame, stack_pointer);
3838+
PyCFunctionFast cfunc = _PyCFunctionFast_CAST(method->d_method->ml_meth);
38383839
PyObject *res_o = _PyCallMethodDescriptorFast_StackRefSteal(
38393840
callable,
3840-
method->d_method,
3841+
cfunc,
38413842
self,
38423843
arguments,
38433844
total_args
@@ -3931,9 +3932,10 @@
39313932
assert(self != NULL);
39323933
STAT_INC(CALL, hit);
39333934
_PyFrame_SetStackPointer(frame, stack_pointer);
3935+
PyCFunctionFastWithKeywords cfunc = _PyCFunctionFastWithKeywords_CAST(method->d_method->ml_meth);
39343936
PyObject *res_o = _PyCallMethodDescriptorFastWithKeywords_StackRefSteal(
39353937
callable,
3936-
method->d_method,
3938+
cfunc,
39373939
self,
39383940
arguments,
39393941
total_args
@@ -4012,6 +4014,14 @@
40124014
JUMP_TO_PREDICTED(CALL);
40134015
}
40144016
}
4017+
// _CHECK_RECURSION_LIMIT
4018+
{
4019+
if (_Py_ReachedRecursionLimit(tstate)) {
4020+
UPDATE_MISS_STATS(CALL);
4021+
assert(_PyOpcode_Deopt[opcode] == (CALL));
4022+
JUMP_TO_PREDICTED(CALL);
4023+
}
4024+
}
40154025
// _CALL_METHOD_DESCRIPTOR_NOARGS
40164026
{
40174027
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
@@ -4022,11 +4032,6 @@
40224032
}
40234033
_PyStackRef self_stackref = args[0];
40244034
PyObject *self = PyStackRef_AsPyObjectBorrow(self_stackref);
4025-
if (_Py_ReachedRecursionLimit(tstate)) {
4026-
UPDATE_MISS_STATS(CALL);
4027-
assert(_PyOpcode_Deopt[opcode] == (CALL));
4028-
JUMP_TO_PREDICTED(CALL);
4029-
}
40304035
STAT_INC(CALL, hit);
40314036
PyCFunction cfunc = method->d_method->ml_meth;
40324037
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -4117,6 +4122,14 @@
41174122
JUMP_TO_PREDICTED(CALL);
41184123
}
41194124
}
4125+
// _CHECK_RECURSION_LIMIT
4126+
{
4127+
if (_Py_ReachedRecursionLimit(tstate)) {
4128+
UPDATE_MISS_STATS(CALL);
4129+
assert(_PyOpcode_Deopt[opcode] == (CALL));
4130+
JUMP_TO_PREDICTED(CALL);
4131+
}
4132+
}
41204133
// _CALL_METHOD_DESCRIPTOR_O
41214134
{
41224135
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
@@ -4125,19 +4138,12 @@
41254138
if (!PyStackRef_IsNull(self_or_null)) {
41264139
arguments--;
41274140
}
4128-
if (_Py_ReachedRecursionLimit(tstate)) {
4129-
UPDATE_MISS_STATS(CALL);
4130-
assert(_PyOpcode_Deopt[opcode] == (CALL));
4131-
JUMP_TO_PREDICTED(CALL);
4132-
}
4133-
_PyStackRef arg_stackref = arguments[1];
4134-
_PyStackRef self_stackref = arguments[0];
41354141
STAT_INC(CALL, hit);
41364142
PyCFunction cfunc = method->d_method->ml_meth;
4143+
PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]);
4144+
PyObject *arg = PyStackRef_AsPyObjectBorrow(arguments[1]);
41374145
_PyFrame_SetStackPointer(frame, stack_pointer);
4138-
PyObject *res_o = _PyCFunction_TrampolineCall(cfunc,
4139-
PyStackRef_AsPyObjectBorrow(self_stackref),
4140-
PyStackRef_AsPyObjectBorrow(arg_stackref));
4146+
PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, self, arg);
41414147
stack_pointer = _PyFrame_GetStackPointer(frame);
41424148
_Py_LeaveRecursiveCallTstate(tstate);
41434149
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
@@ -5615,12 +5621,14 @@
56155621
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
56165622
PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict);
56175623
PyObject *update_o = PyStackRef_AsPyObjectBorrow(update);
5624+
PyObject *dupkey = NULL;
56185625
_PyFrame_SetStackPointer(frame, stack_pointer);
5619-
int err = _PyDict_MergeEx(dict_o, update_o, 2);
5626+
int err = _PyDict_MergeUniq(dict_o, update_o, &dupkey);
56205627
stack_pointer = _PyFrame_GetStackPointer(frame);
56215628
if (err < 0) {
56225629
_PyFrame_SetStackPointer(frame, stack_pointer);
5623-
_PyEval_FormatKwargsError(tstate, callable_o, update_o);
5630+
_PyEval_FormatKwargsError(tstate, callable_o, update_o, dupkey);
5631+
Py_XDECREF(dupkey);
56245632
stack_pointer = _PyFrame_GetStackPointer(frame);
56255633
JUMP_TO_LABEL(error);
56265634
}
@@ -9424,40 +9432,45 @@
94249432
INSTRUCTION_STATS(LIST_EXTEND);
94259433
_PyStackRef list_st;
94269434
_PyStackRef iterable_st;
9427-
iterable_st = stack_pointer[-1];
9428-
list_st = stack_pointer[-2 - (oparg-1)];
9429-
PyObject *list = PyStackRef_AsPyObjectBorrow(list_st);
9430-
PyObject *iterable = PyStackRef_AsPyObjectBorrow(iterable_st);
9431-
_PyFrame_SetStackPointer(frame, stack_pointer);
9432-
PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable);
9433-
stack_pointer = _PyFrame_GetStackPointer(frame);
9434-
if (none_val == NULL) {
9435+
_PyStackRef i;
9436+
_PyStackRef value;
9437+
// _LIST_EXTEND
9438+
{
9439+
iterable_st = stack_pointer[-1];
9440+
list_st = stack_pointer[-2 - (oparg-1)];
9441+
PyObject *list = PyStackRef_AsPyObjectBorrow(list_st);
9442+
PyObject *iterable = PyStackRef_AsPyObjectBorrow(iterable_st);
94359443
_PyFrame_SetStackPointer(frame, stack_pointer);
9436-
int matches = _PyErr_ExceptionMatches(tstate, PyExc_TypeError);
9444+
PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable);
94379445
stack_pointer = _PyFrame_GetStackPointer(frame);
9438-
if (matches &&
9439-
(Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable)))
9440-
{
9446+
if (none_val == NULL) {
94419447
_PyFrame_SetStackPointer(frame, stack_pointer);
9442-
_PyErr_Clear(tstate);
9443-
_PyErr_Format(tstate, PyExc_TypeError,
9448+
int matches = _PyErr_ExceptionMatches(tstate, PyExc_TypeError);
9449+
stack_pointer = _PyFrame_GetStackPointer(frame);
9450+
if (matches &&
9451+
(Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable)))
9452+
{
9453+
_PyFrame_SetStackPointer(frame, stack_pointer);
9454+
_PyErr_Clear(tstate);
9455+
_PyErr_Format(tstate, PyExc_TypeError,
94449456
"Value after * must be an iterable, not %.200s",
94459457
Py_TYPE(iterable)->tp_name);
9446-
stack_pointer = _PyFrame_GetStackPointer(frame);
9458+
stack_pointer = _PyFrame_GetStackPointer(frame);
9459+
}
9460+
JUMP_TO_LABEL(error);
94479461
}
9462+
assert(Py_IsNone(none_val));
9463+
i = iterable_st;
9464+
}
9465+
// _POP_TOP
9466+
{
9467+
value = i;
94489468
stack_pointer += -1;
94499469
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
94509470
_PyFrame_SetStackPointer(frame, stack_pointer);
9451-
PyStackRef_CLOSE(iterable_st);
9471+
PyStackRef_XCLOSE(value);
94529472
stack_pointer = _PyFrame_GetStackPointer(frame);
9453-
JUMP_TO_LABEL(error);
94549473
}
9455-
assert(Py_IsNone(none_val));
9456-
stack_pointer += -1;
9457-
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
9458-
_PyFrame_SetStackPointer(frame, stack_pointer);
9459-
PyStackRef_CLOSE(iterable_st);
9460-
stack_pointer = _PyFrame_GetStackPointer(frame);
94619474
DISPATCH();
94629475
}
94639476

cinderx/Jit/jit_rt.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,10 +2129,19 @@ int JITRT_DictMerge(
21292129
PyObject* dict,
21302130
PyObject* update,
21312131
PyObject* func) {
2132+
#if PY_VERSION_HEX >= 0x030F0000
2133+
PyObject* dupkey = NULL;
2134+
if (_PyDict_MergeUniq(dict, update, &dupkey) < 0) {
2135+
_PyEval_FormatKwargsError(tstate, func, update, dupkey);
2136+
Py_XDECREF(dupkey);
2137+
return -1;
2138+
}
2139+
#else
21322140
if (_PyDict_MergeEx(dict, update, 2) < 0) {
21332141
_PyEval_FormatKwargsError(tstate, func, update);
21342142
return -1;
21352143
}
2144+
#endif
21362145
return 0;
21372146
}
21382147

cinderx/ParallelGC/parallel_gc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,9 @@ gc_collect_main(
11631163
struct Ci_PyGCImpl* gc_impl,
11641164
PyThreadState* tstate,
11651165
int generation,
1166-
#if PY_VERSION_HEX >= 0x030E0000
1166+
#if PY_VERSION_HEX >= 0x030F0000
1167+
struct gc_generation_stats* stats) {
1168+
#elif PY_VERSION_HEX >= 0x030E0000
11671169
struct gc_collection_stats* stats) {
11681170
#else
11691171
Py_ssize_t* n_collected,

cinderx/UpstreamBorrow/borrowed-3.15.c.template

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ PyDictKeysObject* ci_dict_empty_keys;
166166
// @Borrow function insert_split_value from Objects/dictobject.c [3.15]
167167
// @Borrow function insert_combined_dict from Objects/dictobject.c [3.15]
168168
// @Borrow function insertdict from Objects/dictobject.c [3.15]
169+
// @Borrow function setitem_take2_lock_held_known_hash from Objects/dictobject.c [3.15]
169170
// @Borrow function setitem_take2_lock_held from Objects/dictobject.c [3.15]
170171
// @Borrow function setitem_lock_held from Objects/dictobject.c [3.15]
171172
// @Borrow function _PyDict_DelItem_KnownHash_LockHeld from Objects/dictobject.c [3.15]
@@ -396,6 +397,7 @@ error:
396397

397398
// @Borrow CPP directives noinclude from Python/pystate.c
398399
// @Borrow CPP directives noinclude from Objects/obmalloc.c
400+
// @Borrow function _pymalloc_virtual_alloc_size from Objects/obmalloc.c
399401
// @Borrow function _PyObject_VirtualAlloc from Objects/obmalloc.c
400402
// @Borrow function allocate_chunk from Python/pystate.c
401403
// @Borrow function push_chunk from Python/pystate.c

0 commit comments

Comments
 (0)