Skip to content

Commit c73ba59

Browse files
Merge remote-tracking branch 'upstream/main' into pr/143094
2 parents 07a6f26 + cbe0cb7 commit c73ba59

File tree

12 files changed

+86
-29
lines changed

12 files changed

+86
-29
lines changed

Include/internal/pycore_jit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ typedef _Py_CODEUNIT *(*jit_func)(
2525

2626
int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length);
2727
void _PyJIT_Free(_PyExecutorObject *executor);
28+
void _PyJIT_Fini(void);
2829

2930
#endif // _Py_JIT
3031

Include/internal/pycore_object.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -252,25 +252,6 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
252252
}
253253
}
254254

255-
static inline void
256-
_Py_DECREF_NO_DEALLOC(PyObject *op)
257-
{
258-
if (_Py_IsImmortal(op)) {
259-
_Py_DECREF_IMMORTAL_STAT_INC();
260-
return;
261-
}
262-
_Py_DECREF_STAT_INC();
263-
#ifdef Py_REF_DEBUG
264-
_Py_DEC_REFTOTAL(PyInterpreterState_Get());
265-
#endif
266-
op->ob_refcnt--;
267-
#ifdef Py_DEBUG
268-
if (op->ob_refcnt <= 0) {
269-
_Py_FatalRefcountError("Expected a positive remaining refcount");
270-
}
271-
#endif
272-
}
273-
274255
#else
275256
// TODO: implement Py_DECREF specializations for Py_GIL_DISABLED build
276257
static inline void
@@ -279,12 +260,6 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
279260
Py_DECREF(op);
280261
}
281262

282-
static inline void
283-
_Py_DECREF_NO_DEALLOC(PyObject *op)
284-
{
285-
Py_DECREF(op);
286-
}
287-
288263
static inline int
289264
_Py_REF_IS_MERGED(Py_ssize_t ob_ref_shared)
290265
{

Include/internal/pycore_optimizer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ typedef struct {
2727
uint8_t valid;
2828
uint8_t chain_depth; // Must be big enough for MAX_CHAIN_DEPTH - 1.
2929
bool warm;
30+
uint8_t pending_deletion;
3031
int32_t index; // Index of ENTER_EXECUTOR (if code isn't NULL, below).
3132
_PyBloomFilter bloom;
3233
_PyExecutorLinkListNode links;

Lib/multiprocessing/spawn.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def get_preparation_data(name):
184184
sys_argv=sys.argv,
185185
orig_dir=process.ORIGINAL_DIR,
186186
dir=os.getcwd(),
187-
start_method=get_start_method(),
187+
start_method=get_start_method(allow_none=True),
188188
)
189189

190190
# Figure out whether to initialise main in the subprocess as a module

Lib/test/_test_multiprocessing.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5967,6 +5967,26 @@ def test_context(self):
59675967
self.assertRaises(ValueError, ctx.set_start_method, None)
59685968
self.check_context(ctx)
59695969

5970+
@staticmethod
5971+
def _dummy_func():
5972+
pass
5973+
5974+
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
5975+
def test_spawn_dont_set_context(self):
5976+
# Run a process with spawn or forkserver context may change
5977+
# the global start method, see gh-109263.
5978+
for method in ('fork', 'spawn', 'forkserver'):
5979+
multiprocessing.set_start_method(None, force=True)
5980+
5981+
try:
5982+
ctx = multiprocessing.get_context(method)
5983+
except ValueError:
5984+
continue
5985+
process = ctx.Process(target=self._dummy_func)
5986+
process.start()
5987+
process.join()
5988+
self.assertIsNone(multiprocessing.get_start_method(allow_none=True))
5989+
59705990
def test_context_check_module_types(self):
59715991
try:
59725992
ctx = multiprocessing.get_context('forkserver')

Lib/test/test_capi/test_opt.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3133,6 +3133,26 @@ def testfunc(n):
31333133
self.assertNotIn("_POP_TOP_INT", uops)
31343134
self.assertIn("_POP_TOP_NOP", uops)
31353135

3136+
def test_143026(self):
3137+
# https://github.com/python/cpython/issues/143026
3138+
3139+
result = script_helper.run_python_until_end('-c', textwrap.dedent("""
3140+
import gc
3141+
thresholds = gc.get_threshold()
3142+
try:
3143+
gc.set_threshold(1)
3144+
3145+
def f1():
3146+
for i in range(5000):
3147+
globals()[''] = i
3148+
3149+
f1()
3150+
finally:
3151+
gc.set_threshold(*thresholds)
3152+
"""), PYTHON_JIT="1")
3153+
self.assertEqual(result[0].rc, 0, result)
3154+
3155+
31363156
def global_identity(x):
31373157
return x
31383158

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Starting a process from spawn context in :mod:`multiprocessing` no longer
2+
sets the start method globally.

Python/jit.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ typedef struct {
151151
uintptr_t instruction_starts[UOP_MAX_TRACE_LENGTH];
152152
} jit_state;
153153

154+
static size_t _Py_jit_shim_size = 0;
155+
154156
// Warning! AArch64 requires you to get your hands dirty. These are your gloves:
155157

156158
// value[value_start : value_start + len]
@@ -676,6 +678,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz
676678
* We compile this once only as it effectively a normal
677679
* function, but we need to use the JIT because it needs
678680
* to understand the jit-specific calling convention.
681+
* Don't forget to call _PyJIT_Fini later!
679682
*/
680683
static _PyJitEntryFuncPtr
681684
compile_shim(void)
@@ -717,6 +720,7 @@ compile_shim(void)
717720
jit_free(memory, total_size);
718721
return NULL;
719722
}
723+
_Py_jit_shim_size = total_size;
720724
return (_PyJitEntryFuncPtr)memory;
721725
}
722726

