From ed528af780d7e55a619ac3852cf34950e5bbbb5c Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 16 Jun 2026 20:51:55 +0200 Subject: [PATCH 1/4] Fix parsing sdist names with dashes in name --- .../src/tests/test_patched_pip.py | 19 +++++++++++++++++-- .../modules/graalpy_pip_extensions.py | 14 ++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_patched_pip.py b/graalpython/com.oracle.graal.python.test/src/tests/test_patched_pip.py index dc3647c4aa..ffeec0ffe5 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_patched_pip.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_patched_pip.py @@ -152,12 +152,12 @@ def build_package(self, name, version): self.package_cache[cache_key] = {'sdist': sdist, 'wheel': wheel} return self.package_cache[cache_key] - def add_package_to_index(self, name, version, dist_type): + def add_package_to_index(self, name, version, dist_type, destination_name=None): package = self.build_package(name, version)[dist_type] # extra careful, not using shutil.copy so we get more detailed traceback # on some flaky windows CI workers self.assertTrue(package.exists(), f"Built package disappeared: {package}") - destination = self.index_dir / package.name + destination = self.index_dir / (destination_name or package.name) with open(package, 'rb') as src, open(destination, 'wb') as dst: shutil.copyfileobj(src, dst) @@ -252,6 +252,21 @@ def test_sdist_unpatched_version(self): self.run_venv_pip_install('foo') assert self.run_test_fun() == "Unpatched" + def test_sdist_hyphenated_name_with_patched_prefix(self): + self.add_package_to_index( + 'cython-test-exception-raiser', + '1.0.2', + 'sdist', + destination_name='cython-test-exception-raiser-1.0.2.tar.gz', + ) + self.prepare_config('cython', [{ + 'patch': 'cython.patch', + 'version': '>= 3', + 'subdir': 'src', + }]) + self.run_venv_pip_install('cython-test-exception-raiser') + assert self.run_test_fun() == "Unpatched" + def test_sdist_patched_version(self): self.add_package_to_index('foo', '1.1.0', 'sdist') self.prepare_config('foo', [{ diff --git a/graalpython/lib-graalpython/modules/graalpy_pip_extensions.py b/graalpython/lib-graalpython/modules/graalpy_pip_extensions.py index e963eefdf0..7136258574 100644 --- a/graalpython/lib-graalpython/modules/graalpy_pip_extensions.py +++ b/graalpython/lib-graalpython/modules/graalpy_pip_extensions.py @@ -300,8 +300,18 @@ def apply_graalpy_patches(filename, location, warn_suggested_versions=False): # we expect filename to be something like "pytest-5.4.2-py3-none-any.whl" archive_name = os.path.basename(filename) - name_ver_match = re.match(r"^(?P.*?)-(?P[^-]+).*?\.(?Ptar\.gz|tar|whl|zip)$", - archive_name, re.I) + if archive_name.endswith('.whl'): + name_ver_match = re.match( + r"^(?P[^-]+)-(?P[^-]+)(?:-(?P[^-]+))?-(?P[^-]+)-(?P[^-]+)-(?P[^-]+)\.(?Pwhl)$", + archive_name, + re.I, + ) + else: + name_ver_match = re.match( + r"^(?P.*)-(?P[^-]+)\.(?Ptar\.gz|tar|zip)$", + archive_name, + re.I, + ) if not name_ver_match: logger.warning(f"GraalPy warning: could not parse package name, version, or format from {archive_name!r}.\n" "Could not determine if any GraalPy specific patches need to be applied.") From 7a36645c9dc89e1944c0c8480c0ba5705e22aef1 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 18 Jun 2026 10:49:38 +0200 Subject: [PATCH 2/4] Remove patch for old pip --- .../lib-graalpython/patches/metadata.toml | 6 - .../lib-graalpython/patches/pip-23.2.1.patch | 619 ------------------ 2 files changed, 625 deletions(-) delete mode 100644 graalpython/lib-graalpython/patches/pip-23.2.1.patch diff --git a/graalpython/lib-graalpython/patches/metadata.toml b/graalpython/lib-graalpython/patches/metadata.toml index b009f39440..1571d5636b 100644 --- a/graalpython/lib-graalpython/patches/metadata.toml +++ b/graalpython/lib-graalpython/patches/metadata.toml @@ -582,12 +582,6 @@ note = "Not needed since 3.1." install-priority = 0 license = 'MIT' -[[pip.rules]] -version = '== 23.2.1' -patch = 'pip-23.2.1.patch' -license = 'MIT' -subdir = 'src' - [[pip.rules]] version = '== 24.3.1' patch = 'pip-24.3.1.patch' diff --git a/graalpython/lib-graalpython/patches/pip-23.2.1.patch b/graalpython/lib-graalpython/patches/pip-23.2.1.patch deleted file mode 100644 index 32a8e7f1aa..0000000000 --- a/graalpython/lib-graalpython/patches/pip-23.2.1.patch +++ /dev/null @@ -1,619 +0,0 @@ -diff --git a/pip/__init__.py b/pip/__init__.py -index 6633ef7..d7c21db 100644 ---- a/pip/__init__.py -+++ b/pip/__init__.py -@@ -11,3 +11,6 @@ def main(args: Optional[List[str]] = None) -> int: - from pip._internal.utils.entrypoints import _wrapper - - return _wrapper(args) -+ -+ -+__GRAALPY_PATCHED = True -diff --git a/pip/_internal/cli/cmdoptions.py b/pip/_internal/cli/cmdoptions.py -index 02ba608..85c7c22 100644 ---- a/pip/_internal/cli/cmdoptions.py -+++ b/pip/_internal/cli/cmdoptions.py -@@ -357,7 +357,9 @@ def extra_index_url() -> Option: - dest="extra_index_urls", - metavar="URL", - action="append", -- default=[], -+ # GraalPy change: add default extra index with our prebuilt binaries. If PIP_INDEX_URL is set, -+ # assume the user configured a custom index and does not want to use any default index. -+ default=[] if "PIP_INDEX_URL" in os.environ else ["https://www.graalvm.org/python/wheels/"], - help="Extra URLs of package indexes to use in addition to " - "--index-url. Should follow the same rules as " - "--index-url.", -@@ -892,7 +894,7 @@ disable_pip_version_check: Callable[..., Option] = partial( - "--disable-pip-version-check", - dest="disable_pip_version_check", - action="store_true", -- default=False, -+ default=True, # GraalPy: we do not want to incentivize the upgrade - help="Don't periodically check PyPI to determine whether a new version " - "of pip is available for download. Implied with --no-index.", - ) -diff --git a/pip/_internal/cli/req_command.py b/pip/_internal/cli/req_command.py -index 86070f1..2c8889a 100644 ---- a/pip/_internal/cli/req_command.py -+++ b/pip/_internal/cli/req_command.py -@@ -68,6 +68,10 @@ def _create_truststore_ssl_context() -> Optional["SSLContext"]: - return truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - - -+# GraalPy change: we need the session to fetch remote metadata, but it would be too difficult to pass it down all -+# the possible code paths -+_GRAALPY_SESSION = None -+ - class SessionCommandMixin(CommandContextMixIn): - - """ -@@ -100,6 +104,9 @@ class SessionCommandMixin(CommandContextMixIn): - # automatically ContextManager[Any] and self._session becomes Any, - # then https://github.com/python/mypy/issues/7696 kicks in - assert self._session is not None -+ # GraalPy change -+ global _GRAALPY_SESSION -+ _GRAALPY_SESSION = self._session - return self._session - - def _build_session( -diff --git a/pip/_internal/index/package_finder.py b/pip/_internal/index/package_finder.py -index b6f8d57..6c37e0b 100644 ---- a/pip/_internal/index/package_finder.py -+++ b/pip/_internal/index/package_finder.py -@@ -35,6 +35,7 @@ from pip._internal.utils.logging import indent_log - from pip._internal.utils.misc import build_netloc - from pip._internal.utils.packaging import check_requires_python - from pip._internal.utils.unpacking import SUPPORTED_EXTENSIONS -+from pip._internal.utils.graalpy import apply_graalpy_sort_order, get_graalpy_candidates - - if TYPE_CHECKING: - from pip._vendor.typing_extensions import TypeGuard -@@ -487,6 +488,7 @@ class CandidateEvaluator: - - return sorted(filtered_applicable_candidates, key=self._sort_key) - -+ @apply_graalpy_sort_order - def _sort_key(self, candidate: InstallationCandidate) -> CandidateSortingKey: - """ - Function to pass as the `key` argument to a call to sorted() to sort -@@ -852,8 +854,11 @@ class PackageFinder: - - logger.debug("Local files found: %s", ", ".join(paths)) - -+ # We add links for few packages that don't publish sdists -+ graalpy_candidates = get_graalpy_candidates(project_name) -+ - # This is an intentional priority ordering -- return file_candidates + page_candidates -+ return file_candidates + page_candidates + graalpy_candidates - - def make_candidate_evaluator( - self, -diff --git a/pip/_internal/network/download.py b/pip/_internal/network/download.py -index 79b82a5..3ee418a 100644 ---- a/pip/_internal/network/download.py -+++ b/pip/_internal/network/download.py -@@ -6,6 +6,7 @@ import mimetypes - import os - from typing import Iterable, Optional, Tuple - -+from pip._internal.utils.graalpy import AddedSourceLink - from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response - - from pip._internal.cli.progress_bars import get_download_progress_renderer -@@ -98,7 +99,7 @@ def _get_http_response_filename(resp: Response, link: Link) -> str: - filename = link.filename # fallback - # Have a look at the Content-Disposition header for a better guess - content_disposition = resp.headers.get("content-disposition") -- if content_disposition: -+ if content_disposition and not isinstance(link, AddedSourceLink): - filename = parse_content_disposition(content_disposition, filename) - ext: Optional[str] = splitext(filename)[1] - if not ext: -diff --git a/pip/_internal/operations/install/wheel.py b/pip/_internal/operations/install/wheel.py -index a8cd133..20dd1e6 100644 ---- a/pip/_internal/operations/install/wheel.py -+++ b/pip/_internal/operations/install/wheel.py -@@ -591,6 +591,9 @@ def _install_wheel( - file.save() - record_installed(file.src_record_path, file.dest_path, file.changed) - -+ from pip._internal.utils.graalpy import apply_graalpy_patches -+ apply_graalpy_patches(wheel_path, lib_dir) -+ - def pyc_source_file_paths() -> Generator[str, None, None]: - # We de-duplicate installation paths, since there can be overlap (e.g. - # file in .data maps to same location as file in wheel root). -diff --git a/pip/_internal/resolution/resolvelib/candidates.py b/pip/_internal/resolution/resolvelib/candidates.py -index de04e1d..888ba75 100644 ---- a/pip/_internal/resolution/resolvelib/candidates.py -+++ b/pip/_internal/resolution/resolvelib/candidates.py -@@ -20,6 +20,7 @@ from pip._internal.req.constructors import ( - from pip._internal.req.req_install import InstallRequirement - from pip._internal.utils.direct_url_helpers import direct_url_from_link - from pip._internal.utils.misc import normalize_version_info -+from pip._internal.utils import graalpy - - from .base import Candidate, CandidateVersion, Requirement, format_name - -@@ -242,6 +243,8 @@ class _InstallRequirementBackedCandidate(Candidate): - for r in requires: - yield self._factory.make_requirement_from_spec(str(r), self._ireq) - yield self._factory.make_requires_python_requirement(self.dist.requires_python) -+ if self.name == 'virtualenv' and not graalpy.DISABLE_PATCHING: -+ yield self._factory.make_requirement_from_spec('graalpy-virtualenv-seeder', self._ireq) - - def get_install_requirement(self) -> Optional[InstallRequirement]: - return self._ireq -diff --git a/pip/_internal/utils/graalpy.py b/pip/_internal/utils/graalpy.py -new file mode 100644 -index 0000000..a976ab5 ---- /dev/null -+++ b/pip/_internal/utils/graalpy.py -@@ -0,0 +1,334 @@ -+import abc -+import logging -+import os -+import re -+import sys -+import tempfile -+import zipfile -+from contextlib import contextmanager -+from pathlib import Path -+from tomllib import TOMLDecodeError -+from urllib.parse import urlparse, urljoin, urlunparse -+ -+from pip._internal.models.candidate import InstallationCandidate -+from pip._internal.models.link import Link -+from pip._internal.utils.urls import url_to_path, path_to_url -+from pip._vendor import tomli, requests -+from pip._vendor.packaging.specifiers import SpecifierSet -+from pip._vendor.packaging.utils import canonicalize_name -+from pip._vendor.packaging.version import VERSION_PATTERN -+ -+MARKER_FILE_NAME = 'GRAALPY_MARKER' -+METADATA_FILENAME = 'metadata.toml' -+DEFAULT_PATCHES_PATH = Path(__graalpython__.core_home) / 'patches' -+VERSION_PARAMETER = '' -+DEFAULT_PATCHES_URL = f'https://raw.githubusercontent.com/oracle/graalpython/refs/heads/github/patches/{VERSION_PARAMETER}/graalpython/lib-graalpython/patches/' -+ -+PATCHES_URL = os.environ.get('PIP_GRAALPY_PATCHES_URL', DEFAULT_PATCHES_URL) -+DISABLE_PATCHING = os.environ.get('PIP_GRAALPY_DISABLE_PATCHING', '').lower() in ('true', '1') -+DISABLE_VERSION_SELECTION = os.environ.get('PIP_GRAALPY_DISABLE_VERSION_SELECTION', '').lower() in ('true', '1') -+ -+GRAALPY_VERSION = os.environ.get('TEST_PIP_GRAALPY_VERSION', __graalpython__.get_graalvm_version()) -+ -+logger = logging.getLogger(__name__) -+ -+ -+def url_for_file(patches_url, filename): -+ scheme, netloc, path, params, query, fragment = urlparse(patches_url) -+ path = urljoin(path, filename) -+ return urlunparse((scheme, netloc, path, params, query, fragment)) -+ -+ -+class RepositoryException(Exception): -+ pass -+ -+ -+class AbstractPatchRepository(metaclass=abc.ABCMeta): -+ def __init__(self, metadata: dict): -+ self._repository = metadata -+ -+ @staticmethod -+ def metadata_from_string(metadata_content) -> dict: -+ try: -+ parsed_metadata = tomli.loads(metadata_content) -+ return {canonicalize_name(name): data for name, data in parsed_metadata.items()} -+ except TOMLDecodeError as e: -+ raise RepositoryException(f"'{METADATA_FILENAME}' cannot be parsed: {e}") -+ -+ def get_rules(self, name): -+ if metadata := self._repository.get(canonicalize_name(name)): -+ return metadata.get('rules') -+ -+ def get_add_sources(self, name): -+ if metadata := self._repository.get(canonicalize_name(name)): -+ return metadata.get('add-sources') -+ -+ def get_priority_for_version(self, name, version): -+ if rules := self.get_rules(name): -+ for rule in rules: -+ if self.rule_matches_version(rule, version): -+ return rule.get('install-priority', 1) -+ return 0 -+ -+ @staticmethod -+ def rule_matches_version(rule, version): -+ return not rule.get('version') or SpecifierSet(rule['version']).contains(version) -+ -+ def get_suggested_version_specs(self, name): -+ versions = set() -+ if rules := self.get_rules(name): -+ for rule in rules: -+ if 'patch' in rule and rule.get('install-priority', 1) > 0 and (version := rule.get('version')): -+ versions.add(version) -+ return versions -+ -+ def get_matching_rule(self, name, requested_version, dist_type): -+ if metadata := self.get_rules(name): -+ for rule in metadata: -+ if rule.get('dist-type', dist_type) != dist_type: -+ continue -+ if not self.rule_matches_version(rule, requested_version): -+ continue -+ return rule -+ -+ @abc.abstractmethod -+ def resolve_patch(self, patch_name: str): -+ pass -+ -+ -+class EmptyRepository(AbstractPatchRepository): -+ def __init__(self): -+ super().__init__({}) -+ -+ def resolve_patch(self, patch_name: str): -+ raise AssertionError("Invalid call") -+ -+ -+class LocalPatchRepository(AbstractPatchRepository): -+ def __init__(self, patches_path: Path, repository_data: dict): -+ super().__init__(repository_data) -+ self.patches_path = patches_path -+ logger.debug("Loaded GraalPy patch repository from %s", patches_path) -+ -+ @classmethod -+ def from_path(cls, patches_path: Path): -+ try: -+ with open(patches_path / METADATA_FILENAME) as f: -+ metadata_content = f.read() -+ except OSError as e: -+ raise RepositoryException(f"'{METADATA_FILENAME}' cannot be read: {e}") -+ return cls(patches_path, cls.metadata_from_string(metadata_content)) -+ -+ @contextmanager -+ def resolve_patch(self, patch_name: str): -+ yield self.patches_path / patch_name -+ -+ -+class RemotePatchRepository(AbstractPatchRepository): -+ def __init__(self, patches_url: str, repository_data: dict): -+ super().__init__(repository_data) -+ self.patches_url = patches_url -+ logger.debug("Loaded GraalPy patch repository from %s", patches_url) -+ -+ @staticmethod -+ def get_session(): -+ from pip._internal.cli.req_command import _GRAALPY_SESSION -+ return _GRAALPY_SESSION or requests.Session() -+ -+ @classmethod -+ def from_url(cls, patches_url: str): -+ try: -+ url = url_for_file(patches_url, METADATA_FILENAME) -+ response = cls.get_session().get(url) -+ response.raise_for_status() -+ metadata_content = response.content.decode('utf-8') -+ except Exception as e: -+ raise RepositoryException(f"'{METADATA_FILENAME} cannot be retrieved': {e}") -+ return cls(patches_url, cls.metadata_from_string(metadata_content)) -+ -+ @contextmanager -+ def resolve_patch(self, patch_name: str): -+ try: -+ response = self.get_session().get(url_for_file(self.patches_url, patch_name)) -+ response.raise_for_status() -+ except requests.RequestException as e: -+ logger.warning("Failed to download GraalPy patch '%s': %s", patch_name, e) -+ yield None -+ else: -+ with tempfile.TemporaryDirectory() as tempdir: -+ patch_file = Path(tempdir) / patch_name -+ with open(patch_file, 'wb') as f: -+ f.write(response.content) -+ yield patch_file -+ -+ -+__PATCH_REPOSITORY = None -+ -+ -+def repository_from_url_or_path(url_or_path): -+ if '://' not in url_or_path: -+ return LocalPatchRepository.from_path(Path(url_or_path)) -+ elif url_or_path.startswith('file:'): -+ patches_path = Path(url_to_path(url_or_path)) -+ return LocalPatchRepository.from_path(patches_path) -+ else: -+ patches_url = url_or_path -+ if not patches_url.endswith('/'): -+ patches_url += '/' -+ return RemotePatchRepository.from_url(patches_url) -+ -+ -+def create_patch_repository(patches_url): -+ if patches_url and VERSION_PARAMETER in patches_url: -+ if not GRAALPY_VERSION.endswith('-dev'): -+ patches_url = patches_url.replace(VERSION_PARAMETER, GRAALPY_VERSION) -+ else: -+ logger.debug("Skipping versioned GraalPy patch repository on snapshot build") -+ patches_url = None -+ if patches_url: -+ try: -+ return repository_from_url_or_path(patches_url) -+ except RepositoryException as e: -+ logger.warning("Failed to load GraalPy patch repository from %s: %s", patches_url, e) -+ logger.warning("Falling back to internal GraalPy patch repository") -+ try: -+ return LocalPatchRepository.from_path(DEFAULT_PATCHES_PATH) -+ except RepositoryException as e: -+ logger.warning("Failed to load internal GraalPy patch repository: %s", e) -+ return EmptyRepository() -+ -+ -+def get_patch_repository(): -+ global __PATCH_REPOSITORY -+ if not __PATCH_REPOSITORY: -+ __PATCH_REPOSITORY = create_patch_repository(PATCHES_URL) -+ return __PATCH_REPOSITORY -+ -+ -+def apply_graalpy_patches(filename, location): -+ """ -+ Applies any GraalPy patches to package extracted from 'filename' into 'location'. -+ Note that 'location' must be the parent directory of the package directory itself. -+ For example: /path/to/site-package and not /path/to/site-packages/mypackage. -+ """ -+ if DISABLE_PATCHING: -+ return -+ -+ # we expect filename to be something like "pytest-5.4.2-py3-none-any.whl" -+ archive_name = os.path.basename(filename) -+ name_ver_match = re.match(fr"^(?P.*?)-(?P{VERSION_PATTERN}).*?\.(?Ptar\.gz|tar|whl|zip)$", -+ archive_name, re.VERBOSE | re.I) -+ if not name_ver_match: -+ logger.warning(f"GraalPy warning: could not parse package name, version, or format from {archive_name!r}.\n" -+ "Could not determine if any GraalPy specific patches need to be applied.") -+ return -+ -+ name = name_ver_match.group('name') -+ version = name_ver_match.group('version') -+ suffix = name_ver_match.group('suffix') -+ is_wheel = suffix == "whl" -+ -+ if is_wheel and is_wheel_marked(filename): -+ # We already processed it when building from source -+ return -+ -+ import autopatch_capi -+ import subprocess -+ -+ autopatch_capi.auto_patch_tree(location) -+ -+ logger.info(f"Looking for GraalPy patches for {name}") -+ repository = get_patch_repository() -+ -+ if is_wheel: -+ # patches intended for binary distribution: -+ rule = repository.get_matching_rule(name, version, 'wheel') -+ else: -+ # patches intended for source distribution if applicable -+ rule = repository.get_matching_rule(name, version, 'sdist') -+ if not rule: -+ rule = repository.get_matching_rule(name, version, 'wheel') -+ if rule and (subdir := rule.get('subdir')): -+ # we may need to change wd if we are actually patching a source distribution -+ # with a patch intended for a binary distribution, because in the source -+ # distribution the actual deployed sources may be in a subdirectory (typically "src") -+ location = os.path.join(location, subdir) -+ if rule: -+ if patch := rule.get('patch'): -+ with repository.resolve_patch(patch) as patch_path: -+ if not patch_path: -+ return -+ logger.info(f"Patching package {name} using {patch}") -+ exe = '.exe' if os.name == 'nt' else '' -+ try: -+ subprocess.run([f"patch{exe}", "-f", "-d", location, "-p1", "-i", str(patch_path)], check=True) -+ except FileNotFoundError: -+ logger.warning( -+ "WARNING: GraalPy needs the 'patch' utility to apply compatibility patches. Please install it using your system's package manager.") -+ except subprocess.CalledProcessError: -+ logger.warning(f"Applying GraalPy patch failed for {name}. The package may still work.") -+ elif version_specs := repository.get_suggested_version_specs(name): -+ logger.info("We have patches to make this package work on GraalVM for some version(s).") -+ logger.info("If installing or running fails, consider using one of the versions that we have patches for:") -+ for version_spec in version_specs: -+ logger.info(f'{name} {version_spec}') -+ -+ -+def apply_graalpy_sort_order(sort_key_func): -+ if DISABLE_VERSION_SELECTION: -+ return sort_key_func -+ -+ def wrapper(self, candidate): -+ default_sort_key = sort_key_func(self, candidate) -+ priority = get_patch_repository().get_priority_for_version(candidate.name, str(candidate.version)) -+ return priority, default_sort_key -+ -+ return wrapper -+ -+ -+class AddedSourceLink(Link): -+ def __init__(self, url: str, filename: str): -+ super().__init__(url) -+ self._filename = filename -+ -+ @property -+ def filename(self) -> str: -+ return self._filename -+ -+ -+def get_graalpy_candidates(name): -+ repository = get_patch_repository() -+ candidates = [] -+ for add_source in repository.get_add_sources(name) or []: -+ version = add_source['version'] -+ url = add_source['url'] -+ match = re.search(r'\.(tar\.(?:gz|bz2|xz)|zip|whl)$', urlparse(url).path) -+ assert match, "Couldn't determine URL suffix" -+ suffix = match.group(1) -+ # We need to force the filename to match the usual convention, otherwise we won't find a patch -+ link = AddedSourceLink(url, f'{name}-{version}.{suffix}') -+ candidates.append(InstallationCandidate(name=name, version=version, link=link)) -+ if name == 'graalpy-virtualenv-seeder': -+ link = Link(path_to_url(os.path.join(sys.base_prefix, 'graalpy_virtualenv_seeder'))) -+ candidates.append(InstallationCandidate(name=name, version='0.0.1', link=link)) -+ return candidates -+ -+ -+def mark_wheel(path): -+ if DISABLE_PATCHING: -+ return -+ with zipfile.ZipFile(path, 'a') as z: -+ dist_info = None -+ for name in z.namelist(): -+ if m := re.match(r'([^/]+.dist-info)/', name): -+ dist_info = m.group(1) -+ break -+ assert dist_info, "Cannot find .dist_info in built wheel" -+ marker = f'{dist_info}/{MARKER_FILE_NAME}' -+ with z.open(marker, 'w'): -+ pass -+ -+ -+def is_wheel_marked(path): -+ with zipfile.ZipFile(path) as z: -+ return any(re.match(rf'[^/]+.dist-info/{MARKER_FILE_NAME}$', f) for f in z.namelist()) -diff --git a/pip/_internal/utils/unpacking.py b/pip/_internal/utils/unpacking.py -index 78b5c13..18a184c 100644 ---- a/pip/_internal/utils/unpacking.py -+++ b/pip/_internal/utils/unpacking.py -@@ -255,3 +255,5 @@ def unpack_file( - content_type, - ) - raise InstallationError(f"Cannot determine archive format of {location}") -+ from pip._internal.utils.graalpy import apply_graalpy_patches -+ apply_graalpy_patches(filename, location) -diff --git a/pip/_internal/wheel_builder.py b/pip/_internal/wheel_builder.py -index 60d75dd..bdf4231 100644 ---- a/pip/_internal/wheel_builder.py -+++ b/pip/_internal/wheel_builder.py -@@ -7,6 +7,7 @@ import re - import shutil - from typing import Iterable, List, Optional, Tuple - -+from pip._internal.utils import graalpy - from pip._vendor.packaging.utils import canonicalize_name, canonicalize_version - from pip._vendor.packaging.version import InvalidVersion, Version - -@@ -115,6 +116,10 @@ def _should_cache( - if _contains_egg_info(base): - return True - -+ # GraalPy change -+ if isinstance(req.link, graalpy.AddedSourceLink): -+ return True -+ - # Otherwise, do not cache. - return False - -@@ -248,6 +253,11 @@ def _build_one_inside_env( - ) - - if wheel_path is not None: -+ # GraalPy change: watermark wheels that we built so that we don't try to patch them when installing -+ # Note: we currently don't patch source builds from SCM links, so we don't watermark them so that they can -+ # get patched with a wheel patch -+ if not req.link.is_vcs: -+ graalpy.mark_wheel(wheel_path) - wheel_name = os.path.basename(wheel_path) - dest_path = os.path.join(output_dir, wheel_name) - try: -diff --git a/pip/_vendor/packaging/tags.py b/pip/_vendor/packaging/tags.py -index 9a3d25a..e0e7b31 100644 ---- a/pip/_vendor/packaging/tags.py -+++ b/pip/_vendor/packaging/tags.py -@@ -4,6 +4,7 @@ - - import logging - import platform -+import struct - import sys - import sysconfig - from importlib.machinery import EXTENSION_SUFFIXES -@@ -36,7 +37,7 @@ INTERPRETER_SHORT_NAMES: Dict[str, str] = { - } - - --_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32 -+_32_BIT_INTERPRETER = struct.calcsize("P") == 4 - - - class Tag: -@@ -224,10 +225,46 @@ def cpython_tags( - yield Tag(interpreter, "abi3", platform_) - - --def _generic_abi() -> Iterator[str]: -- abi = sysconfig.get_config_var("SOABI") -- if abi: -- yield _normalize_string(abi) -+# GraalVM change: backported change from pypa/packaging -+def _generic_abi() -> List[str]: -+ """ -+ Return the ABI tag based on EXT_SUFFIX. -+ """ -+ # The following are examples of `EXT_SUFFIX`. -+ # We want to keep the parts which are related to the ABI and remove the -+ # parts which are related to the platform: -+ # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 -+ # - mac: '.cpython-310-darwin.so' => cp310 -+ # - win: '.cp310-win_amd64.pyd' => cp310 -+ # - win: '.pyd' => cp37 (uses _cpython_abis()) -+ # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73 -+ # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' -+ # => graalpy_38_native -+ -+ ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) -+ if not isinstance(ext_suffix, str) or ext_suffix[0] != ".": -+ raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") -+ parts = ext_suffix.split(".") -+ if len(parts) < 3: -+ # CPython3.7 and earlier uses ".pyd" on Windows. -+ return _cpython_abis(sys.version_info[:2]) -+ soabi = parts[1] -+ if soabi.startswith("cpython"): -+ # non-windows -+ abi = "cp" + soabi.split("-")[1] -+ elif soabi.startswith("cp"): -+ # windows -+ abi = soabi.split("-")[0] -+ elif soabi.startswith("pypy"): -+ abi = "-".join(soabi.split("-")[:2]) -+ elif soabi.startswith("graalpy"): -+ abi = "-".join(soabi.split("-")[:3]) -+ elif soabi: -+ # pyston, ironpython, others? -+ abi = soabi -+ else: -+ return [] -+ return [_normalize_string(abi)] - - - def generic_tags( -diff --git a/pip/_vendor/platformdirs/api.py b/pip/_vendor/platformdirs/api.py -index d64ebb9..3655f3d 100644 ---- a/pip/_vendor/platformdirs/api.py -+++ b/pip/_vendor/platformdirs/api.py -@@ -71,7 +71,7 @@ class PlatformDirsABC(ABC): - def _append_app_name_and_version(self, *base: str) -> str: - params = list(base[1:]) - if self.appname: -- params.append(self.appname) -+ params.append(f'{self.appname}-graalpy') - if self.version: - params.append(self.version) - path = os.path.join(base[0], *params) # noqa: PTH118 From a1ddc24b1b9623af95dbcdc45b4dcc7896eddf4e Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 18 Jun 2026 17:31:17 +0200 Subject: [PATCH 3/4] Make autopatch_capi opt-out --- .../modules/graalpy_pip_extensions.py | 11 +++-- graalpython/lib-graalpython/patches/README.md | 4 +- mx.graalpython/verify_patches.py | 6 ++- scripts/get_pypi_source.py | 49 ++++++++++++++----- 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/graalpython/lib-graalpython/modules/graalpy_pip_extensions.py b/graalpython/lib-graalpython/modules/graalpy_pip_extensions.py index 7136258574..86fcd4ddbe 100644 --- a/graalpython/lib-graalpython/modules/graalpy_pip_extensions.py +++ b/graalpython/lib-graalpython/modules/graalpy_pip_extensions.py @@ -326,11 +326,6 @@ def apply_graalpy_patches(filename, location, warn_suggested_versions=False): # We already processed it when building from source return - import autopatch_capi - import subprocess - - autopatch_capi.auto_patch_tree(location) - logger.info(f"Looking for GraalPy patches for {name}") repository = get_patch_repository() @@ -347,6 +342,10 @@ def apply_graalpy_patches(filename, location, warn_suggested_versions=False): # with a patch intended for a binary distribution, because in the source # distribution the actual deployed sources may be in a subdirectory (typically "src") location = os.path.join(location, subdir) + if not rule or rule.get('autopatch', True): + import autopatch_capi + + autopatch_capi.auto_patch_tree(location) if rule: if patch := rule.get('patch'): with repository.resolve_patch(patch) as patch_path: @@ -355,6 +354,8 @@ def apply_graalpy_patches(filename, location, warn_suggested_versions=False): logger.info(f"Patching package {name} using {patch}") exe = '.exe' if os.name == 'nt' else '' try: + import subprocess + subprocess.run([f"patch{exe}", "-f", "-d", str(location), "-p1", "-i", str(patch_path)], check=True) except FileNotFoundError: logger.warning( diff --git a/graalpython/lib-graalpython/patches/README.md b/graalpython/lib-graalpython/patches/README.md index d5ae9b60d3..4aa59f8beb 100644 --- a/graalpython/lib-graalpython/patches/README.md +++ b/graalpython/lib-graalpython/patches/README.md @@ -19,7 +19,7 @@ version = '== 1.0.0' dist-type = 'wheel' # Optional. When applying a patch for a sdist that was created against a wheel, there can be a mismatch in the paths, # when the wheel was built from a subdirectory. When applying a patch on a sdist, this option will cause the patch -# process to be run from given subdirectory. Has no effect when applying patches on wheels. +# process to be run from given subdirectory. Has no effect when applying patches on wheels. subdir = 'src' # Optional. Can specify preference for or against this version when selecting which version to install. Defaults to 1. # When ordering all available versions in the index, each version gets a priority of the first entry it matches in this @@ -29,6 +29,8 @@ subdir = 'src' # a number greater than 1 if you want given version to be preferred to other entries. Additionally, if you set the # priority to 0, the version will not be shown in the suggestion list we display when we didn't find an applicable patch install-priority = 1 +# Optional. Whether to run the `autopatch_capi` before applying the explicit patch. Defaults to true. +autopatch = true # The next entry will apply to all other versions of foo that didn't get matched by the previous rule [[foo.rules]] diff --git a/mx.graalpython/verify_patches.py b/mx.graalpython/verify_patches.py index 39846acfb2..db3506fa07 100644 --- a/mx.graalpython/verify_patches.py +++ b/mx.graalpython/verify_patches.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -60,7 +60,7 @@ } SECTIONS = frozenset({'rules', 'add-sources'}) -RULE_KEYS = frozenset({'version', 'patch', 'license', 'subdir', 'dist-type', 'install-priority', 'note'}) +RULE_KEYS = frozenset({'version', 'patch', 'license', 'subdir', 'dist-type', 'install-priority', 'note', 'autopatch'}) def validate_metadata(patches_dir): @@ -94,6 +94,8 @@ def validate_metadata(patches_dir): assert isinstance(install_priority, int), "'rules.install_priority' must be an int" if dist_type := rule.get('dist-type'): assert dist_type in ('wheel', 'sdist'), "'rules.dist_type' must be on of 'wheel', 'sdist'" + if 'autopatch' in rule: + assert isinstance(rule['autopatch'], bool), "'rules.autopatch' must be a bool" if version := rule.get('version'): # Just try that it doesn't raise SpecifierSet(version) diff --git a/scripts/get_pypi_source.py b/scripts/get_pypi_source.py index 0524e6138f..03e58eeeb7 100755 --- a/scripts/get_pypi_source.py +++ b/scripts/get_pypi_source.py @@ -40,9 +40,9 @@ #!/usr/bin/python import argparse +import builtins import json import os -import re import shutil import subprocess import sys @@ -53,14 +53,27 @@ import urllib.request import zipfile from pathlib import Path -try: - import tomllib -except ModuleNotFoundError: - tomllib = None +from types import SimpleNamespace +REPO_ROOT = Path(__file__).resolve().parents[1] +PATCHES_DIR = REPO_ROOT / "graalpython" / "lib-graalpython" / "patches" +GRAALPY_MODULES_DIR = REPO_ROOT / "graalpython" / "lib-graalpython" / "modules" +PIP_BUNDLED_DIR = REPO_ROOT / "graalpython" / "lib-python" / "3" / "ensurepip" / "_bundled" +PIP_WHEEL = next(PIP_BUNDLED_DIR.glob("pip-*.whl")) + +sys.path[:0] = [str(GRAALPY_MODULES_DIR), str(PIP_WHEEL)] + +if not hasattr(builtins, "__graalpython__"): + builtins.__graalpython__ = SimpleNamespace( + core_home=str(REPO_ROOT / "graalpython" / "lib-graalpython"), + get_graalvm_version=lambda: "0-dev", + ) + +from graalpy_pip_extensions import LocalPatchRepository, canonicalize_name PYPI_URL = "https://pypi.org/pypi" -METADATA_TOML = Path(__file__).resolve().parents[1] / "graalpython" / "lib-graalpython" / "patches" / "metadata.toml" +METADATA_TOML = PATCHES_DIR / "metadata.toml" +PATCH_REPOSITORY = LocalPatchRepository.from_path(PATCHES_DIR) def eprint(*args, **kwargs): @@ -74,7 +87,7 @@ def parse_pkg(pkg_arg): name, version = pkg_arg, None if not name: raise ValueError("missing package name") - return re.sub(r"[-_.]+", "-", name).lower(), version + return canonicalize_name(name), version def pypi_json(name, version=None): @@ -104,11 +117,7 @@ def choose_artifact(files): def find_add_source(name, version): if not version or not METADATA_TOML.is_file(): return None - if tomllib is None: - raise RuntimeError("Reading metadata.toml requires Python 3.11 or newer") - with open(METADATA_TOML, "rb") as metadata_file: - metadata = tomllib.load(metadata_file) - for add_source in metadata.get(name, {}).get("add-sources", []): + for add_source in PATCH_REPOSITORY.get_add_sources(name) or (): if add_source.get("version") == version: return add_source["url"] return None @@ -122,6 +131,17 @@ def artifact_from_add_source(name, version): return {"filename": filename, "url": url}, "sdist" +def get_matching_rule(name, version, dist_type): + return PATCH_REPOSITORY.get_matching_rule(name, version, dist_type) + + +def should_autopatch(name, version, artifact_type): + rule = get_matching_rule(name, version, artifact_type) + if artifact_type == "sdist" and not rule: + rule = get_matching_rule(name, version, "wheel") + return not rule or rule.get("autopatch", True) + + def no_source_error(name, version): sys.exit( f"No suitable source found for {name}=={version}. " @@ -249,7 +269,10 @@ def main(argv=None): except Exception: shutil.rmtree(target_dir, ignore_errors=True) raise - autopatch_capi(target_dir) + if should_autopatch(name, version, artifact_type): + autopatch_capi(target_dir) + else: + eprint(f"Skipping autopatch for {name}=={version}") print(f"Prepared source at: {target_dir}") From 5ec50bab7818420dc908c30ec79d446ffea5d2cb Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 18 Jun 2026 17:31:55 +0200 Subject: [PATCH 4/4] Opt-out of autopatch for cython --- .../patches/Cython-3.0.10.patch | 297 +++++++++++++++--- .../patches/cython-3.1.2.patch | 203 +++++++++++- .../patches/cython-3.2.0.patch | 170 +++++++++- .../patches/cython-3.2.4.patch | 170 +++++++++- .../lib-graalpython/patches/metadata.toml | 5 + 5 files changed, 790 insertions(+), 55 deletions(-) diff --git a/graalpython/lib-graalpython/patches/Cython-3.0.10.patch b/graalpython/lib-graalpython/patches/Cython-3.0.10.patch index e82abf81e1..98848b3d65 100644 --- a/graalpython/lib-graalpython/patches/Cython-3.0.10.patch +++ b/graalpython/lib-graalpython/patches/Cython-3.0.10.patch @@ -67,7 +67,7 @@ index 46dea92..12c0616 100644 ("set", "PySet_Type", [BuiltinMethod("clear", "T", "r", "PySet_Clear"), diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py -index 455d8b6..2d66296 100644 +index 455d8b6..aa34bbb 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -7740,6 +7740,16 @@ class AttributeNode(ExprNode): @@ -83,7 +83,7 @@ index 455d8b6..2d66296 100644 + getattr(self.type, 'name', None) == '__data_union' and + getattr(self.obj.type, 'name') == 'array' + ): -+ return self.type.cast_code("GraalPyArray_Data((PyObject*)%s)" % obj_code) ++ return self.type.cast_code("__Pyx_ArrayData((arrayobject*)%s)" % obj_code) return "%s%s%s" % (obj_code, self.op, self.member) def generate_result_code(self, code): @@ -182,7 +182,7 @@ index c95511d..a68a884 100644 cval = ((PyComplexObject *)o)->cval; else diff --git a/Cython/Utility/Coroutine.c b/Cython/Utility/Coroutine.c -index 35f2e88..30b2d75 100644 +index 688a62d..25fea0b 100644 --- a/Cython/Utility/Coroutine.c +++ b/Cython/Utility/Coroutine.c @@ -539,8 +539,7 @@ static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *$local_tstate_cna @@ -206,23 +206,234 @@ index 35f2e88..30b2d75 100644 #else { diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c -index 3ea60f5..18d1842 100644 +index 2ca461f..d6a7d78 100644 --- a/Cython/Utility/CythonFunction.c +++ b/Cython/Utility/CythonFunction.c -@@ -1789,9 +1789,9 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { - #if PY_VERSION_HEX < 0x03020000 +@@ -26,6 +26,20 @@ + #define __Pyx_CyFunction_SetDefaultsGetter(f, g) \ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) + ++#if CYTHON_COMPILING_IN_GRAAL ++ #define __Pyx_CyFunction_GetMethodDef(func) GraalPyCFunction_GetMethodDef((PyObject*)(func)) ++ #define __Pyx_CyFunction_SetMethodDef(func, ml) GraalPyCFunction_SetMethodDef((PyObject*)(func), ml) ++ #define __Pyx_CyFunction_GetModule(func) GraalPyCFunction_GetModule((PyObject*)(func)) ++ #define __Pyx_CyFunction_SetModule(func, module) GraalPyCFunction_SetModule((PyObject*)(func), module) ++ #define __Pyx_CyFunction_GetDoc(func) GraalPyCFunction_GetDoc((PyObject*)(func)) ++#else ++ #define __Pyx_CyFunction_GetMethodDef(func) (((PyCFunctionObject*)(func))->m_ml) ++ #define __Pyx_CyFunction_SetMethodDef(func, ml) (((PyCFunctionObject*)(func))->m_ml = (ml)) ++ #define __Pyx_CyFunction_GetModule(func) (((PyCFunctionObject*)(func))->m_module) ++ #define __Pyx_CyFunction_SetModule(func, module) (((PyCFunctionObject*)(func))->m_module = (module)) ++ #define __Pyx_CyFunction_GetDoc(func) (((PyCFunctionObject*)(func))->m_ml->ml_doc) ++#endif ++ + + typedef struct { + #if CYTHON_COMPILING_IN_LIMITED_API +@@ -156,11 +170,12 @@ __Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; + #else +- if (((PyCFunctionObject*)op)->m_ml->ml_doc) { ++ const char *doc = __Pyx_CyFunction_GetDoc(op); ++ if (doc) { + #if PY_MAJOR_VERSION >= 3 +- op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); ++ op->func_doc = PyUnicode_FromString(doc); + #else +- op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); ++ op->func_doc = PyString_FromString(doc); + #endif + if (unlikely(op->func_doc == NULL)) + return NULL; +@@ -195,9 +210,9 @@ __Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) + #if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); + #elif PY_MAJOR_VERSION >= 3 +- op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); ++ op->func_name = PyUnicode_InternFromString(__Pyx_CyFunction_GetMethodDef(op)->ml_name); + #else +- op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); ++ op->func_name = PyString_InternFromString(__Pyx_CyFunction_GetMethodDef(op)->ml_name); + #endif /* CYTHON_COMPILING_IN_LIMITED_API */ + if (unlikely(op->func_name == NULL)) + return NULL; +@@ -572,7 +587,7 @@ __Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) + Py_INCREF(m->func_qualname); + return m->func_qualname; + #else +- return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); ++ return PyString_FromString(__Pyx_CyFunction_GetMethodDef(m)->ml_name); + #endif + } + +@@ -604,14 +619,14 @@ static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef * + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + #if !CYTHON_COMPILING_IN_LIMITED_API +- cf->m_ml = ml; ++ __Pyx_CyFunction_SetMethodDef(cf, ml); + cf->m_self = (PyObject *) op; + #endif + Py_XINCREF(closure); + op->func_closure = closure; + #if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); +- cf->m_module = module; ++ __Pyx_CyFunction_SetModule(cf, module); + #endif + op->func_dict = NULL; + op->func_name = NULL; +@@ -670,6 +685,12 @@ __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) + Py_CLEAR(m->func_closure); + #if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); ++#elif CYTHON_COMPILING_IN_GRAAL ++ { ++ PyObject *module = __Pyx_CyFunction_GetModule(m); ++ __Pyx_CyFunction_SetModule(m, NULL); ++ Py_XDECREF(module); ++ } + #else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); + #endif +@@ -728,6 +749,8 @@ static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, + Py_VISIT(m->func_closure); + #if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); ++#elif CYTHON_COMPILING_IN_GRAAL ++ Py_VISIT(__Pyx_CyFunction_GetModule(m)); + #else + Py_VISIT(((PyCFunctionObject*)m)->m_module); + #endif +@@ -780,8 +803,8 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + if (unlikely(flags < 0)) return NULL; + #else + PyCFunctionObject* f = (PyCFunctionObject*)func; +- PyCFunction meth = f->m_ml->ml_meth; +- int flags = f->m_ml->ml_flags; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(f)->ml_meth; ++ int flags = __Pyx_CyFunction_GetMethodDef(f)->ml_flags; + #endif + + Py_ssize_t size; +@@ -813,7 +836,7 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + #else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", +- f->m_ml->ml_name, size); ++ __Pyx_CyFunction_GetMethodDef(f)->ml_name, size); + #endif + return NULL; + } +@@ -849,7 +872,7 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + #else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", +- f->m_ml->ml_name, size); ++ __Pyx_CyFunction_GetMethodDef(f)->ml_name, size); + #endif + + return NULL; +@@ -867,7 +890,7 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + Py_DECREF(py_name); + #else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", +- f->m_ml->ml_name); ++ __Pyx_CyFunction_GetMethodDef(f)->ml_name); + #endif + return NULL; + } +@@ -958,14 +981,14 @@ static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionO + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", +- ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); ++ __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, +- "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); ++ "%.200s() takes no keyword arguments", __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_name); + return -1; + } + return ret; +@@ -974,7 +997,7 @@ static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionO + static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) + { + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; +- PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; ++ PyMethodDef* def = __Pyx_CyFunction_GetMethodDef(cyfunc); + #if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; + #else +@@ -1006,7 +1029,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c + static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) + { + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; +- PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; ++ PyMethodDef* def = __Pyx_CyFunction_GetMethodDef(cyfunc); + #if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; + #else +@@ -1038,7 +1061,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const + static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) + { + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; +- PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; ++ PyMethodDef* def = __Pyx_CyFunction_GetMethodDef(cyfunc); + #if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; + #else +@@ -1064,7 +1087,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, + static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) + { + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; +- PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; ++ PyMethodDef* def = __Pyx_CyFunction_GetMethodDef(cyfunc); + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); + #if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +@@ -1394,11 +1417,11 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type) + } + + meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_New( +- ((PyCFunctionObject *) func)->m_ml, ++ __Pyx_CyFunction_GetMethodDef(func), + ((__pyx_CyFunctionObject *) func)->flags, + ((__pyx_CyFunctionObject *) func)->func_qualname, + ((__pyx_CyFunctionObject *) func)->func_closure, +- ((PyCFunctionObject *) func)->m_module, ++ __Pyx_CyFunction_GetModule(func), + ((__pyx_CyFunctionObject *) func)->func_globals, + ((__pyx_CyFunctionObject *) func)->func_code); + if (unlikely(!meth)) +@@ -1786,12 +1809,18 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { + { + // cdef classes + PyMethodDescrObject *descr = (PyMethodDescrObject *)method; +- #if PY_VERSION_HEX < 0x03020000 ++ #if CYTHON_COMPILING_IN_GRAAL ++ PyTypeObject *d_type = GraalPyDescrObject_GetType(method); ++ PyMethodDef *d_method = GraalPyMethodDescrObject_GetMethod(method); ++ #elif PY_VERSION_HEX < 0x03020000 PyTypeObject *d_type = descr->d_type; #else -- PyTypeObject *d_type = descr->d_common.d_type; -+ PyTypeObject *d_type = GraalPyDescrObject_GetType(method); + PyTypeObject *d_type = descr->d_common.d_type; #endif - return PyDescr_NewClassMethod(d_type, descr->d_method); -+ return PyDescr_NewClassMethod(d_type, GraalPyMethodDescrObject_GetMethod(method)); ++ #if !CYTHON_COMPILING_IN_GRAAL ++ PyMethodDef *d_method = descr->d_method; ++ #endif ++ return PyDescr_NewClassMethod(d_type, d_method); } #endif else if (PyMethod_Check(method)) { diff --git a/Cython/Utility/ModuleSetupCode.c b/Cython/Utility/ModuleSetupCode.c -index d8f60a4..cd61759 100644 +index e2256a0..a217725 100644 --- a/Cython/Utility/ModuleSetupCode.c +++ b/Cython/Utility/ModuleSetupCode.c @@ -113,7 +113,7 @@ @@ -234,16 +445,17 @@ index d8f60a4..cd61759 100644 #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 #endif -@@ -995,7 +995,7 @@ static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +@@ -993,6 +993,9 @@ static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { + #if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) #define __Pyx_PyFrame_SetLineNumber(frame, lineno) ++#elif CYTHON_COMPILING_IN_GRAAL ++ #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) ++ #define __Pyx_PyFrame_SetLineNumber(frame, lineno) GraalPyFrame_SetLineNumber((frame), (lineno)) #else #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) -- #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) -+ #define __Pyx_PyFrame_SetLineNumber(frame, lineno) GraalPyFrame_SetLineNumber((frame), (lineno)) - #endif - - #if CYTHON_COMPILING_IN_LIMITED_API -@@ -1413,11 +1413,7 @@ static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +@@ -1413,11 +1416,7 @@ static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, #define __Pyx_PyType_AsAsync(obj) NULL #endif #ifndef __Pyx_PyAsyncMethodsStruct @@ -256,30 +468,18 @@ index d8f60a4..cd61759 100644 #endif -@@ -1678,7 +1674,7 @@ PyEval_InitThreads(); +@@ -1678,7 +1677,11 @@ PyEval_InitThreads(); static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { #if PY_VERSION_HEX >= 0x030700A1 static PY_INT64_T main_interpreter_id = -1; -- PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); ++ #if CYTHON_COMPILING_IN_GRAAL + PY_INT64_T current_id = GraalPyInterpreterState_GetIDFromThreadState(PyThreadState_Get()); ++ #else + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); ++ #endif if (main_interpreter_id == -1) { main_interpreter_id = current_id; return (unlikely(current_id == -1)) ? -1 : 0; -diff --git a/Cython/Utility/ObjectHandling.c b/Cython/Utility/ObjectHandling.c -index 1021edf..6139fd2 100644 ---- a/Cython/Utility/ObjectHandling.c -+++ b/Cython/Utility/ObjectHandling.c -@@ -2034,8 +2034,8 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) { - #endif - { - PyMethodDescrObject *descr = (PyMethodDescrObject*) method; -- target->func = descr->d_method->ml_meth; -- target->flag = descr->d_method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_STACKLESS); -+ target->func = GraalPyMethodDescrObject_GetMethod(method)->ml_meth; -+ target->flag = GraalPyMethodDescrObject_GetMethod(method)->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_STACKLESS); - } else - #endif - // bound classmethods need special treatment diff --git a/Cython/Utility/StringTools.c b/Cython/Utility/StringTools.c index 0a50bc5..f93b3cc 100644 --- a/Cython/Utility/StringTools.c @@ -303,7 +503,7 @@ index 0a50bc5..f93b3cc 100644 #else if (s1 == s2) { diff --git a/Cython/Utility/arrayarray.h b/Cython/Utility/arrayarray.h -index a9e4923..be07e56 100644 +index a9e4923..0233f72 100644 --- a/Cython/Utility/arrayarray.h +++ b/Cython/Utility/arrayarray.h @@ -32,30 +32,31 @@ typedef struct arraydescr { @@ -358,17 +558,34 @@ index a9e4923..be07e56 100644 Py_ssize_t allocated; struct arraydescr *ob_descr; PyObject *weakreflist; /* List of weak references */ -@@ -109,6 +110,9 @@ PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, +@@ -64,6 +65,16 @@ struct arrayobject { + #endif + }; + ++static CYTHON_INLINE __data_union __Pyx_ArrayData(arrayobject *self) { ++ __data_union data; ++#if CYTHON_COMPILING_IN_GRAAL ++ data.ob_item = GraalPyArray_Data((PyObject*)self); ++#else ++ data = self->data; ++#endif ++ return data; ++} ++ + #ifndef NO_NEWARRAY_INLINE + // fast creation of a new array + static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t size, +@@ -109,6 +120,9 @@ PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, // fast resize (reallocation to the point) // not designed for filing small increments (but for fast opaque array apps) static CYTHON_INLINE int resize(arrayobject *self, Py_ssize_t n) { -+#ifdef CYTHON_COMPILING_IN_GRAAL ++#if CYTHON_COMPILING_IN_GRAAL + return GraalPyArray_Resize((PyObject*)self, n); +#else void *items = (void*) self->data.ob_item; PyMem_Resize(items, char, (size_t)(n * self->ob_descr->itemsize)); if (items == NULL) { -@@ -119,10 +123,14 @@ static CYTHON_INLINE int resize(arrayobject *self, Py_ssize_t n) { +@@ -119,10 +133,14 @@ static CYTHON_INLINE int resize(arrayobject *self, Py_ssize_t n) { __Pyx_SET_SIZE(self, n); self->allocated = n; return 0; @@ -377,13 +594,13 @@ index a9e4923..be07e56 100644 // suitable for small increments; over allocation 50% ; static CYTHON_INLINE int resize_smart(arrayobject *self, Py_ssize_t n) { -+#ifdef CYTHON_COMPILING_IN_GRAAL ++#if CYTHON_COMPILING_IN_GRAAL + return GraalPyArray_Resize((PyObject*)self, n); +#else void *items = (void*) self->data.ob_item; Py_ssize_t newsize; if (n < self->allocated && n*4 > self->allocated) { -@@ -143,6 +151,7 @@ static CYTHON_INLINE int resize_smart(arrayobject *self, Py_ssize_t n) { +@@ -143,6 +161,7 @@ static CYTHON_INLINE int resize_smart(arrayobject *self, Py_ssize_t n) { __Pyx_SET_SIZE(self, n); self->allocated = newsize; return 0; diff --git a/graalpython/lib-graalpython/patches/cython-3.1.2.patch b/graalpython/lib-graalpython/patches/cython-3.1.2.patch index 3ebb069474..5ded4b6c96 100644 --- a/graalpython/lib-graalpython/patches/cython-3.1.2.patch +++ b/graalpython/lib-graalpython/patches/cython-3.1.2.patch @@ -36,7 +36,7 @@ index 5ae2a4e..1d6e63d 100644 +# GraalPy change: watermark our patched version +watermark = f'{version}-graalpy' diff --git a/Cython/Includes/cpython/array.pxd b/Cython/Includes/cpython/array.pxd -index b5e8880..7647f70 100644 +index b5e8880..37a9810 100644 --- a/Cython/Includes/cpython/array.pxd +++ b/Cython/Includes/cpython/array.pxd @@ -99,7 +99,10 @@ cdef extern from *: # Hard-coded utility code hack. @@ -56,13 +56,13 @@ index b5e8880..7647f70 100644 array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr) + # GraalPy change -+ array clonearray(object template_array, Py_ssize_t size) ++ array clonearray(object template_array, Py_ssize_t size, bint zero) + __data_union __Pyx_PyArray_Data(array self) nogil # fast resize/realloc # not suitable for small increments; reallocation 'to the point' int resize(array self, Py_ssize_t n) except -1 -@@ -142,10 +148,13 @@ cdef inline array clone(array template, Py_ssize_t length, bint zero): +@@ -142,10 +148,12 @@ cdef inline array clone(array template, Py_ssize_t length, bint zero): """ fast creation of a new array, given a template array. type will be same as template. if zero is true, new array will be initialized with zeroes.""" @@ -70,13 +70,12 @@ index b5e8880..7647f70 100644 - if zero and op is not None: - memset(op.data.as_chars, 0, length * op.ob_descr.itemsize) - return op -+ # GraalPy change: see clonearray impl in arrayarray.h. Note that the array -+ # is always zero-initialized ++ # GraalPy change: see clonearray impl in arrayarray.h. + # cdef array op = newarrayobject(Py_TYPE(template), length, template.ob_descr) + # if zero and op is not None: + # memset(op.data.as_chars, 0, length * op.ob_descr.itemsize) + # return op -+ return clonearray(template, length) ++ return clonearray(template, length, zero) cdef inline array copy(array self): """ make a copy of an array. """ @@ -123,10 +122,180 @@ index 15ba067..fdef8e5 100644 #define __Pyx_PySlice_Stop(o) __Pyx_NewRef(PySlice_Stop((PySliceObject*)o)) #define __Pyx_PySlice_Step(o) __Pyx_NewRef(PySlice_Step((PySliceObject*)o)) diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c -index 685d287..1b27dd5 100644 +index 685d287..525b900 100644 --- a/Cython/Utility/CythonFunction.c +++ b/Cython/Utility/CythonFunction.c -@@ -1755,8 +1755,12 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { +@@ -74,6 +74,23 @@ typedef struct { + #define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, CGLOBAL(__pyx_CyFunctionType)) + #define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, CGLOBAL(__pyx_CyFunctionType), &PyCFunction_Type) + #define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, CGLOBAL(__pyx_CyFunctionType)) ++#if CYTHON_COMPILING_IN_GRAAL ++#define __Pyx_PyCFunction_GetDoc(func) GraalPyCFunction_GetDoc((PyObject*)(func)) ++#define __Pyx_PyCFunction_GetMethodDef(func) GraalPyCFunction_GetMethodDef((PyObject*)(func)) ++#define __Pyx_PyCFunction_GetModule(func) GraalPyCFunction_GetModule((PyObject*)(func)) ++#define __Pyx_PyCFunction_SetMethodDef(func, ml) GraalPyCFunction_SetMethodDef((PyObject*)(func), ml) ++#define __Pyx_PyCFunction_SetModule(func, module) GraalPyCFunction_SetModule((PyObject*)(func), module) ++#define __Pyx_PyCFunction_ClearModule(func) ++#define __Pyx_PyCFunction_VisitModule(func) ++#else ++#define __Pyx_PyCFunction_GetDoc(func) (((PyCFunctionObject*)(func))->m_ml->ml_doc) ++#define __Pyx_PyCFunction_GetMethodDef(func) (((PyCFunctionObject*)(func))->m_ml) ++#define __Pyx_PyCFunction_GetModule(func) (((PyCFunctionObject*)(func))->m_module) ++#define __Pyx_PyCFunction_SetMethodDef(func, ml) (((PyCFunctionObject*)(func))->m_ml = (ml)) ++#define __Pyx_PyCFunction_SetModule(func, module) (((PyCFunctionObject*)(func))->m_module = (module)) ++#define __Pyx_PyCFunction_ClearModule(func) Py_CLEAR(((PyCFunctionObject*)(func))->m_module) ++#define __Pyx_PyCFunction_VisitModule(func) Py_VISIT(((PyCFunctionObject*)(func))->m_module) ++#endif + static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void (*cfunc)(void));/*proto*/ + #undef __Pyx_IsSameCFunction + #define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +@@ -175,8 +192,8 @@ __Pyx_CyFunction_get_doc_locked(__pyx_CyFunctionObject *op) + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; + #else +- if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +- op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); ++ if (__Pyx_PyCFunction_GetDoc(op)) { ++ op->func_doc = PyUnicode_FromString(__Pyx_PyCFunction_GetDoc(op)); + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { +@@ -221,7 +238,7 @@ __Pyx_CyFunction_get_name_locked(__pyx_CyFunctionObject *op) + #if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); + #else +- op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); ++ op->func_name = PyUnicode_InternFromString(__Pyx_PyCFunction_GetMethodDef(op)->ml_name); + #endif /* CYTHON_COMPILING_IN_LIMITED_API */ + if (unlikely(op->func_name == NULL)) + return NULL; +@@ -600,7 +617,7 @@ static void __Pyx_CyFunction_raise_argument_count_error(__pyx_CyFunctionObject * + py_name, message, size); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_PyCFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", + name, message, size); +@@ -616,7 +633,7 @@ static void __Pyx_CyFunction_raise_type_error(__pyx_CyFunctionObject *func, cons + py_name, message); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_PyCFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s", + name, message); +@@ -724,14 +741,14 @@ static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef * + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + #if !CYTHON_COMPILING_IN_LIMITED_API +- cf->m_ml = ml; ++ __Pyx_PyCFunction_SetMethodDef(cf, ml); + cf->m_self = (PyObject *) op; + #endif + Py_XINCREF(closure); + op->func_closure = closure; + #if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); +- cf->m_module = module; ++ __Pyx_PyCFunction_SetModule(cf, module); + #endif + op->func_dict = NULL; + op->func_name = NULL; +@@ -789,7 +806,7 @@ __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) + #if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); + #else +- Py_CLEAR(((PyCFunctionObject*)m)->m_module); ++ __Pyx_PyCFunction_ClearModule(m); + #endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); +@@ -842,7 +859,7 @@ static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, + #if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); + #else +- Py_VISIT(((PyCFunctionObject*)m)->m_module); ++ __Pyx_PyCFunction_VisitModule(m); + #endif + Py_VISIT(m->func_dict); + __Pyx_VISIT_CONST(m->func_name); +@@ -885,8 +902,8 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + if (unlikely(flags < 0)) return NULL; + #else + PyCFunctionObject* f = (PyCFunctionObject*)func; +- PyCFunction meth = f->m_ml->ml_meth; +- int flags = f->m_ml->ml_flags; ++ PyCFunction meth = __Pyx_PyCFunction_GetMethodDef(f)->ml_meth; ++ int flags = __Pyx_PyCFunction_GetMethodDef(f)->ml_flags; + #endif + Py_ssize_t size; + +@@ -972,7 +989,7 @@ static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, P + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { + #if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE +- return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); ++ return __Pyx_PyVectorcall_FastCallDict(func, vc, PySequence_Fast_ITEMS(args), (size_t)PyTuple_GET_SIZE(args), kw); + #else + // avoid unused function warning + (void) &__Pyx_PyVectorcall_FastCallDict; +@@ -1053,7 +1070,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_PyCFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { +@@ -1096,7 +1113,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_PyCFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { +@@ -1139,7 +1156,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_PyCFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { +@@ -1178,7 +1195,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_PyCFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: +@@ -1414,14 +1431,14 @@ __pyx_FusedFunction_descr_get_locked(__pyx_FusedFunctionObject *func, PyObject * + module = __Pyx_CyFunction_get_module((__pyx_CyFunctionObject *) func, NULL); + if ((unlikely(!module))) return NULL; + #else +- module = ((PyCFunctionObject *) func)->m_module; ++ module = __Pyx_PyCFunction_GetModule(func); + #endif + + meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_New( + #if CYTHON_COMPILING_IN_LIMITED_API + func->ml, + #else +- ((PyCFunctionObject *) func)->m_ml, ++ __Pyx_PyCFunction_GetMethodDef(func), + #endif + ((__pyx_CyFunctionObject *) func)->flags, + ((__pyx_CyFunctionObject *) func)->func_qualname, +@@ -1755,8 +1772,12 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { "This is most likely a classmethod in a cdef class method with binding=False. " "Try setting 'binding' to True.", method); @@ -203,7 +372,7 @@ index abc0614..0723227 100644 if (unlikely(!next_item)) return -1; #elif CYTHON_ASSUME_SAFE_MACROS diff --git a/Cython/Utility/arrayarray.h b/Cython/Utility/arrayarray.h -index d410e66..462d862 100644 +index d410e66..bed69d7 100644 --- a/Cython/Utility/arrayarray.h +++ b/Cython/Utility/arrayarray.h @@ -30,33 +30,34 @@ typedef struct arraydescr { @@ -264,13 +433,20 @@ index d410e66..462d862 100644 Py_ssize_t allocated; struct arraydescr *ob_descr; PyObject *weakreflist; /* List of weak references */ -@@ -105,9 +106,47 @@ PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, +@@ -105,9 +106,55 @@ PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, struct arraydescr *descr); #endif /* ifndef NO_NEWARRAY_INLINE */ +// GraalPy change: we should replace this hack with a proper API once we are +// allowed to change the ABI again -+static CYTHON_INLINE PyObject* clonearray(PyObject *template_array, Py_ssize_t size) { ++static CYTHON_INLINE PyObject* clonearray(PyObject *template_array, Py_ssize_t size, int zero) { ++#if !CYTHON_COMPILING_IN_GRAAL ++ arrayobject *op = (arrayobject*) newarrayobject(Py_TYPE(template_array), size, ((arrayobject*)template_array)->ob_descr); ++ if (zero && op != NULL) { ++ memset(op->data.as_chars, 0, size * op->ob_descr->itemsize); ++ } ++ return (PyObject*) op; ++#else + PyObject* op = NULL; + PyObject* module = NULL; + PyObject* typecode = PyObject_GetAttrString(template_array, "typecode"); @@ -293,6 +469,7 @@ index d410e66..462d862 100644 + Py_XDECREF(typecode); + Py_XDECREF(module); + return op; ++#endif +} + +static CYTHON_INLINE __data_union __Pyx_PyArray_Data(arrayobject *self) { @@ -312,7 +489,7 @@ index d410e66..462d862 100644 void *items = (void*) self->data.ob_item; PyMem_Resize(items, char, (size_t)(n * self->ob_descr->itemsize)); if (items == NULL) { -@@ -118,10 +157,14 @@ static CYTHON_INLINE int resize(arrayobject *self, Py_ssize_t n) { +@@ -118,10 +165,14 @@ static CYTHON_INLINE int resize(arrayobject *self, Py_ssize_t n) { __Pyx_SET_SIZE(self, n); self->allocated = n; return 0; @@ -327,7 +504,7 @@ index d410e66..462d862 100644 void *items = (void*) self->data.ob_item; Py_ssize_t newsize; if (n < self->allocated && n*4 > self->allocated) { -@@ -142,6 +185,9 @@ static CYTHON_INLINE int resize_smart(arrayobject *self, Py_ssize_t n) { +@@ -142,6 +193,9 @@ static CYTHON_INLINE int resize_smart(arrayobject *self, Py_ssize_t n) { __Pyx_SET_SIZE(self, n); self->allocated = newsize; return 0; diff --git a/graalpython/lib-graalpython/patches/cython-3.2.0.patch b/graalpython/lib-graalpython/patches/cython-3.2.0.patch index c7ff6eb2ba..baf1a6100e 100644 --- a/graalpython/lib-graalpython/patches/cython-3.2.0.patch +++ b/graalpython/lib-graalpython/patches/cython-3.2.0.patch @@ -57,8 +57,176 @@ index 1a8cf33..d07f02c 100644 cdef inline array copy(array self): """ make a copy of an array. """ +diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c +index dbab32e..3f50aad 100644 +--- a/Cython/Utility/CythonFunction.c ++++ b/Cython/Utility/CythonFunction.c +@@ -87,6 +87,22 @@ typedef struct { + PyObject *func_is_coroutine; + } __pyx_CyFunctionObject; + ++#if !CYTHON_COMPILING_IN_LIMITED_API ++#if CYTHON_COMPILING_IN_GRAAL ++#define __Pyx_CyFunction_GetMethodDef(cyfunc) GraalPyCFunction_GetMethodDef((PyObject*)(cyfunc)) ++#define __Pyx_CyFunction_SetMethodDef(cyfunc, ml) GraalPyCFunction_SetMethodDef((PyObject*)(cyfunc), ml) ++#define __Pyx_CyFunction_GetModule(cyfunc) GraalPyCFunction_GetModule((PyObject*)(cyfunc)) ++#define __Pyx_CyFunction_SetModule(cyfunc, module) GraalPyCFunction_SetModule((PyObject*)(cyfunc), module) ++#define __Pyx_CyFunction_GetDoc(cyfunc) GraalPyCFunction_GetDoc((PyObject*)(cyfunc)) ++#else ++#define __Pyx_CyFunction_GetMethodDef(cyfunc) (((PyCFunctionObject*)(cyfunc))->m_ml) ++#define __Pyx_CyFunction_SetMethodDef(cyfunc, ml) (((PyCFunctionObject*)(cyfunc))->m_ml = (ml)) ++#define __Pyx_CyFunction_GetModule(cyfunc) (((PyCFunctionObject*)(cyfunc))->m_module) ++#define __Pyx_CyFunction_SetModule(cyfunc, module) (((PyCFunctionObject*)(cyfunc))->m_module = (module)) ++#define __Pyx_CyFunction_GetDoc(cyfunc) (__Pyx_CyFunction_GetMethodDef(cyfunc)->ml_doc) ++#endif ++#endif ++ + #undef __Pyx_CyOrPyCFunction_Check + #define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, CGLOBAL(__pyx_CyFunctionType)) + #define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, CGLOBAL(__pyx_CyFunctionType), &PyCFunction_Type) +@@ -192,8 +208,8 @@ __Pyx_CyFunction_get_doc_locked(__pyx_CyFunctionObject *op) + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; + #else +- if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +- op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); ++ if (__Pyx_CyFunction_GetDoc(op)) { ++ op->func_doc = PyUnicode_FromString(__Pyx_CyFunction_GetDoc(op)); + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { +@@ -238,7 +254,7 @@ __Pyx_CyFunction_get_name_locked(__pyx_CyFunctionObject *op) + #if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); + #else +- op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); ++ op->func_name = PyUnicode_InternFromString(__Pyx_CyFunction_GetMethodDef(op)->ml_name); + #endif /* CYTHON_COMPILING_IN_LIMITED_API */ + if (unlikely(op->func_name == NULL)) + return NULL; +@@ -589,7 +605,7 @@ static void __Pyx_CyFunction_raise_argument_count_error(__pyx_CyFunctionObject * + py_name, message, size); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_CyFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", + name, message, size); +@@ -605,7 +621,7 @@ static void __Pyx_CyFunction_raise_type_error(__pyx_CyFunctionObject *func, cons + py_name, message); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_CyFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s", + name, message); +@@ -720,14 +736,14 @@ static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef * + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + #if !CYTHON_COMPILING_IN_LIMITED_API +- cf->m_ml = ml; ++ __Pyx_CyFunction_SetMethodDef(cf, ml); + cf->m_self = (PyObject *) op; + #endif + Py_XINCREF(closure); + op->func_closure = closure; + #if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); +- cf->m_module = module; ++ __Pyx_CyFunction_SetModule(cf, module); + #endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + op->func_dict = NULL; +@@ -787,8 +803,10 @@ __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) + #if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); + #else ++#if !CYTHON_COMPILING_IN_GRAAL + Py_CLEAR(((PyCFunctionObject*)m)->m_module); + #endif ++#endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func_dict); + #elif PY_VERSION_HEX < 0x030d0000 +@@ -846,8 +864,10 @@ static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, + #if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); + #else ++#if !CYTHON_COMPILING_IN_GRAAL + Py_VISIT(((PyCFunctionObject*)m)->m_module); + #endif ++#endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func_dict); + #else +@@ -902,8 +922,8 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + if (unlikely(flags < 0)) return NULL; + #else + PyCFunctionObject* f = (PyCFunctionObject*)func; +- PyCFunction meth = f->m_ml->ml_meth; +- int flags = f->m_ml->ml_flags; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(f)->ml_meth; ++ int flags = __Pyx_CyFunction_GetMethodDef(f)->ml_flags; + #endif + Py_ssize_t size; + +@@ -1066,7 +1086,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { +@@ -1105,7 +1125,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { +@@ -1144,7 +1164,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { +@@ -1179,7 +1199,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: +@@ -1439,14 +1459,14 @@ __pyx_FusedFunction_descr_get_locked(__pyx_FusedFunctionObject *func, PyObject * + module = __Pyx_CyFunction_get_module((__pyx_CyFunctionObject *) func, NULL); + if ((unlikely(!module))) return NULL; + #else +- module = ((PyCFunctionObject *) func)->m_module; ++ module = __Pyx_CyFunction_GetModule(func); + #endif + + meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_New( + #if CYTHON_COMPILING_IN_LIMITED_API + func->ml, + #else +- ((PyCFunctionObject *) func)->m_ml, ++ __Pyx_CyFunction_GetMethodDef(func), + #endif + ((__pyx_CyFunctionObject *) func)->flags, + ((__pyx_CyFunctionObject *) func)->func_qualname, diff --git a/Cython/Utility/Optimize.c b/Cython/Utility/Optimize.c -index d991081..0faa93c 100644 +index 0744329..9d9c478 100644 --- a/Cython/Utility/Optimize.c +++ b/Cython/Utility/Optimize.c @@ -314,7 +314,7 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t diff --git a/graalpython/lib-graalpython/patches/cython-3.2.4.patch b/graalpython/lib-graalpython/patches/cython-3.2.4.patch index b645e17054..648d6b5e40 100644 --- a/graalpython/lib-graalpython/patches/cython-3.2.4.patch +++ b/graalpython/lib-graalpython/patches/cython-3.2.4.patch @@ -58,8 +58,176 @@ index 4bc0438..72c0360 100644 cdef inline array copy(array self): """ make a copy of an array. """ +diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c +index 8131c86..aa67eda 100644 +--- a/Cython/Utility/CythonFunction.c ++++ b/Cython/Utility/CythonFunction.c +@@ -87,6 +87,22 @@ typedef struct { + PyObject *func_is_coroutine; + } __pyx_CyFunctionObject; + ++#if !CYTHON_COMPILING_IN_LIMITED_API ++#if CYTHON_COMPILING_IN_GRAAL ++#define __Pyx_CyFunction_GetMethodDef(cyfunc) GraalPyCFunction_GetMethodDef((PyObject*)(cyfunc)) ++#define __Pyx_CyFunction_SetMethodDef(cyfunc, ml) GraalPyCFunction_SetMethodDef((PyObject*)(cyfunc), ml) ++#define __Pyx_CyFunction_GetModule(cyfunc) GraalPyCFunction_GetModule((PyObject*)(cyfunc)) ++#define __Pyx_CyFunction_SetModule(cyfunc, module) GraalPyCFunction_SetModule((PyObject*)(cyfunc), module) ++#define __Pyx_CyFunction_GetDoc(cyfunc) GraalPyCFunction_GetDoc((PyObject*)(cyfunc)) ++#else ++#define __Pyx_CyFunction_GetMethodDef(cyfunc) (((PyCFunctionObject*)(cyfunc))->m_ml) ++#define __Pyx_CyFunction_SetMethodDef(cyfunc, ml) (((PyCFunctionObject*)(cyfunc))->m_ml = (ml)) ++#define __Pyx_CyFunction_GetModule(cyfunc) (((PyCFunctionObject*)(cyfunc))->m_module) ++#define __Pyx_CyFunction_SetModule(cyfunc, module) (((PyCFunctionObject*)(cyfunc))->m_module = (module)) ++#define __Pyx_CyFunction_GetDoc(cyfunc) (__Pyx_CyFunction_GetMethodDef(cyfunc)->ml_doc) ++#endif ++#endif ++ + #undef __Pyx_CyOrPyCFunction_Check + #define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, CGLOBAL(__pyx_CyFunctionType)) + #define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, CGLOBAL(__pyx_CyFunctionType), &PyCFunction_Type) +@@ -192,8 +208,8 @@ __Pyx_CyFunction_get_doc_locked(__pyx_CyFunctionObject *op) + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; + #else +- if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +- op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); ++ if (__Pyx_CyFunction_GetDoc(op)) { ++ op->func_doc = PyUnicode_FromString(__Pyx_CyFunction_GetDoc(op)); + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { +@@ -238,7 +254,7 @@ __Pyx_CyFunction_get_name_locked(__pyx_CyFunctionObject *op) + #if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); + #else +- op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); ++ op->func_name = PyUnicode_InternFromString(__Pyx_CyFunction_GetMethodDef(op)->ml_name); + #endif /* CYTHON_COMPILING_IN_LIMITED_API */ + if (unlikely(op->func_name == NULL)) + return NULL; +@@ -589,7 +605,7 @@ static void __Pyx_CyFunction_raise_argument_count_error(__pyx_CyFunctionObject * + py_name, message, size); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_CyFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", + name, message, size); +@@ -605,7 +621,7 @@ static void __Pyx_CyFunction_raise_type_error(__pyx_CyFunctionObject *func, cons + py_name, message); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_CyFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s", + name, message); +@@ -720,14 +736,14 @@ static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef * + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + #if !CYTHON_COMPILING_IN_LIMITED_API +- cf->m_ml = ml; ++ __Pyx_CyFunction_SetMethodDef(cf, ml); + cf->m_self = (PyObject *) op; + #endif + Py_XINCREF(closure); + op->func_closure = closure; + #if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); +- cf->m_module = module; ++ __Pyx_CyFunction_SetModule(cf, module); + #endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + op->func_dict = NULL; +@@ -787,8 +803,10 @@ __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) + #if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); + #else ++#if !CYTHON_COMPILING_IN_GRAAL + Py_CLEAR(((PyCFunctionObject*)m)->m_module); + #endif ++#endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func_dict); + #elif PY_VERSION_HEX < 0x030d0000 +@@ -846,8 +864,10 @@ static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, + #if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); + #else ++#if !CYTHON_COMPILING_IN_GRAAL + Py_VISIT(((PyCFunctionObject*)m)->m_module); + #endif ++#endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func_dict); + #else +@@ -902,8 +922,8 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + if (unlikely(flags < 0)) return NULL; + #else + PyCFunctionObject* f = (PyCFunctionObject*)func; +- PyCFunction meth = f->m_ml->ml_meth; +- int flags = f->m_ml->ml_flags; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(f)->ml_meth; ++ int flags = __Pyx_CyFunction_GetMethodDef(f)->ml_flags; + #endif + Py_ssize_t size; + +@@ -1066,7 +1086,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { +@@ -1105,7 +1125,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { +@@ -1144,7 +1164,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { +@@ -1179,7 +1199,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: +@@ -1439,14 +1459,14 @@ __pyx_FusedFunction_descr_get_locked(__pyx_FusedFunctionObject *func, PyObject * + module = __Pyx_CyFunction_get_module((__pyx_CyFunctionObject *) func, NULL); + if ((unlikely(!module))) return NULL; + #else +- module = ((PyCFunctionObject *) func)->m_module; ++ module = __Pyx_CyFunction_GetModule(func); + #endif + + meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_New( + #if CYTHON_COMPILING_IN_LIMITED_API + func->ml, + #else +- ((PyCFunctionObject *) func)->m_ml, ++ __Pyx_CyFunction_GetMethodDef(func), + #endif + ((__pyx_CyFunctionObject *) func)->flags, + ((__pyx_CyFunctionObject *) func)->func_qualname, diff --git a/Cython/Utility/Optimize.c b/Cython/Utility/Optimize.c -index ee4a811..e8d403b 100644 +index b731f74..300758b 100644 --- a/Cython/Utility/Optimize.c +++ b/Cython/Utility/Optimize.c @@ -314,7 +314,7 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t diff --git a/graalpython/lib-graalpython/patches/metadata.toml b/graalpython/lib-graalpython/patches/metadata.toml index 1571d5636b..4774d0eac1 100644 --- a/graalpython/lib-graalpython/patches/metadata.toml +++ b/graalpython/lib-graalpython/patches/metadata.toml @@ -111,26 +111,31 @@ note = "Versions newer than 43 do not need a patch." [[cython.rules]] version = '>= 3.2.0, < 3.2.4' +autopatch = false patch = 'cython-3.2.0.patch' license = 'Apache-2.0' [[cython.rules]] version = '== 3.2.4' +autopatch = false patch = 'cython-3.2.4.patch' license = 'Apache-2.0' [[cython.rules]] version = '>= 3.1.7, <= 3.1.8' +autopatch = false patch = 'cython-3.1.7.patch' license = 'Apache-2.0' [[cython.rules]] version = '>= 3.1, <= 3.1.6' +autopatch = false patch = 'cython-3.1.2.patch' license = 'Apache-2.0' [[cython.rules]] version = '>= 3.0.10, <= 3.0.12' +autopatch = false patch = 'Cython-3.0.10.patch' license = 'Apache-2.0'