Skip to content

Commit 37a19de

Browse files
committed
Merge branch 'main' into limited_pyslot
2 parents a11419e + cd98657 commit 37a19de

24 files changed

Lines changed: 371 additions & 62 deletions

Include/internal/pycore_opcode_metadata.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_optimizer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ typedef struct _PyExecutorObject {
206206
PyAPI_FUNC(_PyExecutorObject*) _Py_GetExecutor(PyCodeObject *code, int offset);
207207

208208
int _Py_ExecutorInit(_PyExecutorObject *, const _PyBloomFilter *);
209-
void _Py_ExecutorDetach(_PyExecutorObject *);
209+
PyAPI_FUNC(void) _Py_ExecutorDetach(_PyExecutorObject *);
210210
PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
211211

212212
/* We use a bloomfilter with k = 6, m = 256

Include/internal/pycore_uop_ids.h

Lines changed: 7 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 22 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_capi/test_opt.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from test.support import (script_helper, requires_specialization,
1414
import_helper, Py_GIL_DISABLED, requires_jit_enabled,
15-
reset_code)
15+
reset_code, SHORT_TIMEOUT, isolation)
1616

1717
_testinternalcapi = import_helper.import_module("_testinternalcapi")
1818

@@ -4875,6 +4875,27 @@ def f(n):
48754875
self.assertLessEqual(count_ops(ex, "_POP_TOP"), 3)
48764876
self.assertIn("_POP_TOP_NOP", uops)
48774877

4878+
def test_to_bool_noncompact_int(self):
4879+
# gh-155486: non-compact exact integer should remain specialized
4880+
# as _TO_BOOL_INT in Tier 2.
4881+
def f(n, value=1 << 100):
4882+
for _ in range(n):
4883+
if not value:
4884+
return 0
4885+
# The second check should reuse the exact-int type established by the first guard.
4886+
if not value:
4887+
return 0
4888+
return 1
4889+
4890+
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
4891+
self.assertEqual(res, 1)
4892+
self.assertIsNotNone(ex)
4893+
uops = get_opnames(ex)
4894+
self.assertIn("_TO_BOOL_INT", uops)
4895+
self.assertLessEqual(count_ops(ex, "_GUARD_TOS_EXACT_INT"), 1)
4896+
self.assertLessEqual(count_ops(ex, "_POP_TOP"), 3)
4897+
self.assertIn("_POP_TOP_NOP", uops)
4898+
48784899
def test_to_bool_list(self):
48794900
def f(n):
48804901
for i in range(n):
@@ -6225,6 +6246,28 @@ def __exit__(self, e, v, t): ...
62256246
f1()
62266247
"""), PYTHON_JIT="1")
62276248

6249+
@isolation.runInSubprocess(timeout=SHORT_TIMEOUT)
6250+
def test_for_iter_side_exit_does_not_self_link(self):
6251+
def exhaust(iterator):
6252+
for _ in iterator:
6253+
pass
6254+
6255+
values = range(TIER2_THRESHOLD)
6256+
# After the initial trace, MAX_CHAIN_DEPTH side exits cause the final
6257+
# executor to be installed at FOR_ITER.
6258+
warmup_iterators = (
6259+
iter(set(values)),
6260+
iter(dict.fromkeys(values)),
6261+
iter(values),
6262+
enumerate(values),
6263+
zip(values, values),
6264+
)
6265+
for iterator in warmup_iterators:
6266+
exhaust(iterator)
6267+
6268+
# A different iterator type must not link that executor to itself.
6269+
exhaust(map(bool, values))
6270+
62286271
def global_identity(x):
62296272
return x
62306273

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix an infinite loop in JIT when a ``FOR_ITER`` side exit links an executor back to itself.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:mod:`os` and :mod:`signal`: Use glibc functions instead of ``syscall()``:
2+
``pidfd_open()``, ``pidfd_getfd()`` and ``pidfd_send_signal()`` (glibc 2.36),
3+
``gettid()`` and ``getdents64()`` (glibc 2.30), and ``getrandom()`` (glibc
4+
2.25). Patch by Victor Stinner.

Modules/_posixsubprocess.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -388,20 +388,26 @@ _close_range_except(int start_fd,
388388
return 0;
389389
}
390390

391-
#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
391+
#if defined(HAVE_GETDENTS64) \
392+
|| (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H))
393+
394+
#ifdef HAVE_GETDENTS64
395+
# define py_dirent64 dirent64
396+
#else
392397
/* It doesn't matter if d_name has room for NAME_MAX chars; we're using this
393398
* only to read a directory of short file descriptor number names. The kernel
394399
* will return an error if we didn't give it enough space. Highly Unlikely.
395400
* This structure is very old and stable: It will not change unless the kernel
396401
* chooses to break compatibility with all existing binaries. Highly Unlikely.
397402
*/
398-
struct linux_dirent64 {
403+
struct py_dirent64 {
399404
unsigned long long d_ino;
400405
long long d_off;
401406
unsigned short d_reclen; /* Length of this linux_dirent */
402407
unsigned char d_type;
403408
char d_name[256]; /* Filename (null-terminated) */
404409
};
410+
#endif // !HAVE_GETDENTS64
405411

406412
static int
407413
_brute_force_closer(int first, int last)
@@ -441,19 +447,27 @@ _close_open_fds_safe(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len)
441447
_brute_force_closer);
442448
return;
443449
} else {
444-
char buffer[sizeof(struct linux_dirent64)];
445-
int bytes;
446-
while ((bytes = syscall(SYS_getdents64, fd_dir_fd,
447-
(struct linux_dirent64 *)buffer,
448-
sizeof(buffer))) > 0) {
449-
struct linux_dirent64 *entry;
450+
char buffer[sizeof(struct py_dirent64)];
451+
Py_ssize_t bytes;
452+
while (1) {
453+
#ifdef HAVE_GETDENTS64
454+
bytes = getdents64(fd_dir_fd, buffer, sizeof(buffer));
455+
#else
456+
bytes = syscall(SYS_getdents64, fd_dir_fd,
457+
(struct py_dirent64 *)buffer, sizeof(buffer));
458+
#endif
459+
if (bytes <= 0) {
460+
break;
461+
}
462+
463+
struct py_dirent64 *entry;
450464
int offset;
451465
#ifdef _Py_MEMORY_SANITIZER
452466
__msan_unpoison(buffer, bytes);
453467
#endif
454468
for (offset = 0; offset < bytes; offset += entry->d_reclen) {
455469
int fd;
456-
entry = (struct linux_dirent64 *)(buffer + offset);
470+
entry = (struct py_dirent64 *)(buffer + offset);
457471
if ((fd = _pos_int_from_ascii(entry->d_name)) < 0)
458472
continue; /* Not a number. */
459473
if (fd != fd_dir_fd && fd >= start_fd &&

Modules/_testinternalcapi/test_cases.c.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/clinic/posixmodule.c.h

Lines changed: 24 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)