@@ -739,6 +743,7 @@ _Py_LazyJitShim(
739743
return _Py_jit_entry(executor, frame, stack_pointer, tstate);
740744
}
741745

746+
// Free executor's memory allocated with _PyJIT_Compile
742747
void
743748
_PyJIT_Free(_PyExecutorObject *executor)
744749
{
@@ -754,4 +759,22 @@ _PyJIT_Free(_PyExecutorObject *executor)
754759
}
755760
}
756761

762+
// Free shim memory allocated with compile_shim
763+
void
764+
_PyJIT_Fini(void)
765+
{
766+
PyMutex_Lock(&lazy_jit_mutex);
767+
unsigned char *memory = (unsigned char *)_Py_jit_entry;
768+
size_t size = _Py_jit_shim_size;
769+
if (size) {
770+
_Py_jit_entry = _Py_LazyJitShim;
771+
_Py_jit_shim_size = 0;
772+
if (jit_free(memory, size)) {
773+
PyErr_FormatUnraisable("Exception ignored while "
774+
"freeing JIT entry code");
775+
}
776+
}
777+
PyMutex_Unlock(&lazy_jit_mutex);
778+
}
779+
757780
#endif // _Py_JIT

Python/optimizer.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ _Py_ClearExecutorDeletionList(PyInterpreterState *interp)
310310
while (ts) {
311311
_PyExecutorObject *current = (_PyExecutorObject *)ts->current_executor;
312312
if (current != NULL) {
313-
_Py_DECREF_NO_DEALLOC((PyObject *)current);
313+
Py_DECREF((PyObject *)current);
314314
}
315315
ts = ts->next;
316316
}
@@ -320,6 +320,10 @@ _Py_ClearExecutorDeletionList(PyInterpreterState *interp)
320320
static void
321321
add_to_pending_deletion_list(_PyExecutorObject *self)
322322
{
323+
if (self->vm_data.pending_deletion) {
324+
return;
325+
}
326+
self->vm_data.pending_deletion = 1;
323327
PyInterpreterState *interp = PyInterpreterState_Get();
324328
self->vm_data.links.previous = NULL;
325329
self->vm_data.links.next = interp->executor_deletion_list_head;
@@ -627,7 +631,7 @@ _PyJit_translate_single_bytecode_to_trace(
627631
uint32_t target = 0;
628632

629633
target = Py_IsNone((PyObject *)old_code)
630-
? (int)(target_instr - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR)
634+
? (uint32_t)(target_instr - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR)
631635
: INSTR_IP(target_instr, old_code);
632636

633637
// Rewind EXTENDED_ARG so that we see the whole thing.
@@ -1666,6 +1670,7 @@ void
16661670
_Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_set)
16671671
{
16681672
executor->vm_data.valid = true;
1673+
executor->vm_data.pending_deletion = 0;
16691674
for (int i = 0; i < _Py_BLOOM_FILTER_WORDS; i++) {
16701675
executor->vm_data.bloom.bits[i] = dependency_set->bits[i];
16711676
}

Python/pylifecycle.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
#include "pycore_uniqueid.h" // _PyObject_FinalizeUniqueIdPool()
3636
#include "pycore_warnings.h" // _PyWarnings_InitState()
3737
#include "pycore_weakref.h" // _PyWeakref_GET_REF()
38+
#ifdef _Py_JIT
39+
#include "pycore_jit.h" // _PyJIT_Fini()
40+
#endif
3841

3942
#include "opcode.h"
4043

@@ -2267,6 +2270,7 @@ _Py_Finalize(_PyRuntimeState *runtime)
22672270
/* Print debug stats if any */
22682271
_PyEval_Fini();
22692272

2273+
22702274
/* Flush sys.stdout and sys.stderr (again, in case more was printed) */
22712275
if (flush_std_files() < 0) {
22722276
status = -1;
@@ -2346,6 +2350,10 @@ _Py_Finalize(_PyRuntimeState *runtime)
23462350

23472351
finalize_interp_clear(tstate);
23482352

2353+
#ifdef _Py_JIT
2354+
/* Free JIT shim memory */
2355+
_PyJIT_Fini();
2356+
#endif
23492357

23502358
#ifdef Py_TRACE_REFS
23512359
/* Display addresses (& refcnts) of all objects still alive.

0 commit comments

Comments
 (0